0
0
NextjsHow-ToIntermediate · 4 min read

How to Create a Multi-Tenant App in Next.js: Step-by-Step Guide

To create a multi-tenant app in Next.js, use dynamic routing to capture tenant identifiers from URLs, then load tenant-specific data and settings based on that identifier. Manage tenant context globally and separate data storage per tenant to isolate their data securely.
📐

Syntax

Multi-tenant apps in Next.js rely on dynamic routes to identify tenants and context providers to share tenant info across components.

  • pages/[tenant]/index.js: Dynamic route capturing tenant ID.
  • getServerSideProps: Fetch tenant data on each request.
  • React Context: Provide tenant info globally.
javascript
export async function getServerSideProps(context) {
  const { tenant } = context.params;
  // Fetch tenant-specific data here
  return { props: { tenant } };
}

export default function TenantPage({ tenant }) {
  return <h1>Welcome to {tenant} tenant page</h1>;
}
Output
Welcome to [tenant] tenant page
💻

Example

This example shows a Next.js app with dynamic routing for tenants and a React context to share tenant info. It fetches tenant data on the server and displays a tenant-specific welcome message.

javascript
import { createContext, useContext } from 'react';

const TenantContext = createContext(null);

export async function getServerSideProps({ params }) {
  const { tenant } = params;
  // Simulate fetching tenant config
  const tenantConfig = { name: tenant, themeColor: tenant === 'blue' ? 'blue' : 'green' };
  return { props: { tenantConfig } };
}

export default function TenantPage({ tenantConfig }) {
  return (
    <TenantContext.Provider value={tenantConfig}>
      <TenantContent />
    </TenantContext.Provider>
  );
}

function TenantContent() {
  const tenant = useContext(TenantContext);
  return <div style={{ color: tenant.themeColor }}>
    <h1>Welcome to {tenant.name} tenant!</h1>
  </div>;
}
Output
Welcome to blue tenant! (text in blue color) or Welcome to green tenant! (text in green color)
⚠️

Common Pitfalls

Common mistakes include:

  • Not isolating tenant data properly, risking data leaks.
  • Hardcoding tenant info instead of using dynamic routes.
  • Failing to handle unknown tenants gracefully.
  • Not using context or global state, causing repeated tenant info fetching.

Always validate tenant IDs and separate tenant data in your database.

javascript
/* Wrong: Hardcoded tenant page without dynamic routing */
export default function Page() {
  return <h1>Welcome to tenant1</h1>;
}

/* Right: Use dynamic route and fetch tenant info */
export async function getServerSideProps({ params }) {
  const { tenant } = params;
  if (!['tenant1', 'tenant2'].includes(tenant)) {
    return { notFound: true };
  }
  return { props: { tenant } };
}

export default function TenantPage({ tenant }) {
  return <h1>Welcome to {tenant}</h1>;
}
Output
Welcome to tenant1 (or tenant2) or 404 page if tenant unknown
📊

Quick Reference

  • Use pages/[tenant]/index.js for tenant-specific routes.
  • Fetch tenant data in getServerSideProps or getStaticProps with fallback.
  • Use React Context to share tenant info across components.
  • Validate tenant IDs to avoid invalid access.
  • Separate tenant data in your database for security.

Key Takeaways

Use dynamic routes like [tenant] to capture tenant identifiers in URLs.
Fetch tenant-specific data on the server side to customize content per tenant.
Use React Context to provide tenant info globally within your app.
Always validate tenant IDs and handle unknown tenants gracefully.
Keep tenant data isolated in your database to ensure security.