Codegen
Typed Queries
Generate TypedDocumentNode exports for fully typed GraphQL queries
Overview
The @universal-data-layer/codegen-typed-queries extension generates TypedDocumentNode exports from your .graphql files. This provides complete type safety for both query results and variables.
Installation
Terminal
npm install @universal-data-layer/codegen-typed-queries
Configuration
Add the extension to your codegen config:
udl.config.ts
import { defineConfig } from 'universal-data-layer';
export const config = defineConfig({
plugins: [
{
name: '@universal-data-layer/plugin-source-contentful',
options: {
spaceId: process.env['CONTENTFUL_SPACE_ID'],
accessToken: process.env['CONTENTFUL_ACCESS_TOKEN'],
},
},
],
codegen: {
output: './generated',
extensions: ['@universal-data-layer/codegen-typed-queries'],
},
});
Creating Query Files
Create .graphql files anywhere in your project:
app/queries/products.graphql
query GetAllProducts {
allContentfulProducts {
name
slug
price
description
}
}
query GetProductBySlug($slug: String!) {
contentfulProduct(slug: $slug) {
name
slug
price
description
image {
... on ContentfulAsset {
file {
url
}
}
}
}
}
Generated Output
After running the server (which triggers codegen), you'll have:
generated/
├── queries/
│ └── index.ts # TypedDocumentNode exports
├── types/
│ └── index.ts # Schema types
└── index.ts # Re-exports everything
The queries file contains:
// generated/queries/index.ts
export interface GetAllProductsResult {
allContentfulProducts: Array<{
name: string;
slug: string;
price: number;
description: string;
}>;
}
export const GetAllProducts: TypedDocumentNode<
GetAllProductsResult,
Record<string, never>
>;
export interface GetProductBySlugVariables {
slug: string;
}
export interface GetProductBySlugResult {
contentfulProduct: {
name: string;
slug: string;
price: number;
description: string;
image: {
file: {
url: string;
};
};
} | null;
}
export const GetProductBySlug: TypedDocumentNode<
GetProductBySlugResult,
GetProductBySlugVariables
>;
Using Generated Queries
Import and use the generated queries with the UDL client:
import { udl } from 'universal-data-layer/client';
import { GetAllProducts, GetProductBySlug } from '@/generated/queries';
// Result type is automatically inferred
const [error, products] = await udl.query(GetAllProducts);
if (error) {
console.error('Failed to fetch products:', error.message);
return;
}
// TypeScript knows products is Array<{ name, slug, price, description }>
for (const product of products) {
console.log(product.name, product.price);
}
With variables:
import { udl } from 'universal-data-layer/client';
import { GetProductBySlug } from '@/generated/queries';
// Variables are type-checked - must include { slug: string }
const [error, product] = await udl.query(GetProductBySlug, {
variables: { slug: 'my-product' },
});
if (error || !product) {
return;
}
// TypeScript knows the exact shape of product
console.log(product.name, product.image?.file.url);
Type Inference
The extension generates precise types based on your query's selection set:
- Selection sets - Only fields you request are in the result type
- Variables - Required/optional based on
!in the query definition - Nullable fields - Marked as
| nullwhen appropriate - Arrays - Detected from schema and typed correctly
Query Discovery
The extension automatically discovers .graphql and .gql files in your project. It searches:
- All directories except
node_modules,.git, and your output directory - Both
.graphqland.gqlextensions - Multiple queries per file are supported
Limitations
- Fragments - Not yet fully supported. Inline fragment types work, but shared fragments may not resolve correctly.
- Custom scalars - Default to
unknowntype. Define custom scalar mappings if needed. - Named operations only - Anonymous queries are skipped. Always name your operations.
Alternative: graphql-codegen
For advanced features like fragment support, consider using GraphQL Code Generator:
Terminal
npm install @graphql-codegen/cli @graphql-codegen/typescript @graphql-codegen/typescript-operations @graphql-codegen/typed-document-node
codegen.yml
schema: http://localhost:4000/graphql
documents: 'app/**/*.graphql'
generates:
./generated/operations.ts:
plugins:
- typescript
- typescript-operations
- typed-document-node
Next Steps
- CLI Reference - Standalone codegen options
- Next.js Integration - Use typed queries with Next.js