Branch8

How to Migrate Your Shopify Store to Headless Commerce

Matt Li
Matt Li
March 23, 2026
14 mins read
Shopify headless commerce migration guide — decoupled frontend architecture with Storefront API

Key Takeaways

  • Storefront API decouples frontend while Shopify handles checkout
  • Next.js or Hydrogen are the strongest framework choices
  • Multi-currency needs the @inContext GraphQL directive
  • Budget 8–16 weeks and plan for ongoing maintenance costs
  • Redirect mapping is critical to preserve SEO rankings

To migrate a Shopify store to headless commerce, decouple your frontend from Shopify's backend using the Storefront API, build a custom frontend with a framework like Next.js or Hydrogen, connect your data layer, and redirect traffic. The process typically takes 8–16 weeks depending on catalog complexity and the number of third-party integrations.

Why Would You Migrate a Shopify Store to Headless Commerce?

Headless commerce separates your storefront's presentation layer from the commerce engine. Shopify continues to handle products, checkout, inventory, and payments, but your frontend — what customers actually see and interact with — runs independently on a framework you control.

The reasons to go headless vary by market and business model, but the most common drivers we see from clients across Asia are:

  • Performance in low-bandwidth markets. Static-generated pages and edge-cached content load significantly faster in Southeast Asian markets where mobile connections can be inconsistent. According to Google's Web Vitals research, pages that meet Core Web Vitals thresholds see 24% fewer abandonments.
  • Multi-market, multi-language flexibility. A headless frontend gives you full control over locale routing, content structure, and UX patterns that differ across Hong Kong, Taiwan, Singapore, and beyond — without being constrained by Shopify's theme architecture.
  • Composable architecture. You can plug in a headless CMS (Contentful, Sanity, Strapi) for editorial content, a separate search provider (Algolia, Typesense), and market-specific payment gateways without modifying the Shopify backend.
  • Custom checkout experiences. Shopify Plus merchants can use the Checkout Extensibility API to customize checkout, but headless gives you even more control over pre-checkout flows, bundling UIs, and subscription logic.

According to Shopify's own 2024 Commerce Trends report, merchants using headless architectures reported 30–50% improvements in page load times compared to traditional Liquid themes. That said, headless is not universally the right choice — it adds infrastructure complexity and ongoing maintenance costs. For stores with simple catalogs and no multi-market requirements, a well-optimized Shopify theme may be sufficient.

What Are the Prerequisites Before Starting?

Before writing a single line of code, make sure these foundations are in place:

Shopify Plan Requirements

