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 shows up in more places than its main page suggests. Take a waitlist feature: there's the public signup route, sure, but also an admin view, an API route, a database table, an email template, a navbar link, a footer link, a sitemap entry. Delete the public page and the feature is still there — just invisible until someone hits the API route directly or wonders why waitlist_entry is sitting in the schema.
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.
None of this needs to be exhaustive. It needs to be enough that "modular" describes the codebase instead of describing the marketing copy.
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.