---
title: "Automatically Generate TypeScript Types for Your Shopify Storefront Queries"
slug: "shopify-typescript-codegen-nextjs"
published: "2025-08-07"
updated: "2025-12-21"
validated: "2025-10-20"
categories:
  - "Shopify"
tags:
  - "shopify"
  - "graphql"
llm-intent: "reference"
framework-versions:
  - "next.js@15"
  - "typescript@5"
  - "node@20"
  - "graphql-codegen@4"
status: "stable"
llm-purpose: "Stop writing and updating GraphQL types by hand. Learn how to auto-generate TypeScript types and SDK functions for all your Shopify queries."
llm-prereqs:
  - "General familiarity with the article topic"
llm-outputs:
  - "Completed outcome: Stop writing and updating GraphQL types by hand. Learn how to auto-generate TypeScript types and SDK functions for all your Shopify queries."
---

**Summary Triples**
- (GraphQL Code Generator, scans, project GraphQL queries and fragments to discover operations to type)
- (GraphQL Code Generator, connects to, multiple Shopify GraphQL endpoints (Storefront, Admin, Customer) using per-schema headers)
- (Codegen output, generates, TypeScript types and optional SDK functions for every GraphQL operation)
- (Generated types, remain in sync when, you re-run codegen after schema or operation changes)
- (codegen.yml, supports, multiple schemas with independent headers and env-based tokens)
- (Recommended workflow, includes, local watch mode during development and a CI step before builds to regenerate types)
- (Next.js app, consumes, generated types/SDK for type-safe getStaticProps/getServerSideProps and client code)
- (Using codegen, reduces, manual type maintenance and silent runtime errors caused by schema drift)
- (Authentication, is provided via, environment variables mapped to per-schema headers in the codegen configuration)
- (Plugin recommendations, include, typescript, typescript-operations and a transport SDK plugin (e.g., typescript-graphql-request or typescript-fetch) to produce typed SDK functions)

### {GOAL}
Stop writing and updating GraphQL types by hand. Learn how to auto-generate TypeScript types and SDK functions for all your Shopify queries.

### {PREREQS}
- General familiarity with the article topic

### {STEPS}
1. Follow the detailed walkthrough in the article content below.

<!-- llm:goal="Stop writing and updating GraphQL types by hand. Learn how to auto-generate TypeScript types and SDK functions for all your Shopify queries." -->
<!-- llm:prereq="General familiarity with the article topic" -->
<!-- llm:output="Completed outcome: Stop writing and updating GraphQL types by hand. Learn how to auto-generate TypeScript types and SDK functions for all your Shopify queries." -->

# Automatically Generate TypeScript Types for Your Shopify Storefront Queries
> Stop writing and updating GraphQL types by hand. Learn how to auto-generate TypeScript types and SDK functions for all your Shopify queries.
Matija Žiberna · 2025-08-07

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:

```
lib/shopify/queries/
├── admin/
│   └── metaobjects.ts
├── customer-account/
│   └── customer.ts
└── storefront/
    ├── cart.ts
    ├── collection.ts
    ├── menu.ts
    ├── page.ts
    ├── product.ts
    ├── search.ts
    └── ...12 total files

lib/shopify/fragments/
└── storefront/
    ├── product.ts
    ├── image.ts
    ├── cart.ts
    └── seo.ts

lib/shopify/mutations/
└── storefront/
    └── cart.ts
```

Each query file looked like this:

```typescript
// The old way - manual types everywhere
export const getProductQuery = `
  query getProduct($handle: String!) {
    product(handle: $handle) {
      id
      title
      handle
      variants(first: 100) {
        edges {
          node {
            id
            price {
              amount
              currencyCode
            }
          }
        }
      }
    }
  }
`;

// Manual type definition - error-prone!
export type Product = {
  id: string;
  title: string;
  handle: string;
  variants: {
    edges: Array<{
      node: {
        id: string;
        price: {
          amount: string; // Is this string or number?
          currencyCode: string;
        };
      };
    }>;
  };
};
```

### The Pain Points

1. **Type Mismatches**: Shopify returns `amount` as a string, but I kept assuming it was a number
2. **Missing Fields**: Adding new fields to queries but forgetting to update types
3. **Fragment Management**: Complex fragments shared between queries with no type safety
4. **Multiple APIs**: Shopify has 3 different GraphQL APIs with different schemas
5. **Maintenance Nightmare**: Every schema change required manual type updates

