← DeployCloud

Marketplace App Architecture Guide

A two-sided marketplace is really three apps wearing one trench coat: a supply-side onboarding flow, a demand-side discovery/checkout flow, and a trust-and-safety layer that mediates money and disputes between strangers. The hard part is rarely the UI — it is the state machine governing when funds move, who can cancel what, and how you prove what happened when someone complains.

Get the data model right first (users, listings, orders, payments, disputes as distinct entities with clear state transitions), then pick infrastructure that lets you deploy the API close to users while keeping payment logic in one auditable place. Most successful marketplaces run a monolith-first backend on a provider like Render, Railway, or a GCP/AWS managed container service, then push read-heavy catalog traffic to an edge cache (Cloudflare Workers + KV, or Vercel Edge) once scale demands it.

Core data model and state machines

Model five entities explicitly: User (with a role flag or separate Buyer/Seller profiles), Listing, Order, Transaction, and Dispute. Orders should move through an explicit state machine — created → paid_held → fulfilled → released → closed, with disputed and refunded as branch states. Store state transitions as an append-only ledger table, not just a status column, so you can reconstruct history for support and compliance. A Postgres database (AWS RDS, GCP Cloud SQL, DigitalOcean Managed Postgres, or Supabase) is the right default here — marketplaces need transactional integrity that document stores do not guarantee out of the box.

💬 Chat with our AI →

Payment escrow: build vs. buy

Almost no marketplace should build its own money-holding ledger from scratch — the compliance burden (money transmitter licensing) is real. Use a payments platform that supports marketplace/connected-account patterns: Stripe Connect (Standard/Express/Custom accounts, with Stripe holding funds and releasing on your trigger) is the most common choice; Adyen for Platforms and PayPal Commerce Platform are the main alternatives. Your backend calls the provider API to create a PaymentIntent with a destination charge, holds it in escrow, then triggers a transfer to the seller connected account on fulfillment confirmation. Run this logic in a single backend service (not scattered across edge functions) so you have one place to reason about idempotency keys and webhook retries.

💬 Chat with our AI →

Seller onboarding and KYC

Onboarding needs identity verification (KYC/KYB) before a seller can receive payouts. Stripe Connect hosted onboarding flow, Persona, or Onfido handle document capture and verification; your job is to store the verification status and gate listing-creation or payout endpoints behind it. Use webhooks (not polling) to update onboarding status, and queue background jobs (via AWS SQS, GCP Cloud Tasks, or a Redis-backed queue like BullMQ on Railway/Render) for anything that calls a third-party API, so a slow KYC provider never blocks your request thread.

💬 Chat with our AI →

Dispute handling and audit trail

Disputes need their own workflow, separate from the order state machine: opened → evidence_submitted → under_review → resolved. Store all evidence (messages, photos, tracking numbers) tied to the dispute ID in object storage — Cloudflare R2, AWS S3, or GCP Cloud Storage all work and R2 avoids egress fees if you are serving evidence back through a Worker. Log every admin action on a dispute to the same append-only ledger used for orders. If you integrate card-network disputes (chargebacks) via Stripe, mirror their dispute object IDs into your own table so support staff have one place to look, not two systems to cross-reference.

💬 Chat with our AI →

Where to deploy each piece

A pragmatic split: run the core API + payment/dispute logic on a container platform with persistent connections (AWS ECS/Fargate, GCP Cloud Run, DigitalOcean App Platform, or Render) since payment webhooks and Stripe SDKs assume a long-lived server process. Serve the public catalog/search pages through Vercel or Netlify with edge caching, or Cloudflare Pages + Workers if you want the cache and API gateway in the same platform. Keep search itself in a dedicated service (Algolia, Meilisearch, or Elasticsearch on managed hosting) rather than querying Postgres directly for full-text/faceted search at scale.

💬 Chat with our AI →

Frequently asked questions

Do I need a money transmitter license to run a marketplace?

Not if you use a payments platform like Stripe Connect, Adyen, or PayPal Commerce Platform in a managed model — they hold the license and the funds flow through their regulated entity. You take on that burden only if you build custody of funds yourself, which almost no early-stage marketplace should do.

Should disputes and orders share one database table?

No. Keep Orders and Disputes as separate entities with a foreign key relationship. This lets a dispute reference multiple order line items or messages without forcing your order state machine to model every possible complaint path.

Can I run the whole marketplace on serverless/edge functions?

You can for the catalog, search, and static pages, but the payment/escrow logic is easier to reason about on a traditional long-running backend (Cloud Run, Fargate, Render) because Stripe SDKs, webhook idempotency, and multi-step transactions are simpler outside a cold-start, short-timeout edge function.

What database should hold financial transaction records?

A relational database with ACID guarantees — Postgres (RDS, Cloud SQL, Supabase, or DigitalOcean Managed Databases) — not a NoSQL store. You need row-level transactions and foreign key integrity for money movement and audit trails.

💬 Chat with our AI →

💬 Chat with our AI →

Generate a blueprint free →

Explore the full desk on the home page →