Skip to content

Configuration

Full reference for chart/values.yaml, grouped by area. See Installation for how these combine into the three auth modes and the NebariApp integration.

KeyDefaultDescription
image.repositoryghcr.io/nebari-dev/nebari-framesImage repository.
image.tag""Image tag. Empty defaults to the chart appVersion.
image.pullPolicyIfNotPresentImage pull policy.
KeyDefaultDescription
replicaCount1Pod replicas. SQLite is single-writer - do not raise this.
KeyDefaultDescription
persistence.enabledtrueUse a PersistentVolumeClaim for the database. If false, storage is ephemeral and data is lost on pod restart.
persistence.mountPath/dataMount path for the data volume.
persistence.dbFilenebari-frames.dbSQLite filename under the mount path.
persistence.size1GiPVC size.
persistence.storageClass""StorageClass for the PVC. Empty uses the cluster default; set explicitly in production.
persistence.accessModeReadWriteOncePVC access mode.

The app ships with built-in Nebari branding (title, logos, favicon, theme colors) and needs no configuration. Operators can rebrand it without rebuilding the image: the backend serves a runtime configuration document at /config.json, and the SPA applies it before it mounts (title, favicon, theme CSS variables) and in the header and sign-in screens (logo).

KeyDefaultDescription
branding.title""Browser-tab title, also used as the logo’s alt text. Empty keeps Nebari Frames.
branding.logoUrl""Header and sign-in logo (light mode / default). Absolute http(s) URL, root-relative path, or base64 data: image URI.
branding.logoUrlDark""Dark-mode logo. Falls back to logoUrl, then the built-in dark wordmark.
branding.faviconUrl""Favicon URL.
branding.theme.light{}Theme token overrides for light mode (see below).
branding.theme.dark{}Theme token overrides for dark mode.

Every field is optional, and each one falls back to its built-in default independently, so an unbranded install renders exactly as it does without this block - the chart doesn’t even create the ConfigMap.

Supported theme tokens: primary, primaryForeground, primaryHover, background, foreground, card, cardForeground, secondary, secondaryForeground, muted, mutedForeground, accent, accentForeground, border, ring, radius, headerBackground, headerBorder, headerForeground, headerActionHover. Each is applied as the kebab-case CSS custom property (primaryForeground--primary-foreground).

primaryHover (button and badge hover/active) and ring (focus rings) are derived from primary when you don’t set them, so overriding primary alone keeps hover and focus states on-brand instead of flashing Nebari magenta. Set them explicitly only to pin a specific shade.

Token keys are written to CSS as-is - no allow-list is enforced when the chart renders the document or when the SPA applies it - so any other token the SPA defines can technically be set. Only the tokens listed above are supported.

Set branding in values. The chart renders the document into the <release>-nebari-frames-config ConfigMap and mounts it into the pod at /etc/nebari-frames/config/config.json:

branding:
title: "Acme Frames"
logoUrl: "https://cdn.acme.example/logo.svg"
logoUrlDark: "https://cdn.acme.example/logo-dark.svg"
faviconUrl: "https://cdn.acme.example/favicon.svg"
theme:
light:
primary: "oklch(55% 0.19 250)"
primaryForeground: "#ffffff"
dark:
primary: "oklch(62% 0.21 250)"

A branding-only helm upgrade rolls the pod automatically: the pod template carries a checksum of the rendered ConfigMap, and the app reads the document once at startup.

Running the image (or the binary) directly, branding resolves per field, highest first:

  1. BRANDING_* environment variables:

    Env varField
    BRANDING_TITLEtitle
    BRANDING_LOGO_URLlogoUrl
    BRANDING_LOGO_URL_DARKlogoUrlDark
    BRANDING_FAVICON_URLfaviconUrl
    BRANDING_THEMEtheme (raw JSON, e.g. '{"light":{"primary":"#0066cc"},"dark":{}}')
  2. The JSON document at BRANDING_CONFIG_FILE (what the chart mounts).

  3. Built-in Nebari defaults for anything still unset.

Terminal window
docker run -p 8080:8080 \
-e FRAMES_DEV_MODE=true \
-e BRANDING_TITLE="Acme Frames" \
-e BRANDING_LOGO_URL=https://cdn.acme.example/logo.svg \
ghcr.io/nebari-dev/nebari-frames

Branding never blocks startup: an unreadable config file or invalid BRANDING_THEME JSON is logged as a warning and skipped, and every other field still applies.

Theme values are validated in the browser before they are applied: any value containing CSS-injection characters (;, {, }, <, >, quotes, backslash, url(, expression(, javascript:) is dropped instead of injected into the stylesheet. Logo and favicon URLs are restricted to http(s) URLs, root-relative paths, and base64-encoded data: image URIs. A cross-origin logo or favicon host is added to the app’s Content-Security-Policy img-src automatically - only the hosts that branding actually configures.

KeyDefaultDescription
seed.orgSlug""Slug for the seeded organization.
seed.orgDisplayName""Display name for the seeded organization.
seed.adminEmail""Email of the first admin, reconciled to their OIDC subject on first login.

Auth mode is selected fail-closed (mirrors the backend’s own startup check):

nebariapp.enabled && nebariapp.auth.enabled -> OIDC env from the operator-provisioned secret
else auth.devMode == true -> FRAMES_DEV_MODE=true (no auth)
else -> auth.oidc.* (self-managed OIDC)
KeyDefaultDescription
auth.devModefalseWhen true (and NebariApp auth is off), disables auth and uses a fixed dev identity. Local use only.
auth.oidc.issuerUrl""OIDC issuer URL for self-managed auth.
auth.oidc.clientId""OIDC client id for the SPA.
auth.oidc.deviceClientId""OIDC client id for the device-code flow (CLI login).
KeyDefaultDescription
nebariapp.enabledfalseCreate a NebariApp so the nebari-operator provisions routing, TLS, and OIDC.
nebariapp.hostname""Hostname the operator routes to the app.
nebariapp.gatewaypublicGateway the operator attaches the route to.
nebariapp.routing.routes[{pathPrefix: /, pathType: PathPrefix}]Routes the operator creates the HTTPRoute from. Without this the operator reports RoutingNotConfigured and the hostname is unreachable.
nebariapp.routing.tls.enabledtrueWhether the operator provisions a certificate for the hostname. Without this the operator reports TLSDisabled.
nebariapp.landingPage.enabledtrueShow a tile on the Nebari landing page.
nebariapp.landingPage.displayNameFramesTile display name.
nebariapp.landingPage.descriptionReusable context Frames for AI assistants, with a remote MCP endpoint.Tile description.
nebariapp.landingPage.categoryPlatformTile category.
nebariapp.auth.enabledtrueWhen true, the operator provisions OIDC clients and the app uses them (see Auth modes above).
nebariapp.auth.scopes[openid, profile, email]OIDC scopes requested.
KeyDefaultDescription
mcp.enabledtrueMount the /mcp endpoint when a public URL is derivable.
mcp.publicUrl""Override the MCP public URL. Defaults to https://<nebariapp.hostname> when nebariapp.enabled is true.