César E. Benavides | Design Engineer & Software Architect
How To Generate TypeScript Types For Any GraphQL API

How To Generate TypeScript Types For Any GraphQL API

5 min read
Tutorial
GraphQL
TypeScript
React

How To Generate TypeScript Types For Any GraphQL API

Credits: GraphQL Code Generator | Example Code Repository

Introduction

(Type) Safety First!

Building robust frontend and backend solutions requires a reliable source of truth. When working with GraphQL APIs, manually typing every response and query variable is tedious, error-prone, and impossible to maintain at scale. Fortunately, the GraphQL ecosystem gives us powerful tooling to automatically generate TypeScript types directly from any GraphQL schema -- ensuring your frontend code stays perfectly in sync with the API.

In this tutorial, we will walk through how to set up GraphQL Code Generator in a Next.js project to automatically generate TypeScript types from a GraphQL API. By the end, you will have a fully typed developer experience with autocompletion, compile-time error checking, and a single command to keep everything up to date.

Getting Started

Prerequisites

  • A Next.js App
  • A Working GraphQL API/Backend (this tutorial uses WPGraphQL as the GraphQL backend, but the approach works with any GraphQL API)

Step 1: Clone an empty Next.js repo

With your package manager of choice, scaffold a new Next.js project with TypeScript:

bun create next-app@latest [your-project-name] --ts

Step 2: Install Dev Dependencies

We need a handful of @graphql-codegen packages as dev dependencies. These handle the CLI, TypeScript type generation, React Apollo hook generation, and operation typing:

  • @graphql-codegen/cli -- The core CLI runner
  • @graphql-codegen/typescript-nhost -- TypeScript type generation
  • @graphql-codegen/typescript-react-apollo -- Typed React Apollo hooks
  • @graphql-codegen/typescript-operations -- Typed operations (queries, mutations, fragments)
  • child_process -- For running shell commands from the generate script
  • dotenv -- For loading environment variables
bun install -D @graphql-codegen/typescript-nhost @graphql-codegen/typescript-react-apollo @graphql-codegen/typescript-operations @graphql-codegen/cli child_process dotenv

Your package.json devDependencies should now look something like this:

{
  "devDependencies": {
    "@graphql-codegen/cli": "^5.0.0",
    "@graphql-codegen/typescript-nhost": "^2.0.0",
    "@graphql-codegen/typescript-operations": "^4.0.0",
    "@graphql-codegen/typescript-react-apollo": "^4.0.0",
    "child_process": "^1.0.2",
    "dotenv": "^16.3.1"
  }
}

Step 3: Create Generation Files

We need three files to wire everything up:

graphql.config.yaml -- This tells the codegen where to find the schema, where to look for operations, and what plugins to use:

schema:
  - ${NEXT_PUBLIC_GRAPHQL_ENDPOINT}:
      headers:
        Authorization: Bearer ${AUTH_TOKEN}
 
documents: "src/**/*.graphql"
 
generates:
  types/wp/index.ts:
    plugins:
      - typescript
      - typescript-operations
      - typescript-react-apollo
    config:
      reactApolloVersion: 3
      withHooks: true
      withHOC: false
      withComponent: false

generate.js -- A small Node script that loads your .env values and runs the codegen CLI:

const { execSync } = require("child_process");
require("dotenv").config({ path: ".env" });
 
const endpoint = process.env.NEXT_PUBLIC_GRAPHQL_ENDPOINT;
const token = process.env.AUTH_TOKEN;
 
if (!endpoint) {
  console.error("Missing NEXT_PUBLIC_GRAPHQL_ENDPOINT in .env");
  process.exit(1);
}
 
const command = `npx graphql-codegen --config graphql.config.yaml`;
 
try {
  execSync(command, {
    stdio: "inherit",
    env: {
      ...process.env,
      NEXT_PUBLIC_GRAPHQL_ENDPOINT: endpoint,
      AUTH_TOKEN: token || "",
    },
  });
} catch (error) {
  console.error("Code generation failed:", error.message);
  process.exit(1);
}

