Writing custom migration and bulk update scripts using the template's shared utilities.
<aside> âšī¸
Prerequisites
npm run gql -- '{ shop { name } }' returns data
</aside>The scripts/lib/migration/ directory provides reusable building blocks for writing scripts against the Shopify Admin API - paginated fetching, throttle-aware retry, progress tracking, and codegen type safety.
<aside> đĄ
Need content management instead? The Shopify CLI now handles this natively, and the AI Toolkit builds on top of it for AI-assisted workflows â same thing, much quicker setup. Use that instead of this template's content management workflow. See the Content Management Guide for details.
</aside>
<aside> đ
Using Claude Code for scripts? CLAUDE.md ships pre-configured for content management. For script-heavy work, update it with your project's context â what data you're migrating, the source system, any field mappings or constraints worth noting. This gives Claude Code the right background when helping you write and debug scripts.
</aside>
Custom scripts are for the other kind of work: migrating data from external platforms, bulk updates across thousands of resources, or any data-heavy operation that needs to run reliably at scale. That's what this guide covers.
The scripts/examples/ folder is intentionally minimal - it contains a single getAllProducts.ts file that demonstrates the paginated-fetch pattern. This is a template, not a full application, so it ships light on purpose. The example exists to show the pattern; your actual scripts will be tailored to your store's specific needs.
The code snippets throughout this guide provide additional context for building on top of the included utilities.
Start by figuring out what data you need. Browse the Shopify Admin GraphQL API reference to find the right query or mutation, then write it using the #graphql tag so codegen can pick it up:
const QUERY = `#graphql
query getProducts($first: Int!, $after: String) {
products(first: $first, after: $after) {
nodes { id title }
pageInfo { hasNextPage endCursor }
}
}
` as const;
Once your query is written, generate TypeScript types from it:
npm run graphql-codegen
Then import the generated types into your script:
import type { GetProductsQuery } from "../types/admin.generated";
adminApi() for individual queries and mutationsThe adminApi() function handles authentication and shop resolution automatically:
import { adminApi } from "./lib/shopify-client.js";
import { disconnect } from "./lib/shopify-auth.js";
try {
const result = await adminApi(QUERY, { id: "gid://shopify/Product/123" });
console.log(result.data);
} finally {
await disconnect();
}