# A complete introduction to Apollo, the GraphQL toolkit

> Learn how to use current Apollo Client with React and Apollo Server to query, cache, and serve a GraphQL API, including authentication basics.

Author: [Flavio Copes](https://flaviocopes.com/about/) | Published: 2018-03-19 | Updated: 2026-07-18 | Topics: [GraphQL](https://flaviocopes.com/tags/graphql/) | Canonical: https://flaviocopes.com/apollo/

![The Apollo Logo](https://flaviocopes.com/images/apollo/logo.png)

Apollo is a collection of tools for working with [GraphQL](https://flaviocopes.com/graphql/).

The two pieces you are most likely to use are:

- **Apollo Client**, which sends GraphQL operations from an application and caches the results
- **Apollo Server**, which runs a GraphQL API in Node.js

You can use either one independently. Apollo Client can talk to any standards-compliant GraphQL server, and Apollo Server can serve any GraphQL client.

Older tutorials use packages such as `apollo-boost`, `react-apollo`, `apollo-client`, and `apollo-server`. Those packages are obsolete. Current projects use the scoped `@apollo/client` and `@apollo/server` packages.

## What does Apollo Client do?

Apollo Client sends queries, mutations, and subscriptions to a GraphQL API.

It also stores results in a normalized in-memory cache. When two query results describe the same object, Apollo can identify that object and update every part of the interface that uses it.

Apollo Client is not limited to React, but this guide uses the official React integration.

## How do you install Apollo Client?

In a React project, install:

```sh
npm install @apollo/client graphql rxjs
```

`graphql` provides the core GraphQL parsing and execution utilities. Apollo Client uses RxJS observables internally, so `rxjs` is also a direct dependency.

## How do you create an Apollo Client?

Create a client near your React entry point:

```js
import {
  ApolloClient,
  HttpLink,
  InMemoryCache
} from '@apollo/client'

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

`HttpLink` sends operations over HTTP. Change `/graphql` to the URL of your API.

`InMemoryCache` stores query results for the lifetime of the page. It uses fields such as `__typename` and `id` to identify objects by default.

## How do you connect Apollo Client to React?

Import `ApolloProvider` from the React entry point and wrap the application:

```jsx
import { ApolloProvider } from '@apollo/client/react'
import { createRoot } from 'react-dom/client'

const root = createRoot(document.getElementById('root'))

root.render(
  <ApolloProvider client={client}>
    <App />
  </ApolloProvider>
)
```

Components below the provider can now use Apollo's React hooks.

## How do you run a query?

Define a GraphQL document with the `gql` template tag:

```jsx
import { gql } from '@apollo/client'
import { useQuery } from '@apollo/client/react'

const GET_BOOKS = gql`
  query GetBooks {
    books {
      id
      title
      author
    }
  }
`

export default function Books() {
  const { loading, error, data } = useQuery(GET_BOOKS)

  if (loading) {
    return <p>Loading...</p>
  }

  if (error) {
    return <p>Could not load the books.</p>
  }

  return (
    <ul>
      {data.books.map((book) => (
        <li key={book.id}>
          {book.title} by {book.author}
        </li>
      ))}
    </ul>
  )
}
```

`useQuery()` starts the operation, subscribes the component to the result, and re-renders it when the state changes.

The `loading`, `error`, and `data` states all matter. Do not assume that `data` is immediately available.

## How does the cache work?

Apollo Client checks the cache before sending the same query to the network. The default fetch policy for many queries is `cache-first`.

You can choose another policy for a specific query:

```js
const result = useQuery(GET_BOOKS, {
  fetchPolicy: 'network-only'
})
```

Do this deliberately. Disabling the cache everywhere removes one of Apollo Client's main benefits.

After a mutation, Apollo can often update existing objects automatically when the mutation returns their identifiers and changed fields. For list additions, removals, or results with unusual identifiers, you may need to update the cache or refetch a query.

## How do you authenticate a request?

The safest setup depends on the application.

If the server uses a secure session cookie, include credentials in the HTTP link:

```js
const httpLink = new HttpLink({
  uri: '/graphql',
  credentials: 'include'
})
```

The server must configure CORS correctly when the client and API use different origins. Cookie-authenticated mutation requests also need [CSRF protection](https://flaviocopes.com/csrf/).

For bearer-token authentication, add an authorization link before the HTTP link:

```js
import {
  ApolloClient,
  HttpLink,
  InMemoryCache
} from '@apollo/client'
import { SetContextLink } from '@apollo/client/link/context'

const httpLink = new HttpLink({
  uri: '/graphql'
})

const authLink = new SetContextLink(({ headers }) => {
  const token = getAccessToken()

  return {
    headers: {
      ...headers,
      authorization: token ? `Bearer ${token}` : ''
    }
  }
})

const client = new ApolloClient({
  link: authLink.concat(httpLink),
  cache: new InMemoryCache()
})
```

`getAccessToken()` is application-specific. Do not put a server API key, private GitHub token, or other long-lived secret in browser code. Anyone can inspect a browser bundle.

Also remember that authentication answers “who is this?” Authorization still has to be enforced by the server for every protected operation and object.

## What does Apollo Server do?

Apollo Server runs a GraphQL API.

You provide:

- A schema containing GraphQL type definitions
- Resolver functions that return the data for fields
- Optional context shared by the resolvers for one operation
- Plugins and integration settings

Apollo Server can read from databases, REST APIs, queues, files, or other GraphQL services. GraphQL does not decide where your data lives.

## How do you install Apollo Server?

Create a Node.js project and install:

```sh
npm install @apollo/server graphql
```

The following JavaScript example uses ES modules. Save it as `server.mjs`, or set `"type": "module"` in `package.json`.

## How do you create a small GraphQL server?

```js
import { ApolloServer } from '@apollo/server'
import {
  startStandaloneServer
} from '@apollo/server/standalone'

const books = [
  {
    id: '1',
    title: 'The Hobbit',
    author: 'J.R.R. Tolkien'
  },
  {
    id: '2',
    title: 'The Left Hand of Darkness',
    author: 'Ursula K. Le Guin'
  }
]

const typeDefs = `#graphql
  type Book {
    id: ID!
    title: String!
    author: String!
  }

  type Query {
    books: [Book!]!
  }
`

const resolvers = {
  Query: {
    books() {
      return books
    }
  }
}

const server = new ApolloServer({
  typeDefs,
  resolvers
})

const { url } = await startStandaloneServer(server, {
  listen: {
    port: 4000
  }
})

console.log(`Server ready at ${url}`)
```

Run it:

```sh
node server.mjs
```

Open the URL printed in the terminal. In a development setup, Apollo's landing page can open Apollo Sandbox, where you can run this query:

```graphql
query GetBooks {
  books {
    id
    title
    author
  }
}
```

The standalone server is excellent for learning and prototypes. Apollo recommends a web-framework integration for production applications that need more control over routing, CORS, middleware, and the rest of the HTTP stack.

## What is a resolver?

A resolver returns the value for one field.

Its full signature receives four arguments:

```js
field(parent, args, contextValue, info) {
  // ...
}
```

- `parent` is the result from the parent field
- `args` contains the GraphQL field arguments
- `contextValue` contains per-operation data such as the authenticated user and data sources
- `info` describes the GraphQL operation and schema

Most resolvers only need some of these values.

## How do you authenticate an Apollo Server request?

Read and verify the credential while creating the context. Put the resulting user, not the raw unverified token, in `contextValue`.

Then check permissions in the relevant resolver or in a shared authorization layer:

```js
const resolvers = {
  Query: {
    account(parent, args, contextValue) {
      if (!contextValue.user) {
        throw new Error('Not authenticated')
      }

      return findAccount(contextValue.user.id)
    }
  }
}
```

Do not rely on hiding a field in the client. A caller can send any valid GraphQL operation directly to the server.

For public production GraphQL endpoints, also set request-size limits, timeouts, and limits on expensive operations. Keep introspection and developer landing pages aligned with your threat model.

## Do you need Apollo GraphOS?

No. Apollo Client and Apollo Server work without a hosted Apollo account.

Apollo GraphOS is an optional platform for schema delivery, operation metrics, routing, and collaboration across GraphQL services. Add it when those operational features solve a real problem for your team.

Start with the current official [Apollo Client guide](https://www.apollographql.com/docs/react/get-started) and [Apollo Server guide](https://www.apollographql.com/docs/apollo-server/getting-started) for version-specific details.
