Building a headless Shopify storefront with Next.js should be exciting, but I found myself trapped in a frustrating cycle that was draining my productivity and confidence. Every time I needed to fetch products, manage cart operations, or query collections, I faced the same tedious process: write a GraphQL query, then manually craft TypeScript types that I hoped would match Shopify's ever-evolving schema.
The reality was far from ideal. I'd spend hours carefully typing out interfaces, second-guessing whether Shopify returned amount as a string or number, whether fields were nullable, or what the exact structure of nested objects looked like. Worse yet, when I updated queries to add new fields or optimize performance, I'd inevitably forget to update the corresponding types. This led to a cascade of silent failures, mysterious runtime errors, and late-night debugging sessions trying to figure out why my perfectly valid-looking code was breaking in production.
What started as a simple e-commerce project became a maintenance nightmare. I was spending more time managing types than building features, and every schema change from Shopify felt like a potential disaster waiting to happen. There had to be a better way.
Before: Manual types that get outdated, are prone to errors, and require constant maintenance - turning feature development into a frustrating guessing game.
After: Automatically generated types that are always in sync with your GraphQL operations and Shopify's schema - letting you focus on building great user experiences instead of wrestling with type definitions.
What We'll Build
A complete GraphQL code generation system that:
Scans all your GraphQL queries and fragments
Connects to Shopify's multiple APIs (Storefront, Admin, Customer Account)
Generates TypeScript types for every operation
Creates a clean export system for easy importing
Provides SDK functions for type-safe GraphQL requests
Tech Stack
Next.js 15 with App Router
Shopify Storefront API, Admin API, Customer Account API
GraphQL Code Generator (@graphql-codegen/cli) -> This is crucial for this to work
GraphQL Request for client operations
Problem Setup
I had a Next.js 15 e-commerce app with dozens of GraphQL queries spread across multiple files. The queries are now organized by Shopify API type, making it clear which API each query targets:
Pros: No codegen needed
Cons: Runtime overhead, complex setup for multiple APIs
Why I Chose GraphQL Code Generator
GraphQL Code Generator is the industry standard because it:
Generates types at build time (no runtime cost)
Supports complex multi-API setups like Shopify's
Creates both types AND SDK functions
Has excellent Next.js integration
Handles fragments and complex nested structures perfectly
Implementation
Now comes the exciting part – setting up automatic type generation that will transform how you work with GraphQL in your Shopify project. We'll walk through this implementation step-by-step, and by the end, you'll have a system that automatically generates both TypeScript types and SDK functions for all your Shopify API operations.
The process involves several key steps: installing the necessary packages, configuring multiple Shopify API schemas, organizing your queries properly, and setting up the code generation pipeline. Each step builds on the previous one, so we'll take it methodically to ensure everything works perfectly.
Step 1: Install Dependencies
First, let's install the necessary packages for GraphQL code generation:
@graphql-codegen/typescript: Generates base TypeScript types from GraphQL schema
@graphql-codegen/typescript-operations: Generates types for your specific queries/mutations
@graphql-codegen/typescript-graphql-request: Creates SDK functions for graphql-request client
@shopify/hydrogen-codegen: Provides Shopify's Customer Account API schema access
graphql-request: Lightweight GraphQL client (alternative to Apollo)
Step 2: Set Up Environment Variables
Create or update your .env with Shopify API credentials. If you're deploying to Vercel, make sure to add these to your Vercel project's environment variables as well:
bash
# Storefront API (public, for product/collection queries)# Found in your Shopify headless app - use the "Storefront access token"
SHOPIFY_STOREFRONT_ACCESS_TOKEN=your_storefront_token
NEXT_PUBLIC_SHOPIFY_STORE_DOMAIN=your-store.myshopify.com
# Admin API (private, for metafields/admin operations)# Found in your Shopify private app - use the "Admin API access token"
SHOPIFY_ADMIN_API_ACCESS_TOKEN=your_admin_token
# Customer Account API (optional, for customer authentication)# Found in your Shopify headless app - just the shop ID is needed for public schema access
NEXT_PUBLIC_SHOPIFY_SHOP_ID=your_shop_id
Why multiple APIs?
Shopify separates functionality across different GraphQL APIs:
Storefront API: Public data (products, collections, cart)
This is where the magic happens! We're about to configure a system that will automatically scan all your GraphQL queries, connect to Shopify's schemas, and generate both precise TypeScript types and ready-to-use SDK functions. The best part? Once this is set up, every time you modify a query, the types update automatically – no more manual typing, no more guessing about field structures or nullability.
generates: Defines what files to create and from which sources
schema: Points to Shopify's GraphQL schema endpoints with authentication
documents: Array of files containing your GraphQL operations
plugins: What to generate (base types, operation types, SDK functions)
config.avoidOptionals: Makes nullable fields explicit (T | null instead of T?)
Step 4: Fix Your Query Format
Critical Step: GraphQL Code Generator only recognizes queries with the /* GraphQL */ comment.
Before (doesn't work with codegen):
typescript
exportconst getProductQuery = `
query getProduct($handle: String!) {
product(handle: $handle) {
id
title
}
}
`;
After (works with codegen):
typescript
exportconst getProductQuery = /* GraphQL */`
query getProduct($handle: String!) {
product(handle: $handle) {
id
title
}
}
`;
Why the comment matters:
The /* GraphQL */ comment is a special marker that tells the code generator "this string contains a GraphQL operation." Without it, the generator skips the query entirely.
Step 5: Understanding Generated Type Names
GraphQL codegen automatically creates type names based on your operation names, following a predictable pattern.
Type Naming Rules
GraphQL codegen uses this pattern:
code
[OperationName] + [OperationType] + ["Variables" for variables]
The JavaScript variable name like getProductsViaSearchQuery is completely ignored by the code generator. Only the GraphQL operation name like SearchProducts matters for type generation. The system automatically appends "Query", "Mutation", or "Subscription" to create the final type names, so you should never include the operation type in your operation name to avoid redundancy like SearchProductsQueryQuery.
Best Practice:
typescript
// Good - clear operation name
query SearchProducts { ... } → SearchProductsQuery// Bad - redundant naming
query SearchProductsQuery { ... } → SearchProductsQueryQuery
Step 6: Structure Your Query Files
Organize your queries with proper fragments for reusability:
typescript
// lib/shopify/fragments/product.tsimport imageFragment from"./image";
import seoFragment from"./seo";
const productFragment = /* GraphQL */`
fragment product on Product {
id
handle
title
description
availableForSale
featuredImage {
...image
}
variants(first: 100) {
edges {
node {
id
title
price {
amount
currencyCode
}
selectedOptions {
name
value
}
}
}
}
seo {
...seo
}
}
${imageFragment}${seoFragment}
`;
exportdefault productFragment;
By implementing GraphQL Code Generation, you've transformed your Shopify headless storefront from error-prone manual types to a robust, automatically-maintained type system.
What you've gained:
Type Safety: Compile-time errors instead of runtime surprises
Always In Sync: Types automatically match your queries
Better DX: Full autocomplete and IntelliSense support
SDK Functions: No more manual GraphQL request boilerplate
Multi-API Support: Clean handling of Shopify's complex API structure
Maintainability: Add new queries without manual type work
The key insight: The simple /* GraphQL */ comment is what unlocks automatic type generation. This small change eliminates hours of manual type maintenance and prevents entire categories of bugs.
Your codebase is now more reliable, maintainable, and developer-friendly. As you add new features, the type system will grow automatically with your queries, keeping everything in perfect sync.