Skip to main content

forgeportal.yaml Reference

ForgePortal is configured via a single YAML file (forgeportal.yaml at the project root) validated by Zod. Every value can be overridden by environment variables. This page documents each top-level section and its fields (type, default, description).

Docker Compose

The provided docker-compose.yml mounts forgeportal.yaml from the project root into the API and Worker containers automatically. Create yours from the example:

cp forgeportal.example.yaml forgeportal.yaml

If the file does not exist, containers start with schema defaults only.

Overview

The file has 12 top-level sections: db, server, auth, scm, discovery, migrations, docs, plugins, pluginPackages, scorecards, encryptionKey, ui. Omitted sections use schema defaults. Secrets (passwords, client secrets, tokens) should be set via env vars, not committed in the file.

Plugin dependency sync

After adding or removing packages in pluginPackages.packages, run pnpm forge:sync to automatically update apps/api/package.json and apps/ui/package.json. See the forge sync reference.


db

Database connection for PostgreSQL.

FieldTypeDefaultDescription
hoststringlocalhostDatabase host.
portnumber5432Database port.
databasestringforgeportalDatabase name.
userstringforgeDatabase user.
passwordstringforge_local_devDatabase password. Set via DB_PASSWORD in production.
maxPoolSizenumber20Maximum connections in the pool.

Example:

db:
host: postgres
port: 5432
database: forgeportal
user: forge
# password: set via DB_PASSWORD
maxPoolSize: 20

server

API server and logging.

FieldTypeDefaultDescription
portnumber4000Listen port.
hoststring0.0.0.0Bind address.
logLevelstringinfoOne of: debug, info, warn, error.
securityHeadersobjectOptional. csp: string for Content-Security-Policy (empty string to disable).

Example:

server:
port: 4000
host: 0.0.0.0
logLevel: info
# securityHeaders:
# csp: "default-src 'self'; ..."

auth

Authentication (OIDC) and session.

