Photo by PJH on Unsplash

On this page

This chapter follows Getting started with urql.

String queries in components drift from the schema silently. GraphQL Code Generator reads your schema and operation documents, then emits TypeScript that tracks field types through refactors.

Install

Terminal window
pnpm add -D @graphql-codegen/cli @graphql-codegen/client-preset
pnpm add graphql

Point the schema at your NestJS schema.gql, introspection URL, or a checked-in SDL file.

Configure codegen.ts

codegen.ts
import type { CodegenConfig } from "@graphql-codegen/cli";
const config: CodegenConfig = {
schema: "http://localhost:3000/graphql",
documents: ["src/**/*.graphql"],
ignoreNoDocuments: true,
generates: {
"./src/gql/": {
preset: "client",
presetConfig: {
fragmentMasking: { unmaskFunctionName: "getFragmentData" },
},
config: {
useTypeImports: true,
},
},
},
};
export default config;

Add a script:

"scripts": {
"codegen": "graphql-codegen --config codegen.ts",
"codegen:watch": "graphql-codegen --config codegen.ts --watch"
}

Run pnpm codegen whenever schema or documents change; use watch during development.

Write operations in .graphql files

src/features/books/queries.graphql
query Books {
books {
id
title
}
}
mutation CreateBook($input: CreateBookInput!) {
createBook(input: $input) {
id
title
}
}

The client preset emits the graphql() function and typed document constants—no separate @graphql-codegen/typescript-urql plugin is required when you call urql with generated documents.

Use generated documents with urql

src/features/books/BooksList.tsx
import { useQuery } from "urql";
import { graphql } from "../../gql";
const BooksDocument = graphql(`
query Books {
books {
id
title
}
}
`);
export function BooksList() {
const [result] = useQuery({ query: BooksDocument });
// result.data is typed
}

Import graphql only from the generated folder so the compiler validates operations.

Fragment masking

Colocate fragments and unwrap them with FragmentType and getFragmentData (or your configured unmask name):

src/features/books/BookSummary.graphql
fragment BookSummary on Book {
id
title
}
import { type FragmentType, getFragmentData } from "../../gql";
import { graphql } from "../../gql";
const BookSummaryFragment = graphql(`
fragment BookSummary on Book {
id
title
}
`);
type Props = { book: FragmentType<typeof BookSummaryFragment> };
export function BookCard({ book }: Props) {
const data = getFragmentData(BookSummaryFragment, book);
return <span>{data.title}</span>;
}

Masking prevents parent components from relying on fields they did not spread.

Persisted documents (optional)

For trusted documents / APQ-style allowlists, add a plugin output that hashes operations:

codegen.ts
generates: {
"./src/gql/": { preset: "client" },
"./persisted-documents.json": {
plugins: ["persisted-operations"],
},
}

Upload hashes to the gateway so only known operations execute in production—a security pattern covered later in this series.

Next: Normalized caching with urql Graphcache.

Search articles

Type a word to search published articles.

Open the search page