How to Configure Feature Flags in Apache Superset: Enabling and Disabling Experimental Functionality
Apache Superset controls experimental and optional functionality through a three-layer feature flag system defined in superset/config.py and managed by FeatureFlagManager, allowing static configuration, environment variables, and dynamic per-request evaluation.
Apache Superset uses feature flags to gate experimental features, beta visualizations, and legacy systems that are being deprecated. When you configure feature flags in Superset, you modify boolean switches that the application checks at runtime to determine which code paths to execute. The flag system is implemented across three distinct configuration layers that merge together when the Flask application initializes.
Understanding the Feature Flag Architecture
The Superset feature flag system operates through a hierarchical merge of three distinct layers defined in superset/config.py and processed by superset/utils/feature_flag_manager.py.
Default Configuration Layer
The baseline feature flags are defined in superset/config.py within the DEFAULT_FEATURE_FLAGS dictionary (lines 539-604). These flags are grouped by lifecycle status—development, testing, stable, and deprecated—and ship with every Superset installation. This dictionary represents the factory defaults that apply unless explicitly overridden.
User Override Layer
Custom configurations belong in superset_config.py (located on your PYTHONPATH) within a FEATURE_FLAGS dictionary (lines 842-844 in superset/config.py). When the Flask app initializes, the FeatureFlagManager merges these values on top of the defaults using Python's dict.update() method. Any flag defined here replaces the corresponding default for your entire deployment.
Dynamic Evaluation Layer
For advanced use cases, superset/config.py supports two optional callable hooks (lines 848-864):
GET_FEATURE_FLAGS_FUNC: Receives the entire merged flag dictionary and returns a modified copyIS_FEATURE_ENABLED_FUNC: Receives a single flag name and default value, returning a boolean
These functions enable per-request, per-user, or progressive rollout logic by intercepting flag queries at runtime.
How to Configure Feature Flags in Superset
You can configure feature flags through static configuration files, environment variables, or dynamic functions depending on your deployment requirements.
Static Configuration via superset_config.py
Create or modify superset_config.py in your Python path to override specific flags:
# /path/to/your/superset_config.py
FEATURE_FLAGS = {
# Enable the new Table-V2 (AG-Grid) visualization
"AG_GRID_TABLE_ENABLED": True,
# Turn off the legacy tagging system
"TAGGING_SYSTEM": False,
}
This file is automatically imported at the end of superset/config.py, and your FEATURE_FLAGS dictionary updates the defaults before the application starts serving requests.
Environment Variable Overrides
Superset automatically parses environment variables matching the pattern SUPERSET_FEATURE_<FLAG_NAME> as booleans during configuration loading (lines 528-535 in superset/config.py). This approach is ideal for containerized deployments:
export SUPERSET_FEATURE_AG_GRID_TABLE_ENABLED=true
export SUPERSET_FEATURE_TAGGING_SYSTEM=false
These values are injected into DEFAULT_FEATURE_FLAGS at startup, providing a declarative way to toggle features without modifying Python files.
Dynamic Rollouts with Custom Functions
For percentage-based rollouts or user-specific features, implement GET_FEATURE_FLAGS_FUNC in superset_config.py:
# superset_config.py
from flask import g
def GET_FEATURE_FLAGS_FUNC(all_flags):
"""
Enable ALERTS_ATTACH_REPORTS only for beta-test users.
"""
if getattr(g, "user", None) and g.user.username.startswith("beta_"):
all_flags["ALERTS_ATTACH_REPORTS"] = True
return all_flags
The FeatureFlagManager passes a deep copy of the merged dictionary to this function, ensuring your mutations affect only the current request context.
Alternatively, use IS_FEATURE_ENABLED_FUNC for per-flag logic without evaluating the entire dictionary:
# superset_config.py
def IS_FEATURE_ENABLED_FUNC(name, default):
# Enable SQLLAB_BACKEND_PERSISTENCE for internal users only
if name == "SQLLAB_BACKEND_PERSISTENCE":
return getattr(g, "user", None) and g.user.is_internal
return default
Core Implementation Details
The FeatureFlagManager class in superset/utils/feature_flag_manager.py (lines 22-59) handles the merging logic during application initialization:
# Inside FeatureFlagManager.init_app()
self._feature_flags = app.config["DEFAULT_FEATURE_FLAGS"] # defaults
self._feature_flags.update(app.config["FEATURE_FLAGS"]) # user overrides
When is_feature_enabled() is called, the manager first checks for IS_FEATURE_ENABLED_FUNC. If defined, it invokes the callable with the flag name and default value. Otherwise, it consults the merged dictionary. For get_feature_flags(), the manager invokes GET_FEATURE_FLAGS_FUNC if present, passing a deep copy of the current flag state to prevent accidental global modifications.
The merge order is immutable: defaults → environment variables → static overrides → dynamic functions. This hierarchy ensures that explicit code configuration takes precedence over environment settings, while dynamic functions have the final say for the current request context.
Summary
- Three-layer system: Superset feature flags merge from
DEFAULT_FEATURE_FLAGS(defaults),FEATURE_FLAGS(static overrides), and optional callable functions (dynamic evaluation). - Configuration location: Define static overrides in
superset_config.pyon yourPYTHONPATH, referenced insuperset/config.pylines 842-844. - Environment support: Set
SUPERSET_FEATURE_<FLAG_NAME>variables for containerized deployments without code changes. - Dynamic control: Implement
GET_FEATURE_FLAGS_FUNCorIS_FEATURE_ENABLED_FUNCinsuperset_config.pyfor per-user or progressive rollout logic. - Manager implementation: The
FeatureFlagManagerinsuperset/utils/feature_flag_manager.pycaches merged flags per request and handles deep copies to isolate dynamic modifications.
Frequently Asked Questions
How do I check if a feature flag is enabled in Superset code?
Query the flag using is_feature_enabled() from the feature flag manager or import the utility function. According to superset/utils/feature_flag_manager.py, this method checks for IS_FEATURE_ENABLED_FUNC first, then falls back to the merged dictionary containing defaults and your superset_config.py overrides.
Can I enable feature flags for specific users only?
Yes. Define GET_FEATURE_FLAGS_FUNC or IS_FEATURE_ENABLED_FUNC in your superset_config.py to inspect the Flask g.user object. As shown in the dynamic evaluation examples, you can conditionally enable flags based on username prefixes, roles, or custom user attributes before returning the flag dictionary or boolean value.
What is the difference between DEFAULT_FEATURE_FLAGS and FEATURE_FLAGS?
DEFAULT_FEATURE_FLAGS is the dictionary defined in superset/config.py (lines 539-604) containing Superset's factory settings grouped by lifecycle status. FEATURE_FLAGS is the empty dictionary in the same file (lines 842-844) that you populate in your custom superset_config.py to override those defaults. The FeatureFlagManager updates the defaults with your overrides during initialization.
Do environment variables override superset_config.py settings?
No. The merge order places environment variables between defaults and static configuration. Environment variables matching SUPERSET_FEATURE_* are parsed into DEFAULT_FEATURE_FLAGS during config loading (lines 528-535), but values explicitly set in your superset_config.py FEATURE_FLAGS dictionary take precedence. Dynamic functions evaluated at request time have the final authority.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →