How the Module System Works
A deep dive into Sentido's module system - enabling and disabling features at both the JavaScript and .NET layers.
By Carl Mills
One of the most requested features in app templates is the ability to ship a product and later enable new capabilities for specific customers - or switch them off globally until they're ready. Sentido's module system handles this elegantly across both layers of the stack.
What is a module?
A module is a named feature that can be switched on or off independently. Sentido ships with these modules:
| Module ID | Description |
|---|---|
| teams | Team management - invite members, assign roles |
| admin-panel | Admin UI - view and manage all users and tenants |
| ai | AI features placeholder |
| analytics | Analytics dashboard placeholder |
Enabling modules
In your .env file, set ENABLED_MODULES to a comma-separated list:
ENABLED_MODULES=teams,admin-panel
The JavaScript layer
In packages/config/modules.ts, isModuleEnabled(moduleId) reads NEXT_PUBLIC_ENABLED_MODULES at runtime. This means the client knows the module state too, which lets the sidebar render the correct navigation items.
Server components can gate content directly:
import { isModuleEnabled } from '@repo/config/modules'
if (!isModuleEnabled('teams')) {
return <p>Teams is not enabled for your plan.</p>
}
The .NET layer
The IModule interface marks each feature module. ENABLED_MODULES is read at startup and each module's endpoints are only registered if it's in the list. This means disabled modules add zero overhead - their routes simply don't exist.
Adding your own module
- Add the module ID to
packages/config/modules.ts - Create a .NET module class implementing
IModule - Add the
<ModuleGate>wrapper to any UI that should be hidden when disabled - Set
ENABLED_MODULESin your environment
That's it. No feature flags service required.