apollo-client vs graphql-tag vs react-apollo
GraphQL State Management and React Integration
apollo-clientgraphql-tagreact-apolloSimilar Packages:

GraphQL State Management and React Integration

apollo-client, react-apollo, and graphql-tag formed the original modular stack for integrating GraphQL into React applications. apollo-client handled caching and network requests, react-apollo provided React-specific hooks and components, and graphql-tag parsed GraphQL query strings. However, the ecosystem has consolidated. apollo-client and react-apollo are now deprecated in favor of @apollo/client, which combines both into a single package. graphql-tag remains a valid utility but is often bundled within the new client.

Npm Package Weekly Downloads Trend

3 Years

Github Stars Ranking

Stat Detail

Package
Downloads
Stars
Size
Issues
Publish
License
apollo-client019,716-4216 years agoMIT
graphql-tag02,331-995 years agoMIT
react-apollo06,802-2056 years agoMIT

Apollo Client Ecosystem: Legacy Modular vs. Modern Consolidated

For years, building GraphQL apps in React meant installing multiple packages: apollo-client for logic, react-apollo for UI bindings, and graphql-tag for query parsing. This modular approach gave developers control but added complexity. Today, the ecosystem has shifted toward consolidation. Let's break down what each package did, why they changed, and what you should use now.

🏗️ Architecture: Separate Packages vs. Unified Bundle

apollo-client was the core engine.

  • It managed the cache, network links, and state.
  • It was framework-agnostic (worked with Vue, Angular, or vanilla JS).
  • You had to manually wire it up to React using a separate library.
// apollo-client: Legacy setup
import ApolloClient from 'apollo-client';
import { HttpLink } from 'apollo-link-http';
import { InMemoryCache } from 'apollo-cache-inmemory';

const client = new ApolloClient({
  link: new HttpLink({ uri: '/graphql' }),
  cache: new InMemoryCache()
});

react-apollo was the bridge to React.

  • It provided Higher-Order Components (HOCs) like graphql() and later Hooks like useQuery.
  • It depended on apollo-client to work.
  • Installing it meant managing two major version numbers simultaneously.
// react-apollo: Legacy React binding
import { ApolloProvider } from 'react-apollo';
import { useQuery } from 'react-apollo';

function App() {
  return (
    <ApolloProvider client={client}>
      <Dashboard />
    </ApolloProvider>
  );
}

@apollo/client (The Modern Standard) combines both.

  • It includes the client logic and React bindings in one package.
  • It simplifies imports and version management.
  • It is the only recommended path for new development.
// @apollo/client: Modern unified setup
import { ApolloClient, InMemoryCache, ApolloProvider, useQuery } from '@apollo/client';

const client = new ApolloClient({
  uri: '/graphql',
  cache: new InMemoryCache()
});

function App() {
  return (
    <ApolloProvider client={client}>
      <Dashboard />
    </ApolloProvider>
  );
}

📝 Query Parsing: External Utility vs. Built-In

graphql-tag is a standalone parser.

  • It turns template literals into GraphQL AST (Abstract Syntax Tree) objects.
  • It was required to tag queries so the client could read them.
  • It is still maintained but often unnecessary now.
// graphql-tag: Standalone usage
import gql from 'graphql-tag';

const GET_USER = gql`
  query GetUser($id: ID!) {
    user(id: $id) { name }
  }
`;

@apollo/client includes gql by default.

  • You can import gql directly from the main package.
  • This reduces the number of dependencies in your package.json.
  • Functionally identical to the standalone package for most users.
// @apollo/client: Built-in gql tag
import { gql } from '@apollo/client';

const GET_USER = gql`
  query GetUser($id: ID!) {
    user(id: $id) { name }
  }
`;

⚠️ Deprecation Status: What's Safe to Use?

This is the most critical part of the comparison. The maintainers have made clear decisions about the future of these libraries.

PackageStatusRecommendation
apollo-client🔴 DeprecatedDo not use. Migrate to @apollo/client.
react-apollo🔴 DeprecatedDo not use. Hooks are now in @apollo/client.
graphql-tag🟢 MaintainedOptional. Only needed if not using @apollo/client.

Why the Change?

Maintaining separate packages caused version mismatches.

  • Developers often struggled to find compatible versions of apollo-client and react-apollo.
  • Bug fixes had to be coordinated across multiple repositories.
  • The unified package ensures that the React bindings always match the core client logic.

🔄 Migration: From Legacy to Modern

If you are currently using the legacy stack, here is how the code changes.

1. Update Imports

Old Way (apollo-client + react-apollo)

import ApolloClient from 'apollo-client';
import { ApolloProvider, useQuery } from 'react-apollo';
import gql from 'graphql-tag';

New Way (@apollo/client)

import { ApolloClient, ApolloProvider, useQuery, gql } from '@apollo/client';

2. Update Client Configuration

Old Way

// Required separate link and cache packages
import { createHttpLink } from 'apollo-link-http';
import { InMemoryCache } from 'apollo-cache-inmemory';

const client = new ApolloClient({
  link: createHttpLink({ uri: '/graphql' }),
  cache: new InMemoryCache()
});

New Way

// Links and cache are built-in
import { HttpLink, InMemoryCache } from '@apollo/client';

const client = new ApolloClient({
  link: new HttpLink({ uri: '/graphql' }),
  cache: new InMemoryCache()
});

🛠️ When to Keep graphql-tag?

There are rare cases where you might still install graphql-tag separately:

  1. Non-Apollo Projects: If you are using a different GraphQL client (like urql or graphql-request) but still want the gql tag utility.
  2. Build Tooling: Some older webpack or babel configurations expect the specific graphql-tag loader for query extraction.
  3. Server-Side Parsing: If you need to parse GraphQL strings in a Node.js backend that does not use the Apollo Client.
