What's the actual recommendation regarding graphql-codegen?

I was trying to debug issues around codegen not showing, and noticed that Apollo actually has conflicting advice regarding the use of @graphql-codegen/client-preset.

The official tutorial suggests using it, but the official docs suggests against it. So which one do I listen to? For what it’s worth the suggestion about data masking is nice, but I don’t like that I now have to import the types instead of having graphql()calls magically inferring the type.

Or should I switch to gql.tada? Not that there’s been any movement on this since 2024… github .com/apollographql/apollo-client/issues/11574

It’s complicated :sweat_smile:

Generally: thanks for bringing that to our attention, I’ll make sure that we rework that part of the tutorial. The recommendation in our docs is our current stance on codegen.

As for the graphql calls magically inferring the type - I get why you like it, but they have one significant downside: they make bundle shaking pretty much impossible, as all calls go through a central function that then returns one of a number of responses. It has the risk of massively bloating up your initial bundle size.

So my recommendation would be to stick with gql calls.

I personally have grown to like a pattern where I just write down a gql call for codegen to pick up, and then import the correctly typed DocumentNode:


import { ScheduleList_QueryFragmentDoc } from "./ScheduleList.generated";
if (false) { // this way the bundler strips this out completely
  // eslint-disable-next-line no-unused-expressions
  gql`
    fragment ScheduleList_Query on Query {
      events(year: $year) {
        id
        start_time_ts
        venue {
          id
        }
        ...ScheduleListItem_SchedSession
        ...SectionHeader_SchedEvent
      }
    }
  `;
}
ScheduleList.fragments = {
  Query: ScheduleList_QueryFragmentDoc,
} as const;
fragmentRegistry.register(ScheduleList.fragments.Query);

An alternative would be to just use graphql files next to your component, so you wouldn’t even write it down.

As for gql.tada, I really like the idea, but we have found a bit of a blocker with fragment colocation - it only creates masked types and there’s no good way to get to the unmasked types - but sometimes we make the unmasked response available to you in callback functions, so I’d say it’s 90% there, but if you want to use those callbacks, it might need additional manual typing.