Skip to main content

Best Boilerplates for Marketplace Platforms 2026

·StarterPick Team
marketplacetwo-sidedstripe-connectsaas-boilerplatenextjs2026

Marketplaces Are One of the Hardest SaaS Categories

Two-sided marketplaces — platforms connecting buyers and sellers — have more moving parts than standard SaaS. You are not just building for one user type; you are building for two, with different needs, different dashboards, and a payment flow that splits revenue between your platform and each seller.

The complexity:

  • Stripe Connect for split payments (platform fee + seller payout)
  • Two onboarding flows (buyer vs seller, with seller identity verification)
  • Listings management (CRUD for seller inventory)
  • Reviews and reputation (trust infrastructure)
  • Messaging between parties (in-platform communication)
  • Dispute resolution (when things go wrong)
  • 1099 tax reporting (for US marketplaces paying sellers)

No standard SaaS boilerplate handles all of this. You combine a boilerplate with custom marketplace infrastructure.

TL;DR

Best starting points for marketplace platforms in 2026:

  1. Stripe Connect + Next.js + any SaaS boilerplate — The payment infrastructure is the critical piece. Stripe Connect handles split payments and seller onboarding.
  2. Sharetribe Flex — Hosted marketplace platform for service and rental marketplaces. Not a boilerplate — a platform.
  3. OpenSaaS + custom marketplace — Free SaaS foundation; build marketplace layers on top.
  4. Payload CMS + Stripe Connect — Content-driven marketplaces (digital products, courses).
  5. T3 Stack + Stripe Connect — Developer-controlled, TypeScript-first marketplace foundation.

Key Takeaways

  • Stripe Connect is required for any marketplace that splits payments — no alternative matches its compliance and onboarding UX
  • Stripe Connect has two modes: Express (fast onboarding, Stripe handles payouts) and Custom (full control, more compliance work)
  • Platform fee on Stripe Connect: take a percentage of each transaction via application_fee_amount
  • Seller verification (KYC/KYB) is handled by Stripe — one of the biggest time-savers
  • Digital product marketplaces (courses, templates) are simpler than service marketplaces (freelancers, rentals)
  • Most marketplaces start with manual matching and add automated matching later

Stripe Connect: The Core Infrastructure

Stripe Connect is the only payment infrastructure worth considering for two-sided marketplaces in 2026.

Setting Up Stripe Connect

import Stripe from 'stripe';

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

// Step 1: Create a connected account for a seller (Express mode):
export async function createSellerAccount(userId: string) {
  const account = await stripe.accounts.create({
    type: 'express',
    country: 'US',
    capabilities: {
      transfers: { requested: true },
      card_payments: { requested: true },
    },
  });

  // Save the Stripe account ID to your database:
  await db.user.update({
    where: { id: userId },
    data: { stripeAccountId: account.id },
  });

  return account.id;
}

// Step 2: Generate onboarding link for seller:
export async function getSellerOnboardingUrl(userId: string, returnUrl: string) {
  const user = await db.user.findUnique({ where: { id: userId } });
  if (!user?.stripeAccountId) throw new Error('No Stripe account');

  const link = await stripe.accountLinks.create({
    account: user.stripeAccountId,
    refresh_url: `${returnUrl}?error=true`,
    return_url: returnUrl,
    type: 'account_onboarding',
  });

  return link.url;
}

// Step 3: Check if seller is fully onboarded:
export async function isSellerOnboarded(stripeAccountId: string): Promise<boolean> {
  const account = await stripe.accounts.retrieve(stripeAccountId);
  return account.charges_enabled && account.payouts_enabled;
}

Processing a Transaction with Platform Fee

// When a buyer purchases from a seller:
export async function createMarketplacePayment(
  buyerId: string,
  sellerId: string,
  listingId: string,
  amountCents: number  // e.g., 5000 = $50.00
) {
  const seller = await db.user.findUnique({ where: { id: sellerId } });
  if (!seller?.stripeAccountId) throw new Error('Seller not connected');

  const platformFeeCents = Math.floor(amountCents * 0.10);  // 10% platform fee

  const paymentIntent = await stripe.paymentIntents.create({
    amount: amountCents,
    currency: 'usd',
    application_fee_amount: platformFeeCents,
    transfer_data: {
      destination: seller.stripeAccountId,
    },
    metadata: { buyerId, sellerId, listingId },
  });

  return paymentIntent.client_secret;
}

