Superset Theming and Branding#
Superset's theming and branding system spans two layers: a Python-side configuration layer in superset_config.py and a frontend Ant Design token system. Since v6.0, logo customization has moved fully into the theme token system (THEME_DEFAULT/THEME_DARK), and the legacy APP_ICON config key is deprecated and no longer rendered by the frontend .
Theme Configuration: THEME_DEFAULT and THEME_DARK#
The primary entry point for theming is the THEME_DEFAULT and THEME_DARK config keys in superset_config.py. These map to the backend THEME config key, which follows the Ant Design theme structure. You can use the Ant Design theme editor to generate token values. Example:
THEME_DEFAULT = {
"token": {
"colorPrimary": "#2893B3",
"brandLogoUrl": "/static/assets/images/my-logo.svg",
"brandLogoAlt": "My Company",
"brandLogoHref": "/",
"brandLogoHeight": "24px",
"brandLogoMargin": "18px",
},
}
THEME_DARK = {
"algorithm": "dark",
"token": {
"colorPrimary": "#4d9aff",
"brandLogoUrl": "/static/assets/images/my-logo-dark.svg",
},
}
How it flows to the frontend:
The THEME value is included in the bootstrap data sent from the backend to the browser on every page load. In RootContextProviders.tsx, if common.theme is non-empty, themeObject.setConfig(common.theme) is called immediately before React mounts .
Token resolution in Theme.tsx: the Theme.setConfig() method merges user tokens over built-in defaults (colors, fonts, brand logo tokens), then calls Ant Design's getDesignToken() to resolve the full AntD token set. Only tokens in the allowedAntdTokens allowlist (222 tokens) are exposed on SupersetTheme.
Built-in brand token defaults :
| Token | Default |
|---|---|
brandLogoUrl | /static/assets/images/superset-logo-horiz.png |
brandLogoAlt | Apache Superset |
brandLogoHref | / |
brandLogoHeight | 24px |
brandLogoMargin | 18px |
Logo rendering in the navbar: Menu.tsx checks theme.brandLogoUrl first; if set, it renders the image using those theme tokens . If not set, it falls back to the legacy brand.icon value from bootstrap data for backward compatibility — this fallback path is explicitly marked for deprecation in the code .
Dark mode toggle is gated by two feature flags :
THEME_ENABLE_DARK_THEME_SWITCH— adds a navbar switch for users (off by default)THEME_ALLOW_THEME_EDITOR_BETA— exposes a JSON theme editor modal (off by default)
Favicon Customization#
Favicons are configured separately via the FAVICONS list in superset_config.py:
FAVICONS = [
{"href": "/static/assets/images/favicon.png"},
{"href": "/static/assets/images/favicon-16x16.png", "sizes": "16x16", "type": "image/png"},
]
Each entry supports href (required), sizes, type, and rel attributes.
Legacy Branding Keys (Still Active in v6)#
These config keys are still defined in config.py and some remain active in v6 :
| Key | Default | Purpose |
|---|---|---|
APP_NAME | "Superset" | Application title |
APP_ICON | /static/assets/images/superset-logo-horiz.png | Deprecated — ignored by frontend |
LOGO_TARGET_PATH | None | Where clicking the logo navigates (None → /superset/welcome) |
LOGO_TOOLTIP | "" | Tooltip on logo hover |
LOGO_RIGHT_TEXT | "" | Text to the right of the logo |
Static Asset Serving: STATIC_ASSETS_PREFIX and the Manifest#
STATIC_ASSETS_PREFIX#
STATIC_ASSETS_PREFIX prepends a string to all static asset URLs rendered in Jinja2 templates. Default is "" (empty). Use cases:
- CDN hosting: set to
https://cdn.example.comto serve assets from a CDN - Sub-path deployment: when running at a non-root path via
SUPERSET_APP_ROOT, the prefix is auto-set to the app root if not explicitly configured
The value is included in bootstrap data and injected into Jinja2 templates via the UIManifestProcessor context processor as assets_prefix.
Manifest-Driven Asset Loading#
UIManifestProcessor reads superset/static/assets/manifest.json (produced by the frontend build) and provides js_manifest(bundle) and css_manifest(bundle) functions to all Jinja2 templates. In debug mode, the manifest is re-parsed on every request to support hot-reloading.
The asset_bundle.html partial macro combines these:
{% for entry in js_manifest(filename) %}
<script src="{{ assets_prefix }}{{ entry }}" ...></script>
{% endfor %}
The manifest file lives at superset/static/assets/manifest.json and is generated by the webpack build. It will be absent until the frontend is built (or the Python package is installed).
Containerized Deployments#
In Docker/Kubernetes setups, branding assets (logos, favicons) must be placed where Superset can serve them. The typical approach is to mount a custom image into /app/superset/static/assets/images/ and reference it in THEME_DEFAULT or FAVICONS. If using a CDN or reverse proxy that rewrites paths, STATIC_ASSETS_PREFIX and/or SUPERSET_APP_ROOT (env var) handle path rewriting automatically.