// Example: Using graphql-tag with a different client
import gql from 'graphql-tag';
import { request } from 'graphql-request';

const query = gql`{ posts { title } }`;
request('/api/graphql', query);

💡 Summary: The Path Forward

apollo-client and react-apollo are history.
They served the community well during the early days of GraphQL in React. However, they are no longer the standard. Continuing to use them introduces technical debt and security risks due to lack of updates.

@apollo/client is the present and future.
It offers the same features with less setup. It is actively maintained, better documented, and designed for modern React patterns like Hooks.

graphql-tag is a utility.
Keep it in your toolkit for non-Apollo tasks, but don't install it unnecessarily if you are already using @apollo/client.

📊 Quick Reference

TaskLegacy PackagesModern Package
Create Clientapollo-client@apollo/client
React Hooksreact-apollo@apollo/client
Parse Queriesgraphql-tag@apollo/client (includes gql)
Cache Configapollo-cache-inmemory@apollo/client
Network Linksapollo-link-http@apollo/client

🏁 Final Recommendation

For any new project, start with @apollo/client.
It removes the guesswork of compatibility and gives you a single source of truth for your GraphQL layer.
If you are maintaining an old app, plan a migration to the unified package as soon as possible to ensure long-term stability.

How to Choose: apollo-client vs graphql-tag vs react-apollo

  • apollo-client:

    Do not choose apollo-client for new projects. It is officially deprecated and no longer receives feature updates. The functionality has been merged into @apollo/client. Only use this if you are maintaining a legacy application that cannot be migrated yet.

  • graphql-tag:

    Choose graphql-tag if you need to parse GraphQL template literals outside of the Apollo ecosystem or if your build setup requires explicit tagging of queries. However, note that @apollo/client now includes this functionality by default, so you often do not need to install it separately anymore.

  • react-apollo:

    Do not choose react-apollo for new projects. It is officially deprecated. All React hooks (like useQuery) and components (like Query) are now built directly into @apollo/client. Migrating to the unified package reduces dependency complexity and ensures long-term support.

README for apollo-client

Apollo Client npm version Open Source Helpers Join the community on Spectrum

Apollo Client is a fully-featured caching GraphQL client with integrations for React, Angular, and more. It allows you to easily build UI components that fetch data via GraphQL. To get the most value out of apollo-client, you should use it with one of its view layer integrations.

To get started with the React integration, go to our React Apollo documentation website.

Apollo Client also has view layer integrations for all the popular frontend frameworks. For the best experience, make sure to use the view integration layer for your frontend framework of choice.

Apollo Client can be used in any JavaScript frontend where you want to use data from a GraphQL server. It's:

  1. Incrementally adoptable, so that you can drop it into an existing JavaScript app and start using GraphQL for just part of your UI.
  2. Universally compatible, so that Apollo works with any build setup, any GraphQL server, and any GraphQL schema.
  3. Simple to get started with, so you can start loading data right away and learn about advanced features later.
  4. Inspectable and understandable, so that you can have great developer tools to understand exactly what is happening in your app.
  5. Built for interactive apps, so your users can make changes and see them reflected in the UI immediately.
  6. Small and flexible, so you don't get stuff you don't need. The core is under 25kb compressed.
  7. Community driven, because Apollo is driven by the community and serves a variety of use cases. Everything is planned and developed in the open.

Get started on the home page, which has great examples for a variety of frameworks.

Installation

# installing the preset package
npm install apollo-boost graphql-tag graphql --save
# installing each piece independently
npm install apollo-client apollo-cache-inmemory apollo-link-http graphql-tag graphql --save

To use this client in a web browser or mobile app, you'll need a build system capable of loading NPM packages on the client. Some common choices include Browserify, Webpack, and Meteor 1.3+.

Install the Apollo Client Developer tools for Chrome for a great GraphQL developer experience!

Usage

You get started by constructing an instance of the core class ApolloClient. If you load ApolloClient from the apollo-boost package, it will be configured with a few reasonable defaults such as our standard in-memory cache and a link to a GraphQL API at /graphql.

import ApolloClient from 'apollo-boost';

const client = new ApolloClient();

To point ApolloClient at a different URL, add your GraphQL API's URL to the uri config property:

import ApolloClient from 'apollo-boost';

const client = new ApolloClient({
  uri: 'https://graphql.example.com'
});

Most of the time you'll hook up your client to a frontend integration. But if you'd like to directly execute a query with your client, you may now call the client.query method like this:

import gql from 'graphql-tag';

client.query({
  query: gql`
    query TodoApp {
      todos {
        id
        text
        completed
      }
    }
  `,
})
  .then(data => console.log(data))
  .catch(error => console.error(error));

Now your client will be primed with some data in its cache. You can continue to make queries, or you can get your client instance to perform all sorts of advanced tasks on your GraphQL data. Such as reactively watching queries with watchQuery, changing data on your server with mutate, or reading a fragment from your local cache with readFragment.

To learn more about all of the features available to you through the apollo-client package, be sure to read through the apollo-client API reference.

Learn how to use Apollo Client with your favorite framework


Contributing

CircleCI codecov

Read the Apollo Contributor Guidelines.

Running tests locally:

npm install
npm test

This project uses TypeScript for static typing and TSLint for linting. You can get both of these built into your editor with no configuration by opening this project in Visual Studio Code, an open source IDE which is available for free on all platforms.

Important discussions

If you're getting booted up as a contributor, here are some discussions you should take a look at:

  1. Static typing and why we went with TypeScript also covered in the Medium post
  2. Idea for pagination handling
  3. Discussion about interaction with Redux and domain vs. client state
  4. Long conversation about different client options, before this repo existed

Maintainers