lkomar.pl
← Wszystkie notatki
Next.jsSanitymulti-tenantarchitecture

Building a multi-tenant Next.js app with one codebase

How I structured a reusable wedding-website boilerplate that deploys independently per client with zero code duplication.


title: Building a multi-tenant Next.js app with one codebase date: 2026-07 description: How I structured a reusable wedding-website boilerplate that deploys independently per client with zero code duplication. tags: [Next.js, Sanity, multi-tenant, architecture]

When I built the Wesele Platform, the core challenge was simple: I wanted one codebase, one Sanity schema definition, but the ability to spin up a fully branded, independently deployed website for each client: different domain, different content, different couple.

The shape of the problem

Most "multi-tenant" tutorials assume you're running one server with sub-domains routing to tenant-specific data. That's a database-centric model. What I needed was different: per-tenant deployment, where each site is its own Vercel project but shares 95% of the code.

Two-repo structure

I split the work into:

The client repo imports the boilerplate via a local symlink during development and as a git subtree in production. This keeps the boilerplate upgradeable without touching client-specific files.

What changes per deployment

The interesting design question is: what's data and what's config?

I settled on three layers:

  1. Sanity content: everything a couple edits, like the photo gallery, guest list messages, and event schedule
  2. Deployment config: set once at deploy time via env vars, like couple names, wedding date, and primary color
  3. i18n copy: translatable UI strings (button labels, section headings) that are shared but localizable

The env var approach turned out to be the right call. Vercel lets you set per-project environment variables, so NEXT_PUBLIC_COUPLE_NAMES="Marcin & Karolina" is all it takes to brand the hero section.

What I'd do differently

The Sanity Studio setup was the roughest part. I wanted each client to have their own Sanity project (separate content, separate access control), but the Studio is bundled into the Next.js app, so updating the Studio means redeploying. For the next client I'd extract the Studio into a standalone Sanity project and just point the Next.js app at the right projectId.


If you're building something similar (a reusable SaaS template, a white-label product, or a per-client static site), the key insight is to decide early which layer each concern lives in. It's hard to move things between layers once content is live.