Skip to main content

Configuration Reference

Butler Portal uses Backstage's layered configuration system. Configuration is defined in YAML files and loaded at startup. You can override settings per environment using multiple config files.

Configuration Files

FilePurposeCommitted to Git
app-config.yamlBase configuration shared across all environmentsYes
app-config.local.yamlLocal development overrides (secrets, endpoints)No (gitignored)
app-config.production.yamlProduction-specific settingsDepends on deployment method

Backstage merges configuration files in order. Values in later files override earlier ones. Load additional config files with the --config flag:

yarn dev --config app-config.yaml --config app-config.local.yaml

App Configuration

Top-level application settings:

app:
title: Butler Portal
baseUrl: http://localhost:3000
FieldDescriptionDefault
app.titleApplication title shown in the browser tab and navbarBackstage
app.baseUrlPublic URL of the frontend applicationhttp://localhost:3000

Backend Configuration

Settings for the Backstage backend process:

backend:
baseUrl: http://localhost:7007
listen:
port: 7007
cors:
origin: http://localhost:3000
methods: [GET, HEAD, PATCH, POST, PUT, DELETE]
credentials: true
FieldDescriptionDefault
backend.baseUrlPublic URL of the backend APIhttp://localhost:7007
backend.listen.portPort the backend listens on7007
backend.cors.originAllowed CORS origin (set to frontend URL)http://localhost:3000

Database Configuration

PostgreSQL connection settings used by the Backstage catalog and the Keeper plugin:

backend:
database:
client: pg
connection:
host: localhost
port: 5432
user: butler
password: ${POSTGRES_PASSWORD}
FieldDescriptionDefault
backend.database.clientDatabase driver. Use pg for PostgreSQL, better-sqlite3 for SQLite (dev only).better-sqlite3
backend.database.connection.hostPostgreSQL server hostnamelocalhost
backend.database.connection.portPostgreSQL server port5432
backend.database.connection.userDatabase username
backend.database.connection.passwordDatabase password. Supports ${ENV_VAR} substitution.
tip

For local development without PostgreSQL, you can use SQLite by setting client: better-sqlite3. Keeper features that require PostgreSQL (such as full-text search) are unavailable in SQLite mode.

Butler Cluster Connection

Portal connects to the Butler management cluster using the Backstage Kubernetes plugin:

kubernetes:
clusterLocatorMethods:
- type: config
clusters:
- name: butler-mgmt
url: https://10.40.0.100:6443
authProvider: serviceAccount
serviceAccountToken: ${BUTLER_SA_TOKEN}
skipTLSVerify: false
caData: ${BUTLER_CA_DATA}
FieldDescriptionRequired
clusters[].nameDisplay name for the clusterYes
clusters[].urlKubernetes API server URLYes
clusters[].authProviderAuthentication method. Use serviceAccount for token-based auth.Yes
clusters[].serviceAccountTokenBearer token for the service accountYes (for serviceAccount auth)
clusters[].skipTLSVerifySkip TLS certificate verificationNo (default false)
clusters[].caDataBase64-encoded CA certificate for the clusterNo

The service account needs RBAC permissions to read and manage Butler CRDs. At minimum, it requires get, list, watch, create, update, and delete on workspaces, tenantclusters, teams, and related resources in the butler.butlerlabs.dev API group.

Authentication and Authorization

Guest Access (Development)

For local development, you can enable guest access:

auth:
providers:
guest:
dangerouslyAllowOutsideDevelopment: false

GitHub Authentication

auth:
providers:
github:
development:
clientId: ${GITHUB_CLIENT_ID}
clientSecret: ${GITHUB_CLIENT_SECRET}

OIDC Authentication

For production deployments with an external identity provider:

auth:
providers:
oidc:
development:
metadataUrl: https://your-idp.example.com/.well-known/openid-configuration
clientId: ${OIDC_CLIENT_ID}
clientSecret: ${OIDC_CLIENT_SECRET}
prompt: auto

Plugin Configuration

Chambers (Workspaces)

chambers:
defaultCluster: butler-mgmt
defaultNamespace: default
sshGateway:
host: ssh.butlerlabs.dev
port: 2222
editors:
- name: VS Code
urlTemplate: "vscode://vscode-remote/ssh-remote+{sshEndpoint}/{workDir}"
- name: JetBrains Gateway
urlTemplate: "jetbrains-gateway://connect#host={sshHost}&port={sshPort}&path={workDir}"
FieldDescriptionDefault
chambers.defaultClusterKubernetes cluster for workspace provisioning
chambers.defaultNamespaceDefault namespace for new workspacesdefault
chambers.sshGateway.hostSSH gateway hostname for workspace access
chambers.sshGateway.portSSH gateway port22
chambers.editorsList of editor integrations with URL templates[]

Keeper (Registry)

keeper:
storage:
type: database
approval:
requiredReviewers: 1
autoApprovePatches: true
FieldDescriptionDefault
keeper.storage.typeArtifact storage backend. database stores in PostgreSQL.database
keeper.approval.requiredReviewersNumber of approvals required to publish an artifact version1
keeper.approval.autoApprovePatchesAutomatically approve patch version bumpsfalse

Herald (Pipeline)

herald:
vector:
configDir: /etc/vector
defaultSources:
- kubernetes_logs
defaultSinks:
- console
FieldDescriptionDefault
herald.vector.configDirDirectory where generated Vector configs are written/etc/vector
herald.vector.defaultSourcesDefault Vector sources for new pipelines[]
herald.vector.defaultSinksDefault Vector sinks for new pipelines[]

Environment Variable Substitution

Backstage supports ${ENV_VAR} syntax in YAML config files. At startup, these references are replaced with the corresponding environment variable values. This is the recommended way to inject secrets:

export POSTGRES_PASSWORD=my-secret-password
export BUTLER_SA_TOKEN=eyJhbGci...
yarn dev

If a referenced environment variable is not set, the application fails to start with a configuration error.

See Also