Stage 7 · Master
Developer Portal & Software Catalog
Backstage Architecture Deep Dive
Understand Backstage core: app, plugins, backend, database, auth, and permission framework. Self-host vs managed.
High-Level Architecture
Frontend (App)
- Single-page React application (TypeScript, Material UI)
- Plugin-based: each feature is a plugin (catalog, scaffolder, techdocs, kubernetes, etc.)
- App package (@backstage/app) composes plugins, configures routing, theming, auth
- Runs as static files (nginx, S3+CloudFront, Vercel) or served by backend
- Communicates with backend via REST (proxy) and WebSocket (real-time)
Backend
- Node.js/Express service (TypeScript)
- Plugin architecture: each backend plugin registers routes, middleware, database access
- Core plugins: catalog, scaffolder, auth, proxy, permissions, search, techdocs
- Database: PostgreSQL (required for catalog, scaffolder, auth sessions)
- Runs as container (Docker, Kubernetes) — single replica for dev, HA for prod
Database
- PostgreSQL 13+ required (catalog, scaffolder, auth, permissions, search index)
- Schema managed by Knex migrations (auto-run on startup)
- Connection pooling via pg-pool (configure pool size for load)
- Backup: Point-in-time recovery (PITR) or pg_dump + WAL-G
- Read replicas for scaling catalog queries (search, listing)
Authentication & Authorization
| Layer | Mechanism | Providers |
|---|---|---|
| Authentication | OAuth2/OIDC + session cookies | GitHub, GitLab, Google, Azure AD, Okta, Keycloak, custom OIDC |
| User Identity | Backstage User Entity + claims | Email, name, groups, token claims |
| Permissions | Policy-based (allow/deny) | Built-in: catalog, scaffolder, techdocs. Custom: RBAC, ABAC |
| Token Management | Backend-to-backend tokens | Service-to-service auth for backend plugins |
# packages/backend/src/plugins/permissions.ts
import { PermissionPolicy, AuthorizeResult } from '@backstage/plugin-permission-node';
import { stringifyEntityRef } from '@backstage/catalog-model';
export class CustomPermissionPolicy implements PermissionPolicy {
async handle(request: PermissionRequest): Promise<AuthorizeResult> {
const { userEntityRef, permission, resource } = request;
// Allow users to read all catalog entities
if (permission.name === 'catalog.entity.read') {
return AuthorizeResult.ALLOW;
}
// Allow users to modify entities they own
if (permission.name === 'catalog.entity.update' || permission.name === 'catalog.entity.delete') {
const owner = resource.entity?.metadata?.annotations?.['backstage.io/owned-by'];
if (owner && userEntityRef === `user:${owner}`) {
return AuthorizeResult.ALLOW;
}
// Check if user is member of owning team
const userTeams = await this.getUserTeams(userEntityRef);
if (owner && userTeams.includes(owner)) {
return AuthorizeResult.ALLOW;
}
return AuthorizeResult.DENY;
}
return AuthorizeResult.DENY;
}
}
Custom permission policies enable fine-grained access control based on ownership, team membership, and resource type.
Plugin System
- Frontend plugins: React components, routes, API clients (e.g., @backstage/plugin-catalog)
- Backend plugins: Express routers, database access, external integrations (e.g., @backstage/plugin-catalog-backend)
- Plugin packages: Published to npm, versioned independently
- Core plugins: Catalog, Scaffolder, TechDocs, Auth, Proxy, Permissions, Search, Kubernetes
- Community plugins: ArgoCD, Grafana, PagerDuty, Jira, SonarQube, Dependabot, etc.
- Custom plugins: Org-specific integrations (platform API, internal tools, compliance)
Deployment Options
| Option | Description | Pros | Cons |
|---|---|---|---|
| Docker Compose | All-in-one container for dev/local | Simple, no K8s needed | Not production-ready |
| Kubernetes (Helm) | Official Helm chart: app, backend, postgres, redis | HA, scalable, GitOps-friendly | Operational complexity |
| Managed Backstage (Roadie) | SaaS: hosted app + backend + DB | Zero ops, auto-upgrades, support | Cost, less customization |
| Spotify Backstage (Managed) | Spotify's managed offering | Native, enterprise support | Invite-only, pricing opaque |
| Custom Deploy | Build your own: ECS, Cloud Run, VMs | Full control | High maintenance burden |
Begin with Docker Compose for evaluation. Move to Kubernetes (Helm) when you need HA, SSO integration, and team access. Consider managed (Roadie) if you lack platform ops capacity. The backend is the only stateful component — PostgreSQL is the critical dependency.
Mark this lesson complete to store local progress and unlock a cleaner resume path the next time you visit.