The buyer pays the full amount. Stripe routes amountCents - platformFeeCents to the seller and platformFeeCents to your platform. Stripe handles tax reporting (1099s for US sellers).


Listing Management

// Prisma schema for marketplace listings:
model Listing {
  id          String   @id @default(cuid())
  sellerId    String
  seller      User     @relation(fields: [sellerId], references: [id])
  title       String
  description String
  price       Int      // In cents
  category    String
  images      String[] // Array of CDN URLs
  status      ListingStatus @default(DRAFT)
  createdAt   DateTime @default(now())
  updatedAt   DateTime @updatedAt

  orders      Order[]
  reviews     Review[]
}

enum ListingStatus {
  DRAFT
  ACTIVE
  PAUSED
  SOLD
}

model Order {
  id            String      @id @default(cuid())
  listingId     String
  buyerId       String
  sellerId      String
  amountCents   Int
  platformFee   Int
  status        OrderStatus @default(PENDING)
  stripePaymentId String?
  createdAt     DateTime    @default(now())
}

model Review {
  id        String @id @default(cuid())
  listingId String
  buyerId   String
  rating    Int    // 1-5
  comment   String
  createdAt DateTime @default(now())
}

Seller Dashboard vs Buyer Dashboard

// Seller dashboard API routes:
// GET /api/seller/listings - their listings with analytics
// GET /api/seller/orders - orders for their listings
// GET /api/seller/payouts - payout history from Stripe
// GET /api/seller/earnings - revenue summary

// Seller payout history from Stripe:
export async function getSellerPayouts(stripeAccountId: string) {
  const payouts = await stripe.payouts.list(
    { limit: 20 },
    { stripeAccount: stripeAccountId }
  );
  return payouts.data;
}

// Buyer dashboard:
// GET /api/buyer/orders - their purchase history
// GET /api/buyer/reviews - reviews they have left

In-Platform Messaging

For service marketplaces where buyers and sellers need to communicate:

// Simple messaging schema:
model Conversation {
  id          String   @id @default(cuid())
  buyerId     String
  sellerId    String
  listingId   String
  createdAt   DateTime @default(now())
  messages    Message[]
}

model Message {
  id             String       @id @default(cuid())
  conversationId String
  conversation   Conversation @relation(fields: [conversationId], references: [id])
  senderId       String
  content        String
  createdAt      DateTime     @default(now())
  readAt         DateTime?
}

For real-time messaging, add Supabase Realtime subscriptions on the messages table filtered by conversation_id.


Platform Fee Structures

Fee ModelHow It WorksBest For
Percentage fee5-20% of each transactionMost marketplaces
Listing feeCharge sellers to listEtsy-style, high-volume items
Subscription + percentageMonthly fee + reduced %High-volume sellers
Flat fee per transaction$X per orderHigh-ticket items
FreemiumFree to list, % on salesBuilding initial supply

Stripe Connect handles all of these. The application_fee_amount parameter is the platform's cut per transaction.


Digital Product Marketplaces

Simpler than service marketplaces — no escrow, no disputes, instant delivery:

// Digital product delivery after payment:
export async function handleSuccessfulPayment(paymentIntentId: string) {
  const payment = await stripe.paymentIntents.retrieve(paymentIntentId);
  const { listingId, buyerId } = payment.metadata;

  const listing = await db.listing.findUnique({
    where: { id: listingId },
    select: { downloadUrl: true, sellerId: true },
  });

  // Create download token (expires in 24h):
  const token = await db.downloadToken.create({
    data: {
      listingId,
      buyerId,
      token: randomBytes(32).toString('hex'),
      expiresAt: new Date(Date.now() + 24 * 60 * 60 * 1000),
    },
  });

  // Send download link to buyer:
  await sendEmail({
    to: buyer.email,
    subject: 'Your purchase is ready',
    body: `Download your file: ${process.env.NEXT_PUBLIC_URL}/download/${token.token}`,
  });
}

Marketplace TypeStack
Digital productsPayload CMS + Stripe Connect + Next.js
Service marketplaceT3 Stack + Stripe Connect + messaging
Rental marketplaceSharetribe Flex (hosted) or custom
Freelancer platformOpenSaaS + Stripe Connect + Escrow
Course marketplaceShipFast + Stripe Connect + video (Mux)

Methodology

Based on publicly available information from Stripe Connect documentation, marketplace builder communities, and public examples as of March 2026.


Building a marketplace? StarterPick helps you find the right SaaS boilerplate foundation before you layer on marketplace-specific features.

Comments