Build Guide
How to Build an E-Commerce Store
A custom e-commerce store built with Next.js and Stripe outperforms Shopify on speed and SEO — and costs $0/month to run at small scale.
E-commerce combines auth, payments, inventory, search, and email automation. Master it and you have the building blocks of any transactional business on the internet.
Data model
The core tables you'll need before writing any UI.
Build order
The sequence that minimises rewrites — build in this order.
Product catalogue
Build a product listing page with image, name, price, and an "Add to Cart" button. Use Next.js SSG for product pages — fast loads and good SEO. Fetch product data from Supabase at build time.
Shopping cart
Store the cart as a JSON array in a cookie or localStorage: [{productId, variantId, quantity}]. Add a cart sidebar that slides in on add. Show item count in the header. Persist across page navigations.
Stripe Checkout
On checkout click, POST the cart to /api/checkout. Create a Stripe Checkout Session with line items mapped from your cart. Redirect the user to the Stripe-hosted checkout page. Handle success and cancel redirects.
Webhook for order confirmation
Create a /api/stripe/webhook route. Verify the Stripe signature. On checkout.session.completed: create an Order row in your DB, decrement inventory, send a confirmation email via Resend.
Order history for customers
Add a /orders page that shows a customer's order history when they enter their email. Look up orders by email (no account required for small stores). Show order status, items, and total.
Admin panel
Build a simple /admin route (protected by a secret cookie or Clerk). Show all orders with status. Add buttons to update order status (shipped, delivered). Show low-inventory alerts.
Search and filtering
Add a search input that filters products by name on the listing page. Add category filters and a price range slider. For large catalogues, move to server-side search with Supabase full-text search or Algolia.
Done when
Observable behaviors that confirm V1 is complete — verify each one before you ship.
- ✓
Customer adds items, checks out with Stripe test card 4242..., and receives a confirmation email
- ✓
Inventory decrements correctly — buying the last item sets stock to 0
- ✓
Two simultaneous purchases of the last item result in exactly one succeeding
- ✓
Admin panel shows the new order within 60 seconds of the Stripe webhook firing
- ✓
Store opens with 5 seeded products — catalogue is never empty on first visit
First Run Requirement
Seed 5 demo products (T-shirt, Mug, Sticker Pack, Hoodie, Cap) with images and inventory of 10 each. Store opens with a populated catalogue — no manual product creation needed.
Build it with AI — Architect Prompt
Paste this into Claude, Cursor, Windsurf, or any AI coding tool. It includes the full context of this guide — data model, build order, done conditions, and pitfalls — so the AI starts with everything it needs.
<context>
App: E-Commerce Store
Difficulty: Intermediate
Estimated build time: 1–2 weeks
Tech stack (intermediate): Next.js + Stripe + Supabase + Cloudinary (images) — custom store, free at small scale
Data model:
Product: id, name, slug, description, price, compare_at_price, images[], inventory_count, category_id, published
ProductVariant: id, product_id, sku, size, color, price, inventory_count
Order: id, customer_email, status (pending/paid/shipped/delivered/refunded), subtotal, shipping, tax, total, stripe_payment_intent, created_at
OrderItem: id, order_id, product_id, variant_id, quantity, unit_price
Cart: session_id (cookie), items[] — stored in a cookie or localStorage, not DB
FIRST RUN REQUIREMENT:
Seed 5 demo products (T-shirt, Mug, Sticker Pack, Hoodie, Cap) with images and inventory of 10 each. Store opens with a populated catalogue — no manual product creation needed.
DONE WHEN — verify each before marking V1 complete:
□ Customer adds items, checks out with Stripe test card 4242..., and receives a confirmation email
□ Inventory decrements correctly — buying the last item sets stock to 0
□ Two simultaneous purchases of the last item result in exactly one succeeding
□ Admin panel shows the new order within 60 seconds of the Stripe webhook firing
□ Store opens with 5 seeded products — catalogue is never empty on first visit
Recommended build order:
1. Define API contract + schema + seed data (always first)
2. Product catalogue — Build a product listing page with image, name, price, and an "Add to Cart" button. Use Next.js SSG for product pages — fast loads and good SEO. Fetch product data from Supabase at build time.
3. Shopping cart — Store the cart as a JSON array in a cookie or localStorage: [{productId, variantId, quantity}]. Add a cart sidebar that slides in on add. Show item count in the header. Persist across page navigations.
4. Stripe Checkout — On checkout click, POST the cart to /api/checkout. Create a Stripe Checkout Session with line items mapped from your cart. Redirect the user to the Stripe-hosted checkout page. Handle success and cancel redirects.
5. Webhook for order confirmation — Create a /api/stripe/webhook route. Verify the Stripe signature. On checkout.session.completed: create an Order row in your DB, decrement inventory, send a confirmation email via Resend.
6. Order history for customers — Add a /orders page that shows a customer's order history when they enter their email. Look up orders by email (no account required for small stores). Show order status, items, and total.
7. Admin panel — Build a simple /admin route (protected by a secret cookie or Clerk). Show all orders with status. Add buttons to update order status (shipped, delivered). Show low-inventory alerts.
8. Search and filtering — Add a search input that filters products by name on the listing page. Add category filters and a price range slider. For large catalogues, move to server-side search with Supabase full-text search or Algolia.
9. End-to-end verification — walk every Done When condition above (always last)
Known pitfalls to avoid:
- Fulfilling orders without verifying payment — never trust the success redirect URL to confirm payment. Only fulfil orders after receiving the checkout.session.completed webhook from Stripe.
- Not handling inventory concurrency — two users might buy the last item simultaneously. Use a database transaction with a check: UPDATE products SET inventory = inventory - 1 WHERE inventory > 0 AND id = ?. Check the row count to confirm it succeeded.
- Storing prices in the frontend cart — always recalculate prices server-side before creating the Stripe session. A user can modify their localStorage cart to change prices.
</context>
<role>
You are a Senior Full-Stack Engineer and product architect who has shipped production E-Commerce Stores before. You know exactly where developers get stuck and how to structure the project to avoid rewrites.
</role>
<task id="step-1-clarify">
Before writing any code or spec, ask me 3–5 clarifying questions that will meaningfully change the architecture. Focus on: scale expectations, auth requirements, platform (web / mobile / both), must-have vs nice-to-have features for the MVP, and any hard constraints (budget, deadline, existing infrastructure).
<example>
BAD: "What tech stack do you want to use?" — too broad, doesn't change architecture decisions.
GOOD: "Do you need real-time sync across devices, or is single-device with periodic refresh acceptable? This decides whether we use WebSockets or simple REST polling and significantly affects infrastructure complexity."
</example>
⚠️ Do NOT start planning or writing code until I answer. Present the questions, then stop and wait.
</task>
<task id="step-2-architect">
After I answer your questions, produce the following in order:
1. TECHNICAL SPECIFICATION
- System architecture using → to show data and event flow
- Core data model (refer to data model in <context>)
- API contract — list ALL routes with request/response shapes BEFORE any implementation
WHY: agreeing on contracts first prevents rewrites when frontend and backend shapes diverge
- External APIs and integration points
2. MVP PLAN in three phases:
SETUP ✦ Step 1 (always): API contract + schema migration + seed data
Done when: schema is migrated, seed script runs, app starts with demo data, zero manual setup.
CORE FEATURES — build in this exact order:
2. Product catalogue
3. Shopping cart
4. Stripe Checkout
5. Webhook for order confirmation
6. Order history for customers
7. Admin panel
8. Search and filtering
DONE WHEN — one observable condition per feature:
□ Customer adds items, checks out with Stripe test card 4242..., and receives a confirmation email
□ Inventory decrements correctly — buying the last item sets stock to 0
□ Two simultaneous purchases of the last item result in exactly one succeeding
□ Admin panel shows the new order within 60 seconds of the Stripe webhook firing
□ Store opens with 5 seeded products — catalogue is never empty on first visit
STRETCH GOALS — post-launch additions that are explicitly out of V1 scope.
3. BLOCKER ANALYSIS
Flag: API rate limits, auth complexity, scope risks, cold-start problems, top 2–3 failure modes.
FIRST RUN REQUIREMENT: Seed 5 demo products (T-shirt, Mug, Sticker Pack, Hoodie, Cap) with images and inventory of 10 each. Store opens with a populated catalogue — no manual product creation needed.
✓ Done when: app launches with seed data and the full user journey works without any manual setup.
<self_check>
Before presenting your output, verify:
□ Every answer I gave to clarifying questions is reflected in the spec
□ Step 1 is ALWAYS: API contract + schema + seed — never UI first
□ Done When criteria are observable user behaviors, not internal states
□ The plan is realistic for one person to ship within 1–2 weeks
□ All known pitfalls from <context> are addressed in the spec
</self_check>
</task>
<task id="step-2.5-agents-md">
Generate an AGENTS.md file at the project root. This file is read automatically by Claude Code, Cursor, Windsurf, and all major AI coding tools at the start of every session.
Include:
- Project overview (2–3 sentences)
- Tech stack with exact version numbers
- Folder structure with one-line descriptions per directory
- Key architectural decisions and the WHY behind each
- Coding conventions: camelCase components, kebab-case files, max 200 lines per file, one concern per file
- Available commands: dev, build, test, lint, db:migrate, db:seed
- MVP scope boundaries — features explicitly out of V1
Note in the file: "Cursor users: symlink .cursorrules → AGENTS.md. Claude Code users: symlink CLAUDE.md → AGENTS.md."
</task>
<task id="step-3-implement">
Implement the full project in the exact order from step 2. For each step:
- Write complete code (no placeholders or TODOs)
- Confirm the step works before moving to the next
<constraints>
- Step 1 is ALWAYS: define all API routes + TypeScript request/response interfaces + run schema migration
WHY: agreeing on contracts before writing a single component prevents shape mismatches that require rewrites
- Final step is ALWAYS: start the app and walk every Done When condition from <context> end-to-end
WHY: a spec that passes unit tests but breaks the core user journey is not done
- Max 200 lines per file. WHY: every file must fit in one AI context window for complete reasoning
- One concern per file. WHY: mixing auth logic into API routes makes it impossible to reuse — extract to lib/auth.ts
- TypeScript strict mode, no `any` types. WHY: catches data shape mismatches at compile time, not in production
- All database queries in server components or API routes only. WHY: keeps credentials server-side
- All environment variables documented in .env.example. WHY: next developer sets up in under 5 minutes
</constraints>
</task>How to use this prompt
- 1.Copy the prompt above
- 2.Open Claude, Cursor (Cmd+L), or Windsurf
- 3.Paste the prompt and send — the AI will ask 3–5 clarifying questions
- 4.Answer the questions, then it generates your full project spec
- 5.Continue in the same session to implement step by step
Common mistakes
What trips up most developers building this for the first time.
Fulfilling orders without verifying payment — never trust the success redirect URL to confirm payment. Only fulfil orders after receiving the checkout.session.completed webhook from Stripe.
Not handling inventory concurrency — two users might buy the last item simultaneously. Use a database transaction with a check: UPDATE products SET inventory = inventory - 1 WHERE inventory > 0 AND id = ?. Check the row count to confirm it succeeded.
Storing prices in the frontend cart — always recalculate prices server-side before creating the Stripe session. A user can modify their localStorage cart to change prices.
Recommended tech stack
Pick the level that matches your experience.
Shopify — fastest path to a working store, $29/month, zero dev work
Next.js + Stripe + Supabase + Cloudinary (images) — custom store, free at small scale
Next.js + Stripe + Medusa.js (headless commerce) + Algolia (search)
Take it further — related ideas
Each comes with revenue math, a full build guide, and a prompt to paste into Claude or Cursor.