JustGiving Logo

Migrating to Apollo Client 3 - Part 1: Updating Imports

15 January, 2021

Written by Phillip Parker


Apollo has played a central role in the recent rebuild of our primary products - the Fundraising, Teams and Campaign pages. With this rebuild our focus was to deliver a modern, maintainable front-end powered by GraphQL. Naturally, we were immediately drawn to Apollo. Its impressive caching capabilities and easy to use hooks allowed us to amass a number of components each with their own, colocated GraphQL Queries.

When we learned of Apollo Client 3 (AC3) and the new features it was bringing to the table we were very keen to upgrade. However, our migration journey had a few bumps along the way and it's these that I'd like to discuss. This post will be the first of a four part series covering:

  • Updating your imports
  • Local state and reactive variables
  • Caching, keyFields and keyArgs
  • Pagination, modifying the cache and the merge function

Before jumping in, it's worth noting that Apollo provides its own migration documentation. This is a great place to get an overview of all the breaking changes and they have a good video of refactoring a project to work with AC3.

Updating the imports

If you want to get the imports updated as quickly as possible skip down to Using the jscodeshift transform

Our first migration step is to update the imports used by Apollo. Apollo's import landscape became slightly confusing over the years... do I import from the package directly or apollo-boost 🤔? But with AC3, Apollo has combined all of their packages into a single dependency -@apollo/client. Now the most commonly used modules can be imported directly from here.

import { useMutation, useQuery } from '@apollo/client'

However, there are still some caveats you need to be aware of. When importing links (they are now part of the package), you'll have to be slightly more specific.

import { createPersistedQueryLink } from '@apollo/client/link/persisted-queries';

This works for all links apart from createHttpLink, which is imported directly from @apollo/client 🤷‍♀️.

import { createHttpLink } from '@apollo/client'

If you're doing server-side rendering, getDataFromTree is imported from @apollo/client/react/ssr.

import { getDataFromTree } from '@apollo/client/react/ssr';

And testing your components with the MockedProvider requires you to import from @apollo/client/testing;

import { MockedProvider } from '@apollo/client/testing';

If you were using wait from @apollo/react-testing (we were), this is no longer available and you'll have to create your own. Something like this.

const wait = (): Promise<void> => {
  return new Promise((resolve) => {
    setTimeout(() => {
    }, 1)

Finally, gql from graphql-tools is exported directly from the package. Previously this was required as a peer dependency.

import { gql } from '@apollo/client';

Using the jscodeshift transform

Phew! That's quite a bit of work, especially if you're migrating a big project. Luckily, we have the power of programming on our side and Apollo has your back. They built a code transform using jscodeshift to do the heavy lifting and migrate all of these imports for you. To run this transform on your project, first clone the apollo-client repo as the transform lives inside this repository.

git clone https://github.com/apollographql/apollo-client.git

Then we can use npx to run jscodeshift without having to globally install it. We have a choice of 3 different commands to run based off the files we'd like to transform - js, ts or tsx. Run one of these commands in your favourite terminal making sure to change source-directory to the folder containing the files you'd like to transform.

# To transform all .js files:
npx jscodeshift \
  -t apollo-client/codemods/ac2-to-ac3/imports.js \
  --extensions js \

# To transform all .ts files:
npx jscodeshift \
  -t apollo-client/codemods/ac2-to-ac3/imports.js \
  --extensions ts --parser ts \

# To transform all .tsx files:
npx jscodeshift \
  -t apollo-client/codemods/ac2-to-ac3/imports.js \
  --extensions tsx --parser tsx \

With that your imports will be magically updated! We didn't see any issue with the transform but, it's worth checking the changes before committing. With the easy stuff out of the way, I'll discuss local state and reactive variables in the next post. Stay tuned!