### Why This Matters

In a headless commerce setup, your GraphQL queries are the foundation of your entire app. Wrong types lead to:

- Runtime errors in production
- Poor developer experience
- Bugs that are hard to track down
- Wasted time on manual type maintenance

## Approach Exploration

I have considered couple of approaches. 

#### Option 1: Continue Manual Types

**Pros:** Simple, no new tooling
**Cons:** Error-prone, maintenance heavy, doesn't scale

#### Option 2: GraphQL Code Generator

**Pros:** Automatic, always in sync, supports multiple APIs, great DX
**Cons:** Initial setup complexity, requires build step

#### Option 3: TypeScript + GraphQL Schema Introspection

**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:

```bash
npm install -D @graphql-codegen/cli @graphql-codegen/typescript @graphql-codegen/typescript-operations @graphql-codegen/typescript-graphql-request @shopify/hydrogen-codegen
npm install graphql-request graphql
```

**What each package does:**

- `@graphql-codegen/cli`: Main code generator CLI
- `@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)
- **Admin API**: Private operations (metafield definitions, admin queries)
- **Customer Account API**: Customer authentication and orders

For a deeper dive into how these APIs work together and their specific use cases, check out my comprehensive guide: [Shopify Core APIs Overview](https://www.buildwithmatija.com/blog/shopify-core-apis-overview).

### Step 3: Create the Code Generator Configuration

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.

Create `codegen.ts` in your project root:

```typescript
import "dotenv/config";
import type { CodegenConfig } from "@graphql-codegen/cli";
import { getSchema } from "@shopify/hydrogen-codegen";

// Validate required environment variables
if (
  !process.env.SHOPIFY_STOREFRONT_ACCESS_TOKEN ||
  !process.env.NEXT_PUBLIC_SHOPIFY_STORE_DOMAIN ||
  !process.env.SHOPIFY_ADMIN_API_ACCESS_TOKEN
) {
  throw new Error(
    "Missing required Shopify env vars. Check: SHOPIFY_STOREFRONT_ACCESS_TOKEN, NEXT_PUBLIC_SHOPIFY_STORE_DOMAIN, SHOPIFY_ADMIN_API_ACCESS_TOKEN"
  );
}

/**
 * Multi-API GraphQL Codegen Configuration
 *
 * This configuration generates separate TypeScript types for three Shopify APIs:
 * - Storefront API: Most query files organized in storefront/ folder
 * - Customer Account API: Uses Hydrogen's getSchema for proper schema access
 * - Admin API: metaobjects.ts in admin/ folder
 */
const config: CodegenConfig = {
  generates: {
    // Storefront API - Most queries use this
    "./lib/shopify/generated/storefront.ts": {
      schema: {
        [`https://${process.env.NEXT_PUBLIC_SHOPIFY_STORE_DOMAIN}/api/2025-04/graphql.json`]:
          {
            headers: {
              "X-Shopify-Storefront-Access-Token":
                process.env.SHOPIFY_STOREFRONT_ACCESS_TOKEN!,
            },
          },
      },
      documents: [
        "./lib/shopify/queries/storefront/**/*.ts",
        "./lib/shopify/mutations/storefront/**/*.ts",
        "./lib/shopify/fragments/storefront/**/*.ts",
      ],
      plugins: [
        "typescript",
        "typescript-operations",
        "typescript-graphql-request",
      ],
    },

    // Admin API - metafields.ts and metaobjects.ts (definitions only)
    "./lib/shopify/generated/admin.ts": {
      schema: {
        [`https://${process.env.NEXT_PUBLIC_SHOPIFY_STORE_DOMAIN}/admin/api/2024-01/graphql.json`]:
          {
            headers: {
              "X-Shopify-Access-Token":
                process.env.SHOPIFY_ADMIN_API_ACCESS_TOKEN!,
            },
          },
      },
      documents: ["./lib/shopify/queries/admin/**/*.ts"],
      plugins: [
        "typescript",
        "typescript-operations",
        "typescript-graphql-request",
      ],
    },

    // Customer Account API - Uses Hydrogen's getSchema for proper OAuth handling
    "./lib/shopify/generated/customer-account.ts": {
      schema: getSchema("customer-account"),
      documents: ["./lib/shopify/queries/customer-account/**/*.ts"],
      plugins: [
        "typescript",
        "typescript-operations",
        "typescript-graphql-request",
      ],
    },
  },
  config: {
    avoidOptionals: true,
    maybeValue: "T | null",
  },
};