You need access to the Storefront API, which is available on all Shopify plans. However, for production headless builds, we strongly recommend Shopify Plus because it provides:

  • Higher Storefront API rate limits (per Shopify's API documentation, Plus merchants get significantly more generous throttling)
  • Access to Checkout Extensibility and Functions
  • Multi-currency and multi-language at the platform level
  • Dedicated support and a launch engineer

Technical Prerequisites

  1. Node.js 18+ installed locally
  2. A Shopify Storefront API access token — generated in your Shopify admin under Settings → Apps and sales channels → Develop apps
  3. Git and a deployment platform account (Vercel, Netlify, or Cloudflare Pages)
  4. A headless CMS account if you plan to manage non-commerce content separately (optional but recommended)
  5. Your current theme's audit — document every custom feature, third-party script, and integration in your existing Liquid theme

API Token Setup

In your Shopify admin:

  1. Go to Settings → Apps and sales channels → Develop apps
  2. Click Create an app and name it (e.g., headless-storefront)
  3. Under Configuration, select the Storefront API scopes you need. At minimum, enable:
  • unauthenticated_read_product_listings
  • unauthenticated_read_product_inventory
  • unauthenticated_read_customers (if using customer accounts)
  • unauthenticated_write_checkouts
  • unauthenticated_read_checkouts
  • unauthenticated_read_content
  1. Click Install app and copy your Storefront API access token

Store this token securely — it will be used as an environment variable in your frontend application. Never commit it to a public repository.

Ready to Transform Your Ecommerce Operations?

Branch8 specializes in ecommerce platform implementation and AI-powered automation solutions. Contact us today to discuss your ecommerce automation strategy.

Which Frontend Framework Should You Choose?

This is one of the most consequential decisions in the migration. Here are the three most viable options for Shopify headless storefronts in 2025–2026:

Hydrogen + Oxygen (Shopify's Own Stack)

Hydrogen is Shopify's React-based framework built specifically for headless Shopify storefronts. It runs on Oxygen, Shopify's hosting infrastructure.

  • Pros: Tight Storefront API integration, built-in cart and checkout utilities, Shopify-managed hosting, SSR with streaming
  • Cons: Vendor lock-in to Shopify's hosting (Oxygen), smaller community compared to Next.js, fewer third-party tutorials
  • Best for: Teams that want the fastest path to a headless Shopify store and are comfortable with React

Next.js (Vercel)

Next.js 14+ with the App Router is the most popular choice for headless commerce broadly. The @shopify/hydrogen-react package provides React hooks and components you can use outside of Hydrogen.

  • Pros: Massive community, flexible deployment (Vercel, Cloudflare, self-hosted), ISR and SSG for performance, extensive plugin library
  • Cons: You build more from scratch compared to Hydrogen, need to manage Shopify data fetching patterns yourself
  • Best for: Teams with existing Next.js expertise or those who need to integrate multiple backends beyond Shopify

Nuxt 3 (Vue.js)

If your team is Vue-focused, Nuxt 3 is a strong option. There's no official Shopify SDK for Vue, but the Storefront API is GraphQL-based, so any GraphQL client works.

  • Pros: Vue's approachability, Nitro server engine for flexible deployment, strong in APAC development communities (particularly popular in Taiwan and Vietnam)
  • Cons: No official Shopify component library, more manual integration work
  • Best for: Vue-skilled teams willing to build their own Shopify integration layer

When our team migrated a Hong Kong fashion retailer's Shopify Plus store to headless in Q3 2025, we chose Next.js 14 on Vercel because the client also needed to pull editorial content from Sanity CMS and product reviews from Judge.me's API. The migration took 11 weeks from kickoff to launch, with a 3-person frontend team in our Vietnam office and a technical architect in Hong Kong. Post-launch, the client's Largest Contentful Paint (LCP) dropped from 4.2s to 1.1s, and their mobile conversion rate increased by 18% within the first 60 days.

How Do You Set Up the Headless Frontend? (Step-by-Step)

The following steps use Next.js 14 with the App Router. Adjust accordingly if you chose Hydrogen or Nuxt.

Step 1: Initialize the Project

1npx create-next-app@latest my-headless-store --typescript --tailwind --app
2cd my-headless-store

Install the Shopify dependencies:

1npm install @shopify/hydrogen-react graphql graphql-request

Step 2: Configure Environment Variables

Create a .env.local file in your project root:

1SHOPIFY_STORE_DOMAIN=your-store.myshopify.com
2SHOPIFY_STOREFRONT_API_TOKEN=your_storefront_api_token_here
3SHOPIFY_STOREFRONT_API_VERSION=2025-01

The API version should match Shopify's latest stable release. As of early 2026, 2025-01 or 2025-04 are current. Check Shopify's API versioning documentation for the latest.

Step 3: Create the Shopify Client

Create a utility file at lib/shopify.ts:

1import { GraphQLClient } from 'graphql-request';
2
3const domain = process.env.SHOPIFY_STORE_DOMAIN!;
4const token = process.env.SHOPIFY_STOREFRONT_API_TOKEN!;
5const apiVersion = process.env.SHOPIFY_STOREFRONT_API_VERSION!;
6
7const endpoint = `https://${domain}/api/${apiVersion}/graphql.json`;
8
9export const shopifyClient = new GraphQLClient(endpoint, {
10 headers: {
11 'X-Shopify-Storefront-Access-Token': token,
12 'Content-Type': 'application/json',
13 },
14});
15
16export async function shopifyFetch<T>(query: string, variables?: Record<string, unknown>): Promise<T> {
17 try {
18 const data = await shopifyClient.request<T>(query, variables);
19 return data;
20 } catch (error) {
21 console.error('Shopify API Error:', error);
22 throw error;
23 }
24}

Step 4: Fetch Products

Create a query file at lib/queries/products.ts:

1import { gql } from 'graphql-request';
2
3export const GET_PRODUCTS = gql`
4 query GetProducts($first: Int!) {
5 products(first: $first) {
6 edges {
7 node {
8 id
9 title
10 handle
11 description
12 priceRange {
13 minVariantPrice {
14 amount
15 currencyCode
16 }
17 }
18 images(first: 1) {
19 edges {
20 node {
21 url
22 altText
23 width
24 height
25 }
26 }
27 }
28 }
29 }
30 }
31 }
32`;
33
34export const GET_PRODUCT_BY_HANDLE = gql`
35 query GetProductByHandle($handle: String!) {
36 productByHandle(handle: $handle) {
37 id
38 title
39 description
40 variants(first: 25) {
41 edges {
42 node {
43 id
44 title
45 priceV2 {
46 amount
47 currencyCode
48 }
49 availableForSale
50 }
51 }
52 }
53 images(first: 10) {
54 edges {
55 node {
56 url
57 altText
58 width
59 height
60 }
61 }
62 }
63 }
64 }
65`;

Step 5: Build the Product Listing Page

Create app/products/page.tsx:

1import { shopifyFetch } from '@/lib/shopify';
2import { GET_PRODUCTS } from '@/lib/queries/products';
3import Link from 'next/link';
4
5interface ProductsResponse {
6 products: {
7 edges: Array<{
8 node: {
9 id: string;
10 title: string;
11 handle: string;
12 description: string;
13 priceRange: {
14 minVariantPrice: {
15 amount: string;
16 currencyCode: string;
17 };
18 };
19 images: {
20 edges: Array<{
21 node: {
22 url: string;
23 altText: string | null;
24 };
25 }>;
26 };
27 };
28 }>;
29 };
30}
31
32export default async function ProductsPage() {
33 const data = await shopifyFetch<ProductsResponse>(GET_PRODUCTS, { first: 20 });
34
35 return (
36 <div className="grid grid-cols-2 md:grid-cols-4 gap-6 p-8">
37 {data.products.edges.map(({ node }) => (
38 <Link key={node.id} href={`/products/${node.handle}`}>
39 <div className="group cursor-pointer">
40 {node.images.edges[0] && (
41 <img
42 src={node.images.edges[0].node.url}
43 alt={node.images.edges[0].node.altText || node.title}
44 className="w-full aspect-square object-cover"
45 />
46 )}
47 <h2 className="mt-2 text-sm font-medium">{node.title}</h2>
48 <p className="text-sm text-gray-600">
49 {node.priceRange.minVariantPrice.currencyCode}{' '}
50 {parseFloat(node.priceRange.minVariantPrice.amount).toFixed(2)}
51 </p>
52 </div>
53 </Link>
54 ))}
55 </div>
56 );
57}

Expected output: Run npm run dev, navigate to http://localhost:3000/products, and you should see a grid of your Shopify products with images, titles, and prices.

Step 6: Implement the Cart with Storefront API

The Storefront API uses a Cart object (which replaced the older Checkout object). Create lib/queries/cart.ts:

1import { gql } from 'graphql-request';
2
3export const CREATE_CART = gql`
4 mutation CreateCart($input: CartInput!) {
5 cartCreate(input: $input) {
6 cart {
7 id
8 checkoutUrl
9 lines(first: 10) {
10 edges {
11 node {
12 id
13 quantity
14 merchandise {
15 ... on ProductVariant {
16 id
17 title
18 priceV2 {
19 amount
20 currencyCode
21 }
22 }
23 }
24 }
25 }
26 }
27 }
28 userErrors {
29 field
30 message
31 }
32 }
33 }
34`;
35
36export const ADD_TO_CART = gql`
37 mutation AddToCart($cartId: ID!, $lines: [CartLineInput!]!) {
38 cartLinesAdd(cartId: $cartId, lines: $lines) {
39 cart {
40 id
41 checkoutUrl
42 lines(first: 50) {
43 edges {
44 node {
45 id
46 quantity
47 merchandise {
48 ... on ProductVariant {
49 id
50 title
51 }
52 }
53 }
54 }
55 }
56 }
57 userErrors {
58 field
59 message
60 }
61 }
62 }
63`;

The checkoutUrl returned by the Cart API directs customers to Shopify's hosted checkout. On Shopify Plus, you can customize this checkout using Checkout Extensibility. For non-Plus stores, the hosted checkout is your only option — but it handles payments, taxes, and shipping reliably across all markets.

Ready to Transform Your Ecommerce Operations?

Branch8 specializes in ecommerce platform implementation and AI-powered automation solutions. Contact us today to discuss your ecommerce automation strategy.

How Do You Handle Multi-Currency and Multi-Language for Asian Markets?

This is where headless becomes particularly valuable for cross-border APAC operations. Shopify Markets (available on Plus) provides the backend infrastructure for multi-currency and localized pricing, but your headless frontend needs to handle locale detection and routing.

Add a @shopify/hydrogen-react context wrapper for international pricing. In your Storefront API queries, include the @inContext directive:

1query GetProducts($first: Int!, $country: CountryCode!, $language: LanguageCode!)
2 @inContext(country: $country, language: $language) {
3 products(first: $first) {
4 edges {
5 node {
6 title
7 priceRange {
8 minVariantPrice {
9 amount
10 currencyCode
11 }
12 }
13 }
14 }
15 }
16}

Pass country: "HK" and language: "ZH" for Hong Kong, or country: "SG" and language: "EN" for Singapore. This returns localized prices in the correct currency automatically, assuming you've configured Shopify Markets in your admin.

According to Shopify's Markets documentation, the @inContext directive supports all countries and languages that you've enabled in your Shopify Markets settings. For our Hong Kong fashion retailer, we configured five markets (HK, TW, SG, MY, PH) and used Next.js middleware to detect the user's country via Vercel's x-vercel-ip-country header, routing them to the appropriate locale prefix.

How Do You Handle Redirects and SEO During Migration?

This step is critical and often underestimated. A poorly handled migration can destroy your organic search traffic.

URL Structure Mapping

Shopify's default URL structure uses patterns like:

  • /products/product-handle
  • /collections/collection-handle
  • /pages/page-handle
  • /blogs/news/article-handle

Your headless frontend doesn't have to match these exactly, but if you change any URLs, you must set up 301 redirects. We recommend keeping the same URL structure to minimize redirect chains.

Redirect Configuration in Next.js

In your next.config.js:

1module.exports = {
2 async redirects() {
3 return [
4 // Example: if you changed collection URLs
5 {
6 source: '/collections/:handle',
7 destination: '/shop/:handle',
8 permanent: true,
9 },
10 ];
11 },
12};

Metadata and Structured Data

Use Next.js 14's Metadata API to generate dynamic SEO tags from Shopify product data:

1// app/products/[handle]/page.tsx
2import type { Metadata } from 'next';
3
4export async function generateMetadata({ params }: { params: { handle: string } }): Promise<Metadata> {
5 const product = await getProductByHandle(params.handle);
6 return {
7 title: product.seo?.title || product.title,
8 description: product.seo?.description || product.description?.substring(0, 155),
9 openGraph: {
10 images: [product.images.edges[0]?.node.url],
11 },
12 };
13}

Add JSON-LD structured data for products to maintain rich snippets in search results. According to Google's Search Central documentation, Product structured data should include name, image, description, offers with price and priceCurrency, and availability.

Ready to Transform Your Ecommerce Operations?

Branch8 specializes in ecommerce platform implementation and AI-powered automation solutions. Contact us today to discuss your ecommerce automation strategy.

How Do You Deploy and Go Live?

Deployment Options

  • Vercel — The most straightforward option for Next.js. Push to GitHub, connect to Vercel, and deployments happen automatically. Edge functions run across global PoPs including Hong Kong, Singapore, and Tokyo.
  • Cloudflare Pages — Strong option if you're already using Cloudflare for DNS/CDN. Their Asia network coverage is extensive, with data centers in over 30 Asian cities according to Cloudflare's network page.
  • Oxygen — If you chose Hydrogen, Shopify's Oxygen hosting is the default deployment target.

Go-Live Checklist

  1. Verify all Storefront API queries return correct data in production environment variables
  2. Test checkout flow end-to-end — add to cart, proceed to Shopify checkout, complete a test purchase
  3. Validate redirects — use a tool like Screaming Frog to crawl your old sitemap and confirm every URL either resolves or redirects
  4. Submit updated sitemap to Google Search Console
  5. Test multi-currency — use a VPN to verify pricing displays correctly for each target market
  6. Performance audit — run Lighthouse and Web Vitals checks from multiple Asian locations using WebPageTest's global test agents
  7. Monitor API rate limits — Shopify's Storefront API uses a cost-based throttling system. According to Shopify's API rate limits documentation, each app gets a bucket of 1000 cost points that refills at 100 points per second for standard plans

DNS Cutover

Point your domain to your new hosting provider. If you're on Vercel:

  1. Add your domain in the Vercel dashboard
  2. Update your DNS A/CNAME records
  3. Vercel handles SSL provisioning automatically

Keep your Shopify store active — it still powers your checkout, admin, and backend. You're only moving where the frontend is served from.

What Are Common Pitfalls and How Do You Troubleshoot Them?

API Rate Limiting

Symptom: Intermittent 429 errors or slow responses during traffic spikes.

Fix: Implement request caching aggressively. Use Next.js ISR (Incremental Static Regeneration) or fetch with next: { revalidate: 60 } to cache Storefront API responses. For product pages, a 60-second revalidation window means you hit the API once per minute per page, not once per visitor.

Cart State Persistence

Symptom: Users lose their cart when navigating between pages or returning to the site.

Fix: Store the cartId in a cookie (not localStorage) so it persists across sessions and works with server-side rendering. Use js-cookie or Next.js server actions to manage this.

Checkout Domain Mismatch

Symptom: Customers see a jarring transition from your custom domain to checkout.shopify.com.

Fix: On Shopify Plus, you can configure a custom checkout domain. Without Plus, this redirect is unavoidable but can be smoothed with consistent branding in Shopify's checkout customization settings.

Image Optimization

Symptom: Product images load slowly despite fast page rendering.

Fix: Shopify's CDN supports dynamic image resizing via URL parameters. Append _400x400 or use the width and height parameters in the Storefront API image URLs. Combine with Next.js <Image> component for automatic format negotiation and lazy loading.

1// Shopify CDN image resizing
2const optimizedUrl = `${originalUrl}&width=800&height=800`;

Ready to Transform Your Ecommerce Operations?

Branch8 specializes in ecommerce platform implementation and AI-powered automation solutions. Contact us today to discuss your ecommerce automation strategy.

What Does This Cost and How Long Does It Take?

Timelines and budgets vary significantly, but here are realistic ranges based on our project history across APAC:

  • Simple catalog (under 500 SKUs, single market): 6–10 weeks, USD $25,000–$50,000
  • Mid-complexity (500–5,000 SKUs, 2–3 markets, headless CMS integration): 10–16 weeks, USD $50,000–$120,000
  • Enterprise (5,000+ SKUs, 5+ markets, custom checkout, multiple integrations): 16–24 weeks, USD $120,000–$300,000+

These ranges include discovery, design, development, QA, and launch support. According to Statista's 2024 global e-commerce data, APAC represents over 60% of global e-commerce sales, which makes the investment in a performant, localized headless storefront particularly justifiable for brands targeting this region.

One honest trade-off: ongoing maintenance costs for a headless store are higher than a standard Shopify theme. You're responsible for frontend hosting, build pipelines, and keeping your API integration current with Shopify's quarterly API version releases. Budget an additional 15–20% of the initial build cost annually for maintenance and updates.

If you're considering a headless migration for your Shopify store — especially one serving multiple Asian markets — Branch8's engineering teams across Hong Kong, Vietnam, and Singapore have delivered headless builds on Next.js, Hydrogen, and Nuxt for retail, fashion, and D2C brands. Get in touch with our e-commerce team to discuss your migration scope and timeline.

Sources

FAQ

No, the Storefront API is available on all Shopify plans. However, Shopify Plus provides higher API rate limits, Checkout Extensibility for customizing the checkout experience, and multi-currency through Shopify Markets — all of which are important for production headless stores serving multiple markets.