FieldTypeDefaultDescription
sessionSecretstringchange-me-forgeportal-session-secretMin 16 chars. Used to encrypt session; set via SESSION_SECRET in production.
oidcobject{}OIDC provider settings. See OIDC Setup.
oidc.issuerstring (URL)Discovery URL of the IdP. If empty, dev-mode bypass (no login).
oidc.clientIdstringOAuth2 client ID.
oidc.clientSecretstringNever put in file. Set via OIDC_CLIENT_SECRET.
oidc.redirectUristring (URL)Override redirect URI (default: http(s)://host:port/api/v1/auth/callback).
oidc.scopesstringopenid email profileSpace-separated scopes. Add groups for Keycloak/Okta.
oidc.groupsClaimstringJWT claim for groups/roles. Auto-detected if unset (e.g. groups, roles, realm_access.roles).
roleMappingobjectMap ForgePortal role → list of IDP group/role names. Keys: platform-admin, template-admin, team-admin, developer, viewer.

Example:

auth:
sessionSecret: change-me-in-production
oidc:
issuer: https://keycloak.example.com/realms/forgeportal
clientId: forgeportal
# clientSecret: env OIDC_CLIENT_SECRET
scopes: openid email profile groups
groupsClaim: groups
roleMapping:
platform-admin: ["forge-admins", "SRE"]
developer: ["engineers"]

scm

SCM providers (GitHub, GitLab). Used for discovery, webhooks, and actions. See SCM Providers.

FieldTypeDefaultDescription
github.tokenstringGitHub PAT. Prefer env.
github.appIdstringGitHub App ID (when using App auth).
github.privateKeyPathstringPath to App private key file.
github.webhookSecretstringWebhook secret for signature verification.
gitlab.tokenstringGitLab personal or project token.
gitlab.baseUrlstring (URL)https://gitlab.comGitLab API base (use for self-hosted).
gitlab.webhookSecretstringWebhook secret.

Example:

scm:
github:
# token: set via env
# appId: ...
# privateKeyPath: ...
# webhookSecret: ...
gitlab:
# token: set via env
baseUrl: https://gitlab.com

discovery

Catalog discovery (repo scan).

FieldTypeDefaultDescription
entityFilePathstringentity.yamlFile name (or path) to look for in each repo.
intervalMinutesnumber0Scheduled scan interval in minutes. 0 = disabled (manual only).
orgsarray[]List of { provider: github | gitlab, org: string, topic?: string }. org may be a GitHub organisation slug or personal username — the scanner detects user vs. org automatically.

Example:

discovery:
entityFilePath: entity.yaml
intervalMinutes: 60
orgs:
- provider: github
org: my-org
- provider: gitlab
org: my-group

migrations

Database migrations and seed.

FieldTypeDefaultDescription
dirstringtools/migrationDirectory containing SQL migrations.
runSeedbooleanfalseWhether to run the seed file after migrations.
seedFilestringtools/seed/seed_v1.sqlPath to seed SQL.

docs

Documentation indexing.

FieldTypeDefaultDescription
maxIndexFileSizeBytesnumber5242880 (5 MB)Max size in bytes for a single file to be indexed; larger files are skipped.

pluginPackages

List of npm packages to load as plugins at startup. Use forge sync to keep apps/api/package.json and apps/ui/package.json in sync with this list automatically.

FieldTypeDefaultDescription
packagesstring[][]Package names (e.g. @myorg/forge-plugin-pagerduty). Each must have a valid forgeportal-plugin.json.

Example:

pluginPackages:
packages:
- "@forgeportal/plugin-kubernetes"
- "@myorg/forge-plugin-pagerduty"

After editing this list, run:

pnpm forge:sync

plugins

Per-plugin configuration (enabled flag and non-secret config). Keys are plugin IDs (derived from package name, e.g. pagerduty, kubernetes).

Field (per plugin)TypeDefaultDescription
enabledbooleantrueWhether the plugin is active. Can be overridden in DB (plugin_overrides).
configobject{}Non-secret config key-value. Secrets must be set via env: FORGEPORTAL_PLUGIN_<ID>_<KEY>.

Example — generic:

plugins:
pagerduty:
enabled: true
config:
apiEndpoint: "https://api.pagerduty.com"
# apiToken: set via FORGEPORTAL_PLUGIN_PAGERDUTY_APITOKEN
slack-notify:
enabled: false
config:
defaultChannel: "#alerts"

Example — Kubernetes plugin:

plugins:
kubernetes:
enabled: true
config:
# JSON array of cluster objects (no tokens — use env vars)
clusters: '[{"name":"local","url":"https://kubernetes.docker.internal:6443","skipTLSVerify":true}]'
defaultNamespace: "default"

Cluster tokens are injected via environment variables:

# Pattern: FORGEPORTAL_PLUGIN_KUBERNETES_<CLUSTER_NAME_UPPERCASE>_TOKEN
FORGEPORTAL_PLUGIN_KUBERNETES_LOCAL_TOKEN=eyJhbGciOiJSUzI1NiIs...
FORGEPORTAL_PLUGIN_KUBERNETES_PRODUCTION_TOKEN=eyJhbGciOiJSUzI1NiIs...

See the Kubernetes Plugin docs for the full reference.


scorecards

Scorecard evaluation schedule.

FieldTypeDefaultDescription
evalIntervalHoursnumber24Interval in hours between bulk scorecard evaluations. Set to 0 to disable.

ui

UI branding and customization. All fields are optional — defaults to the standard ForgePortal look.

For a full walkthrough of each option (with examples, color suggestions, and best-practice tips) see the dedicated UI Customization guide.

FieldTypeDefaultDescription
portalNamestringForgePortalNavbar text and browser tab title. Max 80 chars.
logoUrlstring (URL)Replaces the portal name with an <img> in the navbar.
faviconUrlstring (URL)Browser tab favicon.
primaryColorstring#6366f1Navbar + brand accent color. Must be a 6-digit hex (e.g. #e11d48).
navLinksarray[]Up to 10 custom links pinned to the navbar. Each item: label (string), url (URL), icon (emoji, optional).
announcement.messagestringText for the dismissable banner shown above the navbar. Max 500 chars.
announcement.variantstringinfoBanner color style: info (blue), warning (amber), error (red).

Example:

ui:
portalName: "Acme Developer Portal"
logoUrl: "https://cdn.acme.com/logo-white.svg"
faviconUrl: "https://cdn.acme.com/favicon.ico"
primaryColor: "#e11d48"

navLinks:
- label: "Runbooks"
url: "https://wiki.acme.com/runbooks"
icon: "📖"
- label: "On-Call"
url: "https://app.pagerduty.com"
icon: "🔔"

announcement:
message: "🚧 Scheduled maintenance Saturday 02:00–04:00 UTC — catalog scans will be paused"
variant: "warning"
Dark mode

ForgePortal includes a built-in dark mode toggle (sun/moon icon) in the navbar. User preference is saved in localStorage and defaults to OS setting. No configuration required.


encryptionKey

Key used for encrypting sensitive data (e.g. stored secrets). Min 16 characters. Never commit a production value; set via ENCRYPTION_KEY.

FieldTypeDefaultDescription
(root) encryptionKeystringlocal-dev-key-change-in-prod-32chars!Encryption key for AES-256-GCM (e.g. admin-stored SCM secrets).

Full example (annotated)

# Database — override with DB_* env vars
db:
host: localhost
port: 5432
database: forgeportal
user: forge
# password: DB_PASSWORD

# API
server:
port: 4000
host: 0.0.0.0
logLevel: info

# Auth — set OIDC_* and SESSION_SECRET in production
auth:
sessionSecret: change-me
oidc: {}
# roleMapping: { "platform-admin": ["admins"], "developer": ["devs"] }

# SCM — set tokens via env or FORGEPORTAL_SCM__GITHUB__TOKEN
scm:
github: {}
gitlab: { baseUrl: https://gitlab.com }

# Discovery
discovery:
entityFilePath: entity.yaml
intervalMinutes: 0
orgs: []

# Migrations
migrations:
dir: tools/migration
runSeed: false
seedFile: tools/seed/seed_v1.sql

# Docs indexing
docs:
maxIndexFileSizeBytes: 5242880

# Plugins
pluginPackages:
packages: []
plugins: {}

# Scorecards
scorecards:
evalIntervalHours: 24

# Encryption — set ENCRYPTION_KEY in production
encryptionKey: local-dev-key-change-in-prod-32chars!

# UI Branding — all fields optional, full guide at /docs/configuration/ui-customization
# ui:
# portalName: "Acme Developer Portal"
# logoUrl: "https://cdn.acme.com/logo.svg"
# faviconUrl: "https://cdn.acme.com/fav.ico"
# primaryColor: "#e11d48"
# navLinks:
# - { label: "Runbooks", url: "https://wiki.acme.com", icon: "📖" }
# announcement:
# message: "🚧 Maintenance Saturday 02:00–04:00 UTC"
# variant: "warning"

For environment variable overrides, see Environment Variables.