You've heard the word "headless" thrown around in e-commerce circles, and maybe you've quietly wondered whether it's just another trend for developers at big companies with big budgets. It's not — and I say that as someone who first set up a headless storefront on a Saturday morning with a cup of coffee and a lot of browser tabs open.
The honest truth: if you can follow a recipe, you can wire up a Next.js front end to a commerce back end over a weekend. You won't need a dev agency, and you won't need to replatform your entire business. Let's walk through it step by step.
What "Headless" Actually Means for a Small Store
Traditional platforms bundle the storefront (what shoppers see) with the back end (inventory, orders, checkout) into one package. Headless commerce splits those two things apart. Your back end lives somewhere — a lightweight commerce API, an existing Shopify store, whatever — and your front end is a separate app you control completely.
Why does that matter to you? Three reasons:
- Speed. Next.js pre-renders pages at build time, so a product page that took 3.2 seconds on a theme-based store can drop to under 0.8 seconds. Google's Core Web Vitals reward that, and so do conversion rates — research from Portent puts the conversion rate for a 1-second page at 2.5× higher than a 5-second page.
- Flexibility. You're not fighting a theme editor to add a custom section. You write the component you need.
- Cost control. You pay for your commerce API (often free up to a few thousand SKUs) and a hosting platform. Vercel's hobby tier is free; their pro tier is $20/month. Compare that to $79–$299/month for mid-tier Shopify plans plus app fees.
None of that requires you to be a full-stack engineer. You need enough comfort with a terminal to run a few commands, and enough JavaScript to read an error message and Google it.
Picking Your Commerce Back End Before You Write a Line of Code
This is the decision most tutorials skip, and it's the one that bites people later. Your Next.js front end is just a React app — it fetches product data from somewhere. That "somewhere" is your commerce API, and you have real options:
- Medusa.js — open-source, self-hostable, free. Great if you want full control and don't mind managing a Node server (Railway.app makes this cheap at around $5/month).
- Shopify Storefront API — if you already have a Shopify store, you can keep it as a headless back end and build your own front end on top. Your existing products, orders, and checkout stay put.
- Crystallize — generous free tier (up to 1,000 SKUs), GraphQL-first, solid for content-heavy catalogs.
- Saleor — Python/Django-based, open-source, strong community.
For this walkthrough I'll use the Shopify Storefront API because most readers here already have a Shopify store or a free trial. The pattern translates to any of the others with minor changes.
The Weekend Plan: Hours, Not Days
Here's the realistic schedule I've used and seen work for store owners who aren't developers by trade.
Saturday morning (2–3 hours): scaffold and connect
Install Node.js (v18 or later) if you haven't already. Then:
npx create-next-app@latest my-storefront
cd my-storefront
npm install graphql-request
In your Shopify admin, go to Apps → Develop apps → Create an app. Give it a name, then under "Storefront API," enable unauthenticated_read_product_listings and unauthenticated_read_product_inventory. Grab the Storefront API access token — it's a public token, safe to use client-side.
Create a .env.local file in your project root:
NEXT_PUBLIC_SHOPIFY_STORE_DOMAIN=your-store.myshopify.com
NEXT_PUBLIC_SHOPIFY_STOREFRONT_TOKEN=your-token-here
Now create lib/shopify.js with a small helper:
import { GraphQLClient } from 'graphql-request';
const endpoint = `https://${process.env.NEXT_PUBLIC_SHOPIFY_STORE_DOMAIN}/api/2024-01/graphql.json`;
export const shopifyClient = new GraphQLClient(endpoint, {
headers: {
'X-Shopify-Storefront-Access-Token': process.env.NEXT_PUBLIC_SHOPIFY_STOREFRONT_TOKEN,
},
});
That's your connection. Everything else is just fetching data and rendering it.
Saturday afternoon (2–3 hours): product listing page
Create app/products/page.jsx. Write a query to pull your first 12 products:
import { shopifyClient } from '@/lib/shopify';
import { gql } from 'graphql-request';
const PRODUCTS_QUERY = gql`
query {
products(first: 12) {
edges {
node {
id
title
handle
priceRange {
minVariantPrice { amount currencyCode }
}
images(first: 1) {
edges { node { url altText } }
}
}
}
}
}
`;
export default async function ProductsPage() {
const data = await shopifyClient.request(PRODUCTS_QUERY);
const products = data.products.edges.map(e => e.node);
return (
<main>
<h1>Shop</h1>
<div style={{ display: 'grid', gridTemplateColumns: 'repeat(3, 1fr)', gap: '1rem' }}>
{products.map(p => (
<a key={p.id} href={`/products/${p.handle}`}>
<img src={p.images.edges[0]?.node.url} alt={p.images.edges[0]?.node.altText} width={300} />
<p>{p.title}</p>
<p>{p.priceRange.minVariantPrice.amount} {p.priceRange.minVariantPrice.currencyCode}</p>
</a>
))}
</div>
</main>
);
}
Run npm run dev, open localhost:3000/products, and you'll see your real Shopify products rendered in your own code. That moment never gets old.
Sunday (3–4 hours): individual product pages and checkout
Create app/products/[handle]/page.jsx. This is a dynamic route — Next.js uses the handle segment to fetch the right product.
For checkout, here's the key insight most tutorials bury: you don't rebuild Shopify's checkout. You use the Storefront API to create a cart, then redirect the shopper to Shopify's hosted checkout URL. That means PCI compliance, address validation, and payment processing stay Shopify's problem. Your job is just to pass the right line items.
The mutation looks like this:
mutation cartCreate($input: CartInput!) {
cartCreate(input: $input) {
cart {
id
checkoutUrl
}
}
}
Call it with the variant IDs and quantities, grab checkoutUrl, and redirect. Done. Shoppers land on a familiar, trusted checkout flow and you didn't have to build a payment form.
A Real Example: What Changed for a Candle Store
A store selling hand-poured soy candles — about 60 SKUs, $180K/year revenue — was on a Shopify theme that loaded in 4.1 seconds on mobile (measured with PageSpeed Insights). Their bounce rate on product pages was 67%.
They spent one weekend following roughly this process, using their existing Shopify back end with a new Next.js front end deployed on Vercel. Three weeks after launch:
- Mobile load time: 1.3 seconds (PageSpeed score jumped from 41 to 79)
- Bounce rate on product pages: dropped to 48%
- Monthly revenue: up ~$2,200 compared to the same period the prior year
Was the revenue lift entirely from speed? Probably not — they also rewrote their product descriptions that weekend. But the speed improvement alone was worth the two days of effort, and they're now running $20/month in hosting instead of $79 plus three apps.
Could you see similar numbers? That depends on your traffic and your current baseline, but if your PageSpeed score is below 60 on mobile, you're almost certainly leaving conversions on the table.
Three Things to Do Before You Go Live
Before you point your domain at the new storefront, check these off:
-
Add an
<Image>component from Next.js. The raw<img>tag I used above is fine for development, but Next.js'sImagecomponent handles lazy loading, automatic WebP conversion, and responsive sizing. Swapping it in takes about 10 minutes and noticeably improves your Largest Contentful Paint score. -
Set up
generateStaticParamsfor product pages. This tells Next.js to pre-render every product page at build time instead of on demand. For 60 SKUs, build time is under 30 seconds. Your pages load from a CDN edge node instead of a server, which is where that sub-1-second performance comes from. -
Test your checkout flow end to end with a real (small) purchase. Use a test product priced at $0.01, go through the whole flow, confirm the order appears in your Shopify admin. Don't skip this — it takes 5 minutes and saves you from finding out your cart mutation has a typo after you've launched.
Deploying in About 10 Minutes
Push your code to a GitHub repo (free), connect it to Vercel (free tier, takes 3 clicks), add your two environment variables in the Vercel dashboard, and deploy. Vercel automatically assigns you a .vercel.app URL you can share immediately.
When you're ready to go live, update your domain's DNS to point at Vercel. They walk you through it with a step-by-step UI — it's genuinely easier than most domain setups I've done.
If you'd rather self-host, Netlify works identically for Next.js static exports, and Coolify on a $6/month VPS gives you full control if that's your thing.
You're More Ready Than You Think
Headless commerce used to mean a six-figure agency project. Today it means a weekend, a free Vercel account, and the Shopify API you already have access to. The candle store example above wasn't run by a developer — it was run by someone who had never written a GraphQL query before that Saturday.
If your store's mobile speed score is sitting below 60, or you're paying for three Shopify apps just to get the layout you want, this weekend project is worth attempting. You can always keep your current theme live while you build — there's no risk to experimenting on a staging URL.
Your next step: open PageSpeed Insights right now, run your homepage on mobile, and write down your score. That number is your baseline. Two weekends from now, it could look very different.