Spotify Backstage Meet LiteLLM for Corporate AI Governance A new Backstage plugin from @acarmisc provides a governance interface for LiteLLM proxy, enabling developers to manage virtual API keys and monitor AI model usage directly within Backstage 1.50+. The plugin includes frontend React components and a backend Express router, offering features such as KPI dashboards, key management, and model browsing, with configuration via environment variables like LITELLM_BASE_URL and LITELLM_MASTER_KEY. Backstage plugin for LiteLLM governance — enables developers to manage virtual API keys and monitor AI model usage directly from Backstage. This is a Backstage 1.50+ plugin providing a governance interface for LiteLLM proxy. It includes: Frontend : React components built with the New Frontend System @backstage/frontend-plugin-api Backend : Express router using the New Backend System @backstage/backend-plugin-api packages/plugin-litellm - Frontend @acarmisc/backstage-plugin-litellm packages/plugin-litellm-backend - Backend @acarmisc/backstage-plugin-litellm-backend The LiteLLMHomeWidget card surfaces the signed-in user's KPIs USD spent, tokens in/out, active key count alongside a daily-spend sparkline, with a Today / 7d / 30d period selector. The Overview tab is the default landing view. It shows the user's identity header with team chips and key health counters , four KPI tiles Total Spend, Total Requests, Success Rate, Total Tokens , and the Costs chart with per-model daily spend. The full-page version below shows the complete chart grid Daily Spend by Model, Daily Token Usage, Daily Requests, Daily Success Rate, Cumulative Spend vs Budget : Browse, edit, block, and revoke your virtual keys. Each row shows alias, key ID, creation/expiry dates, budget bar, TPM/RPM, and the models it can call. Mint a scoped key with its own budget, team binding, model list, and TPM/RPM caps. Failures e.g. duplicate alias surface inline with the upstream error. Browse every model the proxy exposes, with per-model input/output cost and max input/output token limits. The team filter scopes the list to the team the key will be bound to. A smaller variant of the home widget for surfaces that only need a one-click shortcut into the key-mint flow. This plugin is designed to be used within a Backstage monorepo . It uses workspace dependencies and requires the Backstage CLI to build. From your Backstage monorepo root: yarn add file:../backstage-govai/packages/plugin-litellm yarn add file:../backstage-govai/packages/plugin-litellm-backend Copy the packages directly into your Backstage plugins/ directory and add them to your workspace. Set these in your shell or deployment environment before starting Backstage. Backstage's config system supports ${ENV VAR} substitution in app-config.yaml : LITELLM BASE URL=http://litellm-proxy:4000 LiteLLM proxy URL LITELLM MASTER KEY=sk-... LiteLLM admin master key Add to app-config.yaml . All keys live under the litellm top-level namespace: litellm: Required — base URL of your LiteLLM proxy instance. @visibility backend baseUrl: ${LITELLM BASE URL} Optional — publicly reachable LiteLLM proxy URL, used to build ready-to-paste curl / OpenAI-SDK snippets in the "Key Generated" dialog. Falls back to baseUrl the internal URL when omitted. @visibility backend publicBaseUrl: https://llm-gw.example.com Required — LiteLLM master key for admin operations. Never exposed to the frontend marked @visibility secret . masterKey: ${LITELLM MASTER KEY} Optional — email domain appended to the Backstage user entity name to form the LiteLLM user id. When set, a user entity "user:default/john.doe" maps to "john.doe@example.com" in LiteLLM. Omit to use the bare entity name. @visibility backend userIdDomain: example.com optional Optional — autoprovisioning of LiteLLM users on first access. provisioning: Whether to automatically create a LiteLLM user when the Backstage user is not yet known to LiteLLM. Disabled by default. enabled: false default defaults: Max lifetime spend USD before the account is blocked. maxBudget: 10 default: 10 Spend-reset period after which the spend counter resets. Accepts LiteLLM duration strings: "30d", "7d", "1h", etc. budgetDuration: 30d default: "30d" LiteLLM model IDs the new user is allowed to call. An empty list means all models configured in the proxy are allowed. models: default: all models LiteLLM team IDs to enrol the new user in automatically. teams: default: no teams LiteLLM role assigned to every provisioned user. Valid values: proxy admin, proxy admin viewer, internal user, internal user viewer, team. userRole: internal user default: "internal user" Tokens per minute hard cap omit for no per-user limit . tpmLimit: 100000 Requests per minute hard cap omit for no per-user limit . rpmLimit: 1000 Arbitrary key-value metadata stored on the LiteLLM user record. metadata: cost centre: engineering Optional — role-based provisioning overrides. Evaluated in order; first matching group wins. Fields omitted here fall back to defaults above. roles: - group: group:default/ai-power-users Backstage group entity ref maxBudget: 100 budgetDuration: 30d models: - gpt-4o - claude-3-5-sonnet userRole: internal user Optional — controls for the "Generate New Key" form in the frontend. keyGeneration: Show the "Unlimited budget" checkbox. When false, a positive max budget is always required. allowUnlimitedBudget: false default Require a team to be selected before a key can be generated. Set to false to allow personal, team-less keys. teamRequired: true default Config key reference: | Key | Type | Required | Default | Description | |---|---|---|---|---| litellm.baseUrl | string | yes | — | LiteLLM proxy base URL | litellm.publicBaseUrl | string | no | — | Publicly reachable proxy URL for snippet generation | litellm.masterKey | string | yes | — | Admin master key @visibility secret | litellm.userIdDomain | string | no | — | Email domain for LiteLLM user IDs | litellm.provisioning.enabled | boolean | no | false | Enable autoprovisioning | litellm.provisioning.defaults.maxBudget | number | no | 10 | Max spend USD per reset period | litellm.provisioning.defaults.budgetDuration | string | no | "30d" | Spend-reset period | litellm.provisioning.defaults.models | string | no | | Allowed model IDs empty = all | litellm.provisioning.defaults.teams | string | no | | Team IDs to join on creation | litellm.provisioning.defaults.userRole | string | no | "internal user" | LiteLLM role | litellm.provisioning.defaults.tpmLimit | number | no | — | Tokens-per-minute cap | litellm.provisioning.defaults.rpmLimit | number | no | — | Requests-per-minute cap | litellm.provisioning.defaults.metadata | object | no | {} | Extra metadata on user record | litellm.provisioning.roles .group | string | yes | — | Backstage group entity ref | litellm.provisioning.roles .maxBudget | number | no | — | Overrides default for group | litellm.provisioning.roles .budgetDuration | string | no | — | Overrides default for group | litellm.provisioning.roles .models | string | no | — | Overrides default for group | litellm.provisioning.roles .teams | string | no | — | Overrides default for group | litellm.provisioning.roles .userRole | string | no | — | Overrides default for group | litellm.provisioning.roles .tpmLimit | number | no | — | Overrides default for group | litellm.provisioning.roles .rpmLimit | number | no | — | Overrides default for group | litellm.provisioning.roles .metadata | object | no | — | Merged over default metadata | litellm.keyGeneration.allowUnlimitedBudget | boolean | no | false | Show the "Unlimited budget" checkbox in the Generate New Key form | litellm.keyGeneration.teamRequired | boolean | no | true | Require a team to be selected before a key can be generated | required when the roles array is present In packages/backend/src/index.ts : backend.add import '@acarmisc/backstage-plugin-litellm-backend' ; The plugin uses the Backstage New Frontend System. Add the plugin package as an extension in packages/app/src/App.tsx or equivalent: js import { litellmPlugin, LiteLLMPage } from '@acarmisc/backstage-plugin-litellm'; // Add the route: