HomeBuild Guides › Build a Marketplace
Advanced ⏱ 4-6 hours

Build a Marketplace

Create a two-sided marketplace with user auth, listings, and split payments

Next.js
Next.jsFramework
Supabase
SupabaseDatabase
Stripe
StripeSplit Payments
Vercel
VercelHosting
Clerk
ClerkAuthentication

What You'll Build

A working marketplace where sellers can list products, buyers can purchase, and payments automatically split between you (platform fee) and the seller.

Prerequisites

Architecture

Next.js handles the frontend and API layer. Clerk provides user authentication with role-based access (buyer vs seller). Supabase stores listings, orders, and user profiles. Stripe Connect handles payments - buyers pay, Stripe splits the funds between seller and your platform automatically.

Buyer → Next.js → Clerk (Auth) → Supabase (Listings/Orders) → Stripe Connect (Split Payment) → Seller gets paid

5 Steps

1
Clerk

Scaffold the Next.js app with Clerk

~15 min

Create a Next.js project and integrate Clerk for authentication.

  1. Create a new Next.js project: npx create-next-app@latest marketplace --typescript --tailwind --app
  2. Install Clerk: npm install @clerk/nextjs
  3. Create a Clerk application at clerk.com and get your API keys
  4. Add Clerk keys to .env.local
  5. Wrap your app with in the root layout
  6. Add Clerk middleware to protect routes
Terminal
npx create-next-app@latest marketplace --typescript --tailwind --app
cd marketplace
npm install @clerk/nextjs
.env.local
NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY=pk_...
CLERK_SECRET_KEY=sk_...
NEXT_PUBLIC_CLERK_SIGN_IN_URL=/sign-in
NEXT_PUBLIC_CLERK_SIGN_UP_URL=/sign-up
💡
Tip: Clerk gives you beautiful auth UI components out of the box. Use and components instead of building forms from scratch.
2
Supabase

Set up the Supabase database schema

~20 min

Create the database tables for listings, orders, and seller profiles.

  1. Create a Supabase project and install @supabase/supabase-js
  2. Create a sellers table (user_id, stripe_account_id, store_name, approved)
  3. Create a listings table (seller_id, title, description, price, images, status)
  4. Create an orders table (buyer_id, listing_id, amount, stripe_payment_id, status)
  5. Enable Row Level Security on all tables
  6. Write RLS policies: sellers can CRUD their own listings, buyers can read all active listings
Supabase SQL Editor
CREATE TABLE sellers (
  id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
  user_id TEXT UNIQUE NOT NULL,
  stripe_account_id TEXT,
  store_name TEXT NOT NULL,
  approved BOOLEAN DEFAULT false,
  created_at TIMESTAMPTZ DEFAULT now()
);

CREATE TABLE listings (
  id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
  seller_id UUID REFERENCES sellers(id),
  title TEXT NOT NULL,
  description TEXT,
  price INTEGER NOT NULL,
  images TEXT[],
  status TEXT DEFAULT 'active',
  created_at TIMESTAMPTZ DEFAULT now()
);

CREATE TABLE orders (
  id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
  buyer_id TEXT NOT NULL,
  listing_id UUID REFERENCES listings(id),
  amount INTEGER NOT NULL,
  stripe_payment_id TEXT,
  status TEXT DEFAULT 'pending',
  created_at TIMESTAMPTZ DEFAULT now()
);
💡
Tip: Store prices as integers (cents) to avoid floating-point issues. $19.99 = 1999.
3
Stripe

Set up Stripe Connect for split payments

~30 min

Enable Stripe Connect so sellers can receive payments with your platform taking a fee.

  1. Enable Connect in your Stripe Dashboard under Connect → Settings
  2. Choose "Express" onboarding (Stripe handles seller KYC)
  3. Install Stripe: npm install stripe
  4. Create an API route to generate seller onboarding links
  5. Create a webhook handler for account.updated events to track seller verification
  6. Set your platform fee percentage (e.g., 10%)
src/app/api/connect/onboard/route.ts
import Stripe from 'stripe'
import { NextResponse } from 'next/server'

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

export async function POST(req: Request) {
  const { sellerId } = await req.json()
  const account = await stripe.accounts.create({ type: 'express' })
  const link = await stripe.accountLinks.create({
    account: account.id,
    refresh_url: `${process.env.NEXT_PUBLIC_URL}/seller/onboard`,
    return_url: `${process.env.NEXT_PUBLIC_URL}/seller/dashboard`,
    type: 'account_onboarding'
  })
  // Save account.id to the seller's record in Supabase
  return NextResponse.json({ url: link.url })
}
💡
Tip: Start with Express accounts - they handle all the compliance and tax forms for your sellers.
⚠️
Warning: Stripe Connect requires your platform to be approved. Apply early as it can take a few business days.
4
Stripe

Build the marketplace checkout

~30 min

Create a checkout flow that splits payments between your platform and the seller.

  1. Create a checkout API route that creates a Stripe Checkout Session with payment_intent_data.transfer_data
  2. Set the application_fee_amount to your platform fee (e.g., 10% of the listing price)
  3. Set transfer_data.destination to the seller's Stripe Connect account ID
  4. Build a product detail page with a "Buy Now" button that calls your checkout API
  5. Create success and cancel pages for post-checkout redirects
src/app/api/checkout/route.ts
const session = await stripe.checkout.sessions.create({
  mode: 'payment',
  line_items: [{
    price_data: {
      currency: 'usd',
      product_data: { name: listing.title },
      unit_amount: listing.price
    },
    quantity: 1
  }],
  payment_intent_data: {
    application_fee_amount: Math.round(listing.price * 0.10),
    transfer_data: { destination: seller.stripe_account_id }
  },
  success_url: `${process.env.NEXT_PUBLIC_URL}/orders/{CHECKOUT_SESSION_ID}`,
  cancel_url: `${process.env.NEXT_PUBLIC_URL}/listings/${listing.id}`
})
💡
Tip: Test the entire flow with Stripe test mode before going live. Use the test card 4242 4242 4242 4242.
5
Vercel

Deploy to Vercel

~15 min

Deploy your marketplace with all environment variables configured.

  1. Push to GitHub and import into Vercel
  2. Add all environment variables (Clerk, Supabase, Stripe keys)
  3. Configure your Stripe webhook endpoint for production
  4. Test a full buyer flow: browse → buy → seller gets paid
  5. Test a full seller flow: onboard → list product → receive payment
💡
Tip: Set up Vercel preview deployments for PRs - test new features before they hit production.

🎉 You're Done!

A working marketplace where sellers can list products, buyers can purchase, and payments automatically split between you (platform fee) and the seller.

Done for you

Want this built for you?

Get a step-by-step checklist, setup order, and the exact config for every tool in this guide. Or let me build it for you.

Get the checklist → Want this built for you?