We're building a multi-tenant B2B app on Next.js (App Router + Turbopack). We need to split it into a core + optional features, where each feature can be turned on/off per tenant from an admin panel via API (no redeploy) and tenants ideally shouldn't download code for features they don't have.
Hard constraint: it has to stay one deployment on DigitalOcean App Platform (one build, one container). No multi-app / droplet fleet.
What we've ruled out so far:
- Module Federation — effectively dead under App Router + Turbopack.
- Vercel Microfrontends / Remote Components — need multiple deployments + Vercel's platform, and don't actually solve per-tenant gating anyway (they split by team/route, not by tenant entitlement).
So we're leaning toward keeping it in-app:
- next/dynamic for code-splitting each feature into its own chunk
- a static plugin registry + slot/fill pattern so core never imports a feature directly
- server-side route denial (real 404) for tenants that don't own a feature
- reusing our existing tenant-config flags + policy guards for the runtime gating
Roughly 8–12 features would become "plugins," the rest stays core.
Questions for anyone who's done this:
Did you keep per-tenant feature toggling in a single app, or did you actually split deployments? Any regrets?
Any gotchas with dynamic Redux reducer injection / lazy slices per feature?
Is the "code-split but still in the build" reality good enough, or did stakeholders push for true isolation?
Better patterns I'm missing?
Appreciate any war stories. Thanks!