How to structure features so auth, blog, docs, teams, webhooks, AI, and admin modules can be removed without leaving a broken app.
Most SaaS starters say they are modular.
The useful question is: what happens when you remove a module?
If disabling a feature leaves dead navigation links, broken sitemap entries, missing imports, route handlers that still accept requests, or database tables nobody understands, the module was not really modular. It was just grouped in a folder.
Removable modules need boundaries.
A module usually appears in more places than its main page.
For example, a waitlist module may include:
If removal only deletes the public page, the product still leaks the feature elsewhere.
Feature flags hide behavior at runtime.
They do not remove code.
That distinction matters. Runtime flags are useful for:
But if a buyer wants a smaller codebase, the setup tool also needs to delete files and update references.
A good starter supports both:
Next.js App Router route groups are useful for keeping surfaces understandable:
src/app/[locale]/
(marketing)/
(auth)/
(dashboard)/
admin/
That structure makes it clear which pages are public, protected, authentication-only, or platform admin.
It also lets you reason about SEO. Marketing pages are indexable. Auth, dashboard, and admin pages should be noindex and blocked where appropriate.
The hardest modules to remove are the ones that leak into shared files.
Common leak points:
navigation.ts.sitemap.ts.robots.ts.proxy.ts.If a module needs entries in those files, make the entries obvious and grouped. If a setup wizard removes the module, it should know exactly what to prune.
Disabled UI is not security.
If a module has API routes, those routes need their own gates:
The proxy can return 404 for disabled feature routes, but route handlers should still follow the same protected pattern. That keeps modules safe when moved, copied, or extended.
Module data should be easy to identify.
Good table names:
waitlist_entry.feature_request.audit_log.outgoing_webhook.workflow.Ambiguous table names make removal riskier. If the table name tells you the module, migration work is easier to review.
Useful tests include:
You do not need massive coverage for every module. You need enough tests to prevent obvious leaks.
Not every removable feature should be a plugin.
A simple waitlist page can be a module.
A CRM with pages, routes, hooks, schema, components, AI helpers, and install commands is a better plugin candidate.
Use plugins when the feature has its own lifecycle and customer value. Use modules when the feature is part of the core application shape.
For each module, document:
That list prevents "modular" from becoming marketing language.
Removable modules give buyers confidence.
They can start broad, then strip what they do not need. Or they can keep a larger operational surface without building it themselves.
The codebase stays understandable because module boundaries are explicit.
Codapult documents removable features in the modules overview, including routes, dependencies, and manual removal notes.