NShop
Multi-tenancy

Tenants and domains

Subdomain routing, custom domains, and how the platform picks the right tenant per request.

Every store has a tenant slug — a short, URL-safe identifier like acme or bistro. The slug determines which data the request sees.

Subdomains

By default, each tenant gets a subdomain of the platform domain:

  • acme.shop.example → tenant acme
  • bistro.shop.example → tenant bistro

The middleware reads the Host header, strips the platform domain suffix, and writes the leading subdomain into the x-tenant header.

Custom domains

A tenant can point its own domain (e.g. acmeshop.com) at the platform. DNS to NShop, configure the custom domain in the tenant settings, and the platform resolves the domain to the tenant the same way as subdomains.

Local development

localhost doesn't have subdomains by default. NShop's middleware falls back to a tenant cookie if the subdomain can't be parsed, and falls back further to NEXT_PUBLIC_DEFAULT_TENANT. To work with real subdomains locally, add 127.0.0.1 acme.localhost bistro.localhost to your hosts file.

Country and currency

Each tenant has a home country (ISO-2, e.g. NL, IN) and a currency (EUR or INR), chosen when the tenant is created. Because Stripe ties a connected account's settlement currency to its country, these two must agree — INR with country IN, EUR with an EU country. See Payments → Currency for the full rules and how to switch an existing store.

Why no environment variable per tenant

Tenants are data, not deployments. Adding a new tenant is a Firestore write — /tenants/{slug} — not a redeploy. The same Cloud Run service and the same Cloud Functions serve every tenant.

On this page