.env -- Add your GraphQL endpoint (and optionally an auth token):

NEXT_PUBLIC_GRAPHQL_ENDPOINT=https://your-wordpress-site.com/graphql
AUTH_TOKEN=your-optional-auth-token

Step 4: Modify package.json

Add a generate script so you can run the codegen with a single command:

{
  "scripts": {
    "dev": "next dev",
    "build": "next build",
    "start": "next start",
    "generate": "node generate.js"
  }
}

Step 5: Run the command

bun generate

This will introspect your GraphQL schema, scan your src/**/*.graphql files for operations, and output fully typed TypeScript to types/wp/index.ts.

Type Safety Achieved

Start using your types!

You should now have a new file within types/wp/index.ts containing every type, query, mutation, and subscription from your GraphQL schema -- fully typed and ready to import. Your IDE will provide autocompletion, compile-time error checking, and inline documentation for every field.

Here are some ways these types can be utilized

Using types in a React component (cards-block.tsx):

import { Page_Flexiblecontent_Blocks_CardsBlock } from "@/types/wp";
 
interface CardsBlockProps {
  block: Page_Flexiblecontent_Blocks_CardsBlock;
}
 
export function CardsBlock({ block }: CardsBlockProps) {
  const { cards, headline, subheadline } = block;
 
  return (
    <section>
      <h2>{headline}</h2>
      <p>{subheadline}</p>
      <div className="grid grid-cols-3 gap-4">
        {cards?.map((card, index) => (
          <div key={index} className="rounded-lg border p-4">
            <h3>{card?.title}</h3>
            <p>{card?.description}</p>
          </div>
        ))}
      </div>
    </section>
  );
}

Using types in a data fetching function (getAllPages.ts):

import { gql } from "@apollo/client";
import { GetAllPagesQuery, GetAllPagesQueryVariables } from "@/types/wp";
import { client } from "@/lib/apollo-client";
 
const GET_ALL_PAGES = gql`
  query GetAllPages {
    pages {
      nodes {
        id
        title
        slug
        uri
        flexibleContent {
          blocks {
            ... on Page_Flexiblecontent_Blocks_HeroBlock {
              headline
              subheadline
              backgroundImage {
                sourceUrl
              }
            }
          }
        }
      }
    }
  }
`;
 
export async function getAllPages() {
  const { data } = await client.query<
    GetAllPagesQuery,
    GetAllPagesQueryVariables
  >({
    query: GET_ALL_PAGES,
  });
 
  return data.pages?.nodes || [];
}

Using types for authentication (refreshAuthToken.ts):

import { gql } from "@apollo/client";
import {
  RefreshAuthTokenMutation,
  RefreshAuthTokenMutationVariables,
} from "@/types/wp";
import { client } from "@/lib/apollo-client";
 
const REFRESH_AUTH_TOKEN = gql`
  mutation RefreshAuthToken($input: RefreshJwtAuthTokenInput!) {
    refreshJwtAuthToken(input: $input) {
      authToken
    }
  }
`;
 
export async function refreshAuthToken(refreshToken: string) {
  const { data } = await client.mutate<
    RefreshAuthTokenMutation,
    RefreshAuthTokenMutationVariables
  >({
    mutation: REFRESH_AUTH_TOKEN,
    variables: {
      input: {
        jwtRefreshToken: refreshToken,
      },
    },
  });
 
  return data?.refreshJwtAuthToken?.authToken;
}

Conclusion

Type safety streamlines development, reduces errors, and makes refactoring fearless. By leveraging GraphQL Code Generator, you get a single source of truth for your entire API surface -- automatically generated, always up to date, and deeply integrated with your IDE.

No more guessing at response shapes. No more manually writing interfaces that drift out of sync. Just run bun generate and let the tooling do the work.

Press K to Hire Me