Building a Multi-Tenant SaaS Platform with Next.js

Search for a command to run...

No comments yet. Be the first to comment.
Next.js continues to evolve as a robust full-stack framework for building web applications. Two of its groundbreaking features—Server Actions and React Server Components (RSC)—enable developers to write performant, maintainable, and scalable applicat...
If you’re building modern web applications, chances are you’ve needed a simple backend for tasks like storing form submissions, feedback requests, or lightweight data logs. Instead of spinning up a server or managing databases, what if you could just...

Real-time applications, such as chat apps, require instant data exchange between clients and servers. In this guide, we'll walk through integrating Socket.io with Next.js (App Router) to build a real-time chat application. 🚀 Why Use Socket.io with ...

Managing global state in a Next.js application can be tricky, but Redux Toolkit (RTK) makes it easier by reducing boilerplate and improving performance. In this guide, we’ll walk through integrating Redux Toolkit with Next.js to efficiently manage ap...

Firebase is a powerful backend-as-a-service platform that offers authentication, real-time databases, and hosting. Integrating Firebase with a Next.js application allows you to build scalable and serverless web applications with ease. Why Use Fireba...

Optimization in Next.js App

Multi-tenant SaaS (Software as a Service) platforms allow multiple clients (tenants) to share a single application while maintaining separation of their data and configurations. In this guide, we will explore how to build a multi-tenant SaaS platform using Next.js, leveraging its middleware and dynamic routing capabilities.
Each request must be associated with a specific tenant. This can be done through:
Subdomains (e.g., tenant1.example.com)
Path-based routing (e.g., example.com/tenant1)
Custom headers (e.g., X-Tenant-ID)
Ensure data isolation between tenants. This involves:
Separate database schemas or collections per tenant
Scoped configurations for themes, permissions, or features
Allow tenants to customize the application, such as uploading logos or changing colors, while sharing the same codebase.
Dynamic routing in Next.js enables tenant-specific pages. Let’s implement a path-based routing structure.
src
├── app
│ ├── [tenant]
│ │ ├── dashboard
│ │ │ └── page.tsx
│ │ ├── settings
│ │ │ └── page.tsx
│ ├── middleware.ts
In this structure:
[tenant] is a dynamic segment that matches tenant identifiers.
Pages like /[tenant]/dashboard and /[tenant]/settings serve tenant-specific content.
Create tenant-specific pages using dynamic segments:
import { useRouter } from 'next/navigation';
export default function DashboardPage() {
const router = useRouter();
const { tenant } = router.query;
return (
<div>
<h1>Welcome, {tenant}</h1>
<p>This is the dashboard for tenant: {tenant}</p>
</div>
);
}
Middleware in Next.js can intercept requests and perform tasks such as tenant identification and redirection.
Create a middleware.ts file in the app directory:
import { NextResponse } from 'next/server';
export function middleware(req) {
const url = req.nextUrl;
const tenant = url.pathname.split('/')[1];
if (!tenant) {
// Redirect to a generic landing page if no tenant is specified
return NextResponse.redirect(new URL('/landing', req.url));
}
// Add tenant to the request headers for downstream processing
req.headers.set('x-tenant-id', tenant);
return NextResponse.next();
}
export const config = {
matcher: '/:path*',
};
This middleware:
Extracts the tenant from the URL path.
Redirects users without a tenant to a landing page.
Adds the tenant identifier to the request headers for further use.
Single Database with Tenant ID: Add a tenantId field to each record.
Separate Databases or Schemas: Use a unique database or schema for each tenant.
Modify API calls to include tenant-specific filters:
export default async function handler(req, res) {
const tenantId = req.headers['x-tenant-id'];
// Fetch data scoped to the tenant
const data = await fetchDataForTenant(tenantId);
res.status(200).json(data);
}
Allow tenants to upload their own assets or set configurations.
const tenantThemes = {
tenant1: { primaryColor: '#ff0000', logo: '/logos/tenant1.png' },
tenant2: { primaryColor: '#0000ff', logo: '/logos/tenant2.png' },
};
import { useRouter } from 'next/router';
export default function Header() {
const router = useRouter();
const { tenant } = router.query;
const theme = tenantThemes[tenant] || tenantThemes['default'];
return (
<header style={{ backgroundColor: theme.primaryColor }}>
<img src={theme.logo} alt={`${tenant} logo`} />
</header>
);
}
Simplified Routing: Dynamic routing makes tenant-specific URLs easy to implement.
Built-In Middleware: Next.js middleware simplifies tenant identification and request handling.
Scalable Architecture: ISR and API routes support high traffic while maintaining performance.
Customizable UI: Tenant-specific branding and themes enhance the user experience.
Building a multi-tenant SaaS platform with Next.js is efficient and scalable. By leveraging middleware and dynamic routing, you can create tenant-specific experiences while maintaining a shared codebase. With proper database design and configuration management, you can ensure data isolation and customization for each tenant, paving the way for a robust and flexible SaaS application.