Feature Flags Configuration
Control feature availability and gradual rollouts using feature flags in the Next.js Drizzle SaaS Kit.
Toggle application features on or off using environment variables - no code changes or redeployment required. Feature flags control everything from theme switching to account deletion to custom roles.
Feature flags are boolean (or numeric) settings that enable or disable specific functionality at runtime. In MakerKit, most flags derive automatically from your Account Mode, but you can override any flag via environment variables.
This page is part of the Configuration documentation.
How Feature Flags Work
Feature flags are defined with Zod validation in apps/web/config/feature-flags.config.ts:
const FeatureFlagsSchema = z.object({ enableAccountDeletion: z.boolean(), enableOrganizationDeletion: z.boolean(), enablePersonalAccount: z.boolean(), enableOrganizations: z.boolean(), enablePersonalAccountBilling: z.boolean(), enableOrganizationsBilling: z.boolean(), allowUserToCreateOrganization: z.boolean(), showAccountSwitcher: z.boolean(), enableThemeToggle: z.boolean(), enableVersionUpdater: z.boolean(), enableCustomRoles: z.boolean(), maxRolesPerOrganization: z.number().int().positive().optional(),});Use feature flags when: you want to enable/disable functionality without touching code, control features per environment, or gradually roll out new features.
Avoid feature flags when: the setting is static across all environments (use config files instead), or when the flag would require complex conditional logic throughout the codebase.
If unsure: default values work for most apps. Only override flags when you have a specific requirement.
Flag Reference
Account-Derived Flags
These flags are automatically set based on your NEXT_PUBLIC_ACCOUNT_MODE. Override only when you need non-standard behavior.
| Flag | Default (Hybrid) | Personal-Only | Orgs-Only | Purpose |
|---|---|---|---|---|
enableOrganizations | true | false | true | Show organization features |
enablePersonalAccount | true | true | false | Enable personal account context |
enablePersonalAccountBilling | false | true | false | Bill personal accounts |
enableOrganizationsBilling | true | false | true | Bill organizations |
showAccountSwitcher | true | false | true | Show account switcher UI |
allowUserToCreateOrganization | true | false | true | Allow org creation |
Independent Flags
These flags can be set regardless of account mode:
# ThemeNEXT_PUBLIC_ENABLE_THEME_TOGGLE=true# NotificationsNEXT_PUBLIC_ENABLE_VERSION_UPDATER=false# Roles and permissionsNEXT_PUBLIC_ENABLE_CUSTOM_ROLES=falseNEXT_PUBLIC_MAX_ROLES_PER_ORGANIZATION=10Flag Details
Theme Toggle
NEXT_PUBLIC_ENABLE_THEME_TOGGLE=trueWhen false, hides the theme switcher from the UI. Users are locked to whatever NEXT_PUBLIC_DEFAULT_THEME_MODE you set. Useful for branded apps with strict design guidelines.
Version Updater
NEXT_PUBLIC_ENABLE_VERSION_UPDATER=falseNEXT_PUBLIC_VERSION_UPDATER_REFETCH_INTERVAL_SECONDS=3600When true, periodically checks for new deployments and prompts users to reload. Useful for SPAs where users might have stale code. The interval controls how often to check (default: 1 hour).
Custom Roles
NEXT_PUBLIC_ENABLE_CUSTOM_ROLES=falseNEXT_PUBLIC_MAX_ROLES_PER_ORGANIZATION=10When true, organization admins can create custom roles beyond the defaults (owner, admin, member). The max limit prevents abuse. This is an advanced feature - most apps work fine with the default roles.
Organization Creation
NEXT_PUBLIC_ALLOW_USER_TO_CREATE_ORGANIZATION=trueWhen false in hybrid mode, users can only join existing organizations via invitations. Useful when you want to control organization provisioning through an admin flow or sales process.
Using Flags in Code
Access flags through the config object:
import { featureFlagsConfig } from '@config/feature-flags.config';// Check if organizations are enabledif (featureFlagsConfig.enableOrganizations) { // Show organization UI}// Check role limitsconst maxRoles = featureFlagsConfig.maxRolesPerOrganization ?? 10;The config is type-safe - TypeScript will catch invalid flag names.
Common Pitfalls
- Forgetting derived flags exist: If you set
NEXT_PUBLIC_ACCOUNT_MODE=personal-only, don't also setNEXT_PUBLIC_ENABLE_ORGANIZATIONS=true. The mode handles this automatically. - Enabling custom roles without testing: Custom roles add complexity to permission checks. Test thoroughly before enabling in production.
- Not restarting after flag changes: Environment variables are read at startup. Restart your dev server or redeploy after changes.
- Client/server mismatch:
NEXT_PUBLIC_flags are available on both client and server. Non-prefixed flags are server-only. Don't check server-only flags in client components.
Adding Custom Feature Flags
To add your own flags:
Add the flag to the Zod schema
Add the flag to the Zod schema in feature-flags.config.ts:
const FeatureFlagsSchema = z.object({ // ... existing flags enableBetaFeature: z.boolean(),});Set the default and environment variable mapping
Set the default and environment variable mapping in createFeatureFlags:
const enableBetaFeature = getBoolean( env('NEXT_PUBLIC_ENABLE_BETA_FEATURE'), false, // default value);Use the flag in your code
Use the flag in your code:
import { featureFlagsConfig } from '@config/feature-flags.config';if (featureFlagsConfig.enableBetaFeature) { // Beta feature code}