Building a Multi-Tenant CMS with Next.js and Hasura
How I built Unity Sites, a platform where one Next.js app serves hundreds of different portfolio sites, each with its own content and theme.
Multi-tenant architecture means one codebase, one deployment, and one database serving many different sites. Each tenant gets their own subdomain, theme, and content, but they share the underlying infrastructure.
The key insight for Unity Sites was putting the site context in the database rather than in separate deployments. When a request arrives for aric.unity.ws, middleware extracts the slug and queries Hasura for the site record. That record contains the theme ID, palette, and all settings.
Hasura makes this elegantly simple. Row-level security ensures tenants only see their own data. The GraphQL schema is the same for all tenants. The site_id filter is the only difference between what tenant A sees and what tenant B sees.
The theme system resolves at render time. Each theme is a set of React components (Layout, HomePage, PostPage, etc.) registered in a manifest. The site record stores a theme_id, and the app loads the matching component set. Adding a new theme means adding a folder with the right exports.
For local development, Next.js reads a _site query param as a fallback when not on a real subdomain. Combined with nSelf wildcard subdomains on localhost, every tenant is accessible without any /etc/hosts entries.