Branding Customization#
Dify supports two separate branding customization surfaces: workspace-level logo replacement (gated by subscription/billing) and enterprise-level branding (application title, logos, favicon β gated by deployment edition). The two are independent of each other and use different resolution paths.
Feature Models#
FeatureModel (per-workspace features) carries:
can_replace_logo: bool = Falseβ controls whether the workspace can swap the web app logo
SystemFeatureModel (system-wide features) carries:
branding: BrandingModelβ enterprise-managed fields:application_title,login_page_logo,workspace_logo,favicon(all default empty)
Resolution Logic (FeatureService)#
FeatureService.get_features() populates can_replace_logo in a two-stage pipeline :
- Env override β
_fulfill_params_from_env()setsfeatures.can_replace_logo = dify_config.CAN_REPLACE_LOGO. This always runs first. - Billing override β When
DEPLOYMENT_EDITION == DeploymentEdition.CLOUD,_fulfill_params_from_billing_api()overwrites the value with the billing API response, if the field is present. Billing takes precedence over the env var.
FeatureService.get_system_features() populates enterprise branding :
system_features.branding.enabledis set toTrueonly whenDEPLOYMENT_EDITION == DeploymentEdition.ENTERPRISE- Enterprise branding fields (
applicationTitle,loginPageLogo,workspaceLogo,favicon) are then pulled fromEnterpriseService.get_info()via_fulfill_params_from_enterprise()
Environment Variables#
| Variable | Default | Defined in |
|---|---|---|
CAN_REPLACE_LOGO | False | EnterpriseFeatureConfig |
DEPLOYMENT_EDITION | DeploymentEdition.COMMUNITY | DeploymentConfig |
CAN_REPLACE_LOGO can be set directly as an env var for self-hosted deployments that want logo replacement without a billing integration. When DEPLOYMENT_EDITION == DeploymentEdition.CLOUD, the billing API response overrides this env var.
DEPLOYMENT_EDITION is an enum (DeploymentEdition.COMMUNITY, DeploymentEdition.ENTERPRISE, DeploymentEdition.CLOUD) that serves as the single source of truth for deployment edition and feature gating [api/configs/deploy/init.py]. It replaces the deprecated ENTERPRISE_ENABLED and BILLING_ENABLED flags.
Migration note:
ENTERPRISE_ENABLEDandBILLING_ENABLEDhave been deprecated and consolidated intoDEPLOYMENT_EDITIONas the single source of truth for edition-based feature gating. SetDEPLOYMENT_EDITION=ENTERPRISEfor enterprise deployments orDEPLOYMENT_EDITION=CLOUDfor cloud deployments with billing.
Version note: PR #38126 fixed
CAN_REPLACE_LOGOdefault fromTrueβFalse(previously set toTruein PR #37452). The current correct default isFalse.
Access Control & API#
The workspace_custom billing check in cloud_edition_billing_resource_check gates both the custom-config endpoint and logo upload: if features.can_replace_logo is falsy, the request is rejected with HTTP 403 .
Two console API endpoints handle workspace branding :
POST /workspaces/custom-configβ storesremove_webapp_brandandreplace_webapp_logoon theTenantmodel'scustom_config_dictPOST /workspaces/custom-config/webapp-logo/uploadβ accepts SVG or PNG files only; returns the uploaded file ID
Both endpoints are decorated with @cloud_edition_billing_resource_check("workspace_custom"), meaning they fail with 403 if can_replace_logo is False when DEPLOYMENT_EDITION == DeploymentEdition.CLOUD.
Summary of Gating#
| Feature | Gate | Enabled when |
|---|---|---|
Web app logo replacement (can_replace_logo) | Billing API or CAN_REPLACE_LOGO env var | Billing plan includes it (when DEPLOYMENT_EDITION == DeploymentEdition.CLOUD), or CAN_REPLACE_LOGO=true in env |
| Enterprise branding (title, logos, favicon) | DEPLOYMENT_EDITION == DeploymentEdition.ENTERPRISE | Enterprise license active |