export default config;
```

**Configuration breakdown:**

- **`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
export const getProductQuery = `
  query getProduct($handle: String!) {
    product(handle: $handle) {
      id
      title
    }
  }
`;
```

**After (works with codegen):**

```typescript
export const 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:

```
[OperationName] + [OperationType] + ["Variables" for variables]
```

#### Examples

For this query:

```typescript
export const getProductsViaSearchQuery = /* GraphQL */ `
  query SearchProducts($query: String!, $first: Int) {
    search(query: $query, first: $first) {
      totalCount
      edges { node { ... } }
    }
  }
`;
```

**Generated type names:**

- **Variables**: `SearchProductsQueryVariables`
- **Result**: `SearchProductsQuery`
- **SDK Function**: `SearchProducts()`

#### The Pattern Breakdown

1. **Operation Name**: `SearchProducts` (from your GraphQL operation)
2. **+ Operation Type**: `Query` (automatically detected and appended)
3. **+ "Variables"**: `Variables` (for input variables)

**More examples:**

```typescript
query getProduct       →  GetProductQuery + GetProductQueryVariables
query predictiveSearch →  PredictiveSearchQuery + PredictiveSearchQueryVariables
mutation addToCart     →  AddToCartMutation + AddToCartMutationVariables
```

**Key Insights:**

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.ts
import 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}
`;

export default productFragment;
```

```typescript
// lib/shopify/queries/product.ts
import productFragment from "../fragments/product";

export const getProductQuery = /* GraphQL */ `
  query getProduct($handle: String!) {
    product(handle: $handle) {
      ...product
    }
  }
  ${productFragment}
`;

export const getProductsQuery = /* GraphQL */ `
  query getProducts($first: Int, $query: String, $sortKey: ProductSortKeys) {
    products(first: $first, query: $query, sortKey: $sortKey) {
      edges {
        node {
          ...product
        }
      }
      pageInfo {
        hasNextPage
        endCursor
      }
    }
  }
  ${productFragment}
`;
```

**Fragment benefits:**

- **Reusability**: Define common field sets once, use everywhere
- **Consistency**: Ensures the same fields are fetched across different queries
- **Maintainability**: Update fragment once, all queries get updated
- **Type Safety**: Generated types automatically include fragment fields

### Step 7: Add Package.json Script

Add the codegen script to your `package.json`:

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

### Step 8: Run Code Generation

Execute the type generation:

```bash
npm run codegen
```

**What happens during generation:**

1. Codegen reads your configuration
2. Fetches GraphQL schemas from Shopify APIs
3. Scans all files in your `documents` arrays
4. Extracts GraphQL operations (queries, mutations, fragments)
5. Matches operations against schemas
6. Generates TypeScript types for each operation
7. Creates SDK functions for making requests

You should see output like:

```
[SUCCESS] Generate to ./lib/shopify/generated/storefront.ts
[SUCCESS] Generate to ./lib/shopify/generated/admin.ts
```

### Step 9: Create a Clean Export System

Create `lib/shopify/types/index.ts` to organize all your types:

```typescript
// Clean exports for all Shopify API types
// This file combines both generated types and manual types for easy importing

// Re-export generated types from Storefront API
export type {
  // Operation types
  GetProductQuery,
  GetProductQueryVariables,
  GetProductsQuery,
  GetProductsQueryVariables,
  PredictiveSearchQuery,
  PredictiveSearchQueryVariables,

  // Schema types
  Product as GeneratedProduct,
  ProductVariant as GeneratedProductVariant,
  MoneyV2 as GeneratedMoney,
  Image as GeneratedImage,
  Collection as GeneratedCollection,
} from "../generated/storefront";

// Re-export generated types from Admin API
export type {
  GetMetafieldsQuery,
  GetMetafieldsQueryVariables,
  MetafieldDefinition as GeneratedMetafieldDefinition,
} from "../generated/admin";

// Re-export any remaining manual types that extend generated ones
export type {
  // Custom types that reshape or extend generated types
  Cart,
  CartItem,
  Product,
  Collection,
  // ... other manual types you still need
} from "../types";

// Convenient type aliases for common use cases
import type { Product, Cart, Collection } from "../types";
export type ProductWithVariants = Product;
export type CartWithItems = Cart;
export type CollectionWithProducts = Collection;

// Operation result types for GraphQL requests
export type StorefrontQueryResult<T> = {
  data: T;
  errors?: Array<{
    message: string;
    locations?: Array<{
      line: number;
      column: number;
    }>;
    path?: Array<string | number>;
  }>;
  extensions?: Record<string, any>;
};
```

---

## FAQ: Troubleshooting Common Issues

### Common Mistakes and Solutions

#### Missing `/* GraphQL */` Comment

**Error:**

```bash
No operations found in documents
```

**What happened:**
Without the special comment, codegen couldn't identify which strings contained GraphQL operations.

**Fix:**
Add `/* GraphQL */` before every query template literal.

#### Wrong API Configuration

**Error:**

```bash
Field 'customer' doesn't exist on type 'QueryRoot'
```

**What happened:**
Customer queries were in the Storefront API configuration instead of Customer Account API.

**Fix:**
Move customer-related queries to the correct API configuration in `codegen.ts`.

#### Fragment Import Issues

**Error:**

```bash
Unknown fragment "product"
```

**What happened:**
Fragment wasn't properly imported or the template literal composition was incorrect.

**Fix:**

```typescript
// Correct fragment usage
export const getProductQuery = /* GraphQL */ `
  query getProduct($handle: String!) {
    product(handle: $handle) {
      ...product
    }
  }
  ${productFragment}  // ← Fragment must be composed here
`;
```

#### Environment Variables Not Loaded

**Error:**

```bash
Missing required Shopify env vars
```

**What happened:**
The `dotenv/config` import in `codegen.ts` couldn't find environment variables.

**Fix:**
Ensure your `.env.local` file is in the project root and contains all required variables.

### Debugging Commands

#### Verify Generated Types

```bash
# Check what types were actually generated
grep -E "export type.*Query" lib/shopify/generated/storefront.ts | head -10
```

#### Test Type Compilation

```bash
# Verify TypeScript compilation works
npx tsc --noEmit lib/shopify/types/index.ts
```

#### Query Extraction Checklist

If a query isn't generating types, ensure:

1. File is listed in `codegen.ts` documents array
2. Query has `/* GraphQL */` comment
3. Query syntax is valid GraphQL
4. Operation has a name (`query getProduct` not just `query`)

## Final Working Version

### Using the Generated Types

Here's how to use your generated types in a Next.js component:

```typescript
// components/ProductCard.tsx
import { getSdk } from '@/lib/shopify/generated/storefront';
import { GraphQLClient } from 'graphql-request';
import type {
  GetProductQuery,
  GetProductQueryVariables
} from '@/lib/shopify/types';

// Create GraphQL client
const client = new GraphQLClient(
  `https://${process.env.NEXT_PUBLIC_SHOPIFY_STORE_DOMAIN}/api/2025-04/graphql.json`,
  {
    headers: {
      'X-Shopify-Storefront-Access-Token': process.env.SHOPIFY_STOREFRONT_ACCESS_TOKEN!,
    },
  }
);

// Get SDK with full type safety
const sdk = getSdk(client);

export async function ProductCard({ handle }: { handle: string }) {
  // Fully typed variables
  const variables: GetProductQueryVariables = { handle };

  // Fully typed response
  const response: GetProductQuery = await sdk.getProduct(variables);

  const product = response.product;

  if (!product) {
    return <div>Product not found</div>;
  }

  return (
    <div>
      <h2>{product.title}</h2>
      <p>{product.description}</p>
      {product.featuredImage && (
        <img
          src={product.featuredImage.url}
          alt={product.featuredImage.altText || product.title}
          width={product.featuredImage.width || 300}
          height={product.featuredImage.height || 300}
        />
      )}
      <div>
        ${product.priceRange.minVariantPrice.amount} {product.priceRange.minVariantPrice.currencyCode}
      </div>
    </div>
  );
}
```

### Project Structure Overview

Your final project structure should look like:

```
├── codegen.ts                          # Code generator configuration
├── lib/shopify/
│   ├── queries/                        # GraphQL queries
│   │   ├── product.ts                  # Product queries
│   │   ├── cart.ts                     # Cart operations
│   │   ├── search.ts                   # Search functionality
│   │   └── ...
│   ├── fragments/                      # Reusable GraphQL fragments
│   │   ├── product.ts                  # Product fields
│   │   ├── image.ts                    # Image fields
│   │   └── ...
│   ├── generated/                      # Auto-generated files (don't edit!)
│   │   ├── storefront.ts               # Storefront API types
│   │   ├── admin.ts                    # Admin API types
│   │   └── customer-account.ts         # Customer API types
│   ├── types/
│   │   ├── index.ts                    # Clean exports
│   │   └── types.ts                    # Legacy manual types
│   └── utils/
│       └── clients.ts                  # GraphQL client setup
└── package.json                        # Scripts for codegen
```

### Development Workflow

1. **Write or modify a GraphQL query** with `/* GraphQL */` comment
2. **Run code generation**: `npm run codegen`
3. **Import generated types** in your components
4. **Use the SDK functions** for type-safe requests
5. **Repeat** as you add new features

**Key benefits of this approach:**

- **Always in sync**: Types match your actual queries
- **Compile-time safety**: Catch errors before runtime
- **Great DX**: Autocomplete and IntelliSense for all fields
- **SDK functions**: No need to write GraphQL request boilerplate
- **Multi-API support**: Handle Shopify's complex API structure

## Optional Improvements & Best Practices

### 1. Automated Code Generation

Add codegen to your build process:

```json
{
  "scripts": {
    "build": "npm run codegen && next build",
    "dev": "npm run codegen && next dev"
  }
}
```

### 2. Git Integration

Add generated files to `.gitignore` or commit them:

```gitignore
# Option 1: Ignore generated files (regenerate on each deploy)
lib/shopify/generated/

# Option 2: Commit generated files (faster deploys, easier debugging)
# Keep generated files in git
```

**Tip:** Committing generated files makes deployments faster but creates larger diffs. Choose based on your team's preference.

### 3. Type-Safe Client Wrapper

For the Customer Account API, create a specialized client that handles authentication properly:

```typescript
// lib/shopify/utils/customer-account-sdk.ts
import { GraphQLClient } from "graphql-request";
import { getSdk } from "../generated/customer-account";
import { SHOPIFY_CUSTOMER_ACCOUNT_API_ENDPOINT } from "lib/constants";

/**
 * Creates Customer Account API SDK client with authentication
 */
export function createCustomerAccountSdk(accessToken: string) {
  // Create a client with custom fetch that handles token formatting
  const client = new GraphQLClient(SHOPIFY_CUSTOMER_ACCOUNT_API_ENDPOINT, {
    fetch: async (url: RequestInfo | URL, init?: RequestInit) => {
      const { formatAccessToken } = await import("lib/auth/session");
      const formattedToken = formatAccessToken(accessToken);

      return fetch(url, {
        ...init,
        headers: {
          ...init?.headers,
          "Content-Type": "application/json",
          Authorization: formattedToken, // Customer Account API expects token directly, no "Bearer" prefix
        },
      });
    },
  });

  return getSdk(client);
}

// Export for type inference helpers
export type CustomerAccountSdk = ReturnType<typeof createCustomerAccountSdk>;
```

### 4. Cache Integration

Integrate with Next.js caching:

```typescript
// lib/shopify/cached-client.ts
import { unstable_cache } from "next/cache";
import { shopifyClient } from "./client";

export const getCachedProduct = unstable_cache(
  async (handle: string) => {
    return shopifyClient.getProduct({ handle });
  },
  ["product"],
  { revalidate: 3600 } // 1 hour cache
);
```

### 5. Development Scripts

Add helpful development scripts:

```json
{
  "scripts": {
    "codegen": "graphql-codegen --config codegen.ts",
    "codegen:watch": "graphql-codegen --config codegen.ts --watch",
    "codegen:check": "graphql-codegen --config codegen.ts --check",
    "types:check": "tsc --noEmit"
  }
}
```

## Summary

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.

Thanks,
Matija

## LLM Response Snippet
```json
{
  "goal": "Stop writing and updating GraphQL types by hand. Learn how to auto-generate TypeScript types and SDK functions for all your Shopify queries.",
  "responses": [
    {
      "question": "What does the article \"Automatically Generate TypeScript Types for Your Shopify Storefront Queries\" cover?",
      "answer": "Stop writing and updating GraphQL types by hand. Learn how to auto-generate TypeScript types and SDK functions for all your Shopify queries."
    }
  ]
}
```