Use Cases

A Practical Guide to Building an E-Commerce Site with Claude Code

A practical guide to building an e-commerce site using Claude Code with real-world code examples.

Using Claude Code to Build an E-Commerce Site

An e-commerce site needs a lot of features: product management, cart, checkout, inventory, and order management. With Claude Code, you can efficiently build all of these with a consistent design.

Product Data Model

> Build an e-commerce site with Next.js.
> Include product listing, product detail, cart, and checkout pages,
> integrate Stripe payments, and include inventory management.
// src/types/product.ts
export interface Product {
  id: string;
  name: string;
  slug: string;
  description: string;
  price: number;
  compareAtPrice?: number;
  images: string[];
  category: string;
  variants: ProductVariant[];
  stock: number;
  isActive: boolean;
}

export interface ProductVariant {
  id: string;
  name: string;       // e.g., "Size M / Blue"
  sku: string;
  price: number;
  stock: number;
  attributes: Record<string, string>;
}

export interface CartItem {
  productId: string;
  variantId?: string;
  quantity: number;
  price: number;
}

Cart Implementation

// src/stores/cart-store.ts
import { create } from 'zustand';
import { persist } from 'zustand/middleware';

interface CartState {
  items: CartItem[];
  addItem: (item: CartItem) => void;
  removeItem: (productId: string) => void;
  updateQuantity: (productId: string, quantity: number) => void;
  clearCart: () => void;
  totalPrice: () => number;
  totalItems: () => number;
}

export const useCartStore = create<CartState>()(
  persist(
    (set, get) => ({
      items: [],
      addItem: (item) =>
        set((state) => {
          const existing = state.items.find(
            (i) => i.productId === item.productId && i.variantId === item.variantId
          );
          if (existing) {
            return {
              items: state.items.map((i) =>
                i.productId === item.productId
                  ? { ...i, quantity: i.quantity + item.quantity }
                  : i
              ),
            };
          }
          return { items: [...state.items, item] };
        }),
      removeItem: (productId) =>
        set((state) => ({
          items: state.items.filter((i) => i.productId !== productId),
        })),
      updateQuantity: (productId, quantity) =>
        set((state) => ({
          items: state.items.map((i) =>
            i.productId === productId ? { ...i, quantity } : i
          ),
        })),
      clearCart: () => set({ items: [] }),
      totalPrice: () => get().items.reduce((sum, i) => sum + i.price * i.quantity, 0),
      totalItems: () => get().items.reduce((sum, i) => sum + i.quantity, 0),
    }),
    { name: 'cart-storage' }
  )
);

Checkout API

// src/app/api/checkout/route.ts
import { NextRequest, NextResponse } from 'next/server';
import Stripe from 'stripe';

const stripe = new Stripe(process.env.STRIPE_SECRET_KEY!);

export async function POST(request: NextRequest) {
  const { items } = await request.json();

  // Stock check
  for (const item of items) {
    const product = await getProduct(item.productId);
    if (!product || product.stock < item.quantity) {
      return NextResponse.json(
        { error: `${product?.name || 'Product'} is out of stock` },
        { status: 400 }
      );
    }
  }

  const session = await stripe.checkout.sessions.create({
    mode: 'payment',
    payment_method_types: ['card'],
    line_items: items.map((item: CartItem) => ({
      price_data: {
        currency: 'usd',
        product_data: { name: item.productId },
        unit_amount: item.price,
      },
      quantity: item.quantity,
    })),
    success_url: `${process.env.APP_URL}/order/success?session_id={CHECKOUT_SESSION_ID}`,
    cancel_url: `${process.env.APP_URL}/cart`,
    shipping_address_collection: {
      allowed_countries: ['US', 'CA'],
    },
  });

  return NextResponse.json({ url: session.url });
}

Product Card Component

// src/components/ProductCard.tsx
import Image from 'next/image';
import Link from 'next/link';
import { Product } from '@/types/product';

export function ProductCard({ product }: { product: Product }) {
  const discount = product.compareAtPrice
    ? Math.round((1 - product.price / product.compareAtPrice) * 100)
    : 0;

  return (
    <Link href={`/products/${product.slug}`} className="group">
      <div className="relative aspect-square overflow-hidden rounded-lg">
        <Image
          src={product.images[0]}
          alt={product.name}
          fill
          className="object-cover group-hover:scale-105 transition-transform"
        />
        {discount > 0 && (
          <span className="absolute top-2 right-2 bg-red-500 text-white text-xs px-2 py-1 rounded">
            {discount}% OFF
          </span>
        )}
      </div>
      <h3 className="mt-2 font-medium">{product.name}</h3>
      <div className="flex items-center gap-2">
        <span className="text-lg font-bold">${product.price.toLocaleString()}</span>
        {product.compareAtPrice && (
          <span className="text-sm text-gray-400 line-through">
            ${product.compareAtPrice.toLocaleString()}
          </span>
        )}
      </div>
    </Link>
  );
}

Summary

With Claude Code, you can build out the complex feature set of an e-commerce site with consistent code in one coherent effort. For payment processing details, see the Stripe payment integration guide, and for state management patterns, see state management implementation.

The official Stripe documentation is also a great reference.

#Claude Code #e-commerce #Stripe #Next.js #TypeScript

Level up your Claude Code workflow

50 battle-tested prompt templates you can copy-paste into Claude Code right now.

Free

Free PDF: Claude Code Cheatsheet in 5 Minutes

Key commands, shortcuts, and prompt examples on a single printable page.

Download PDF
M

About the Author

Masa

Engineer obsessed with Claude Code. Runs claudecode-lab.com, a 10-language tech media with 2,000+ pages.