Backstage Developer Portal
Open-source developer portal for building developer platforms with plugin ecosystem.
Overview
Backstage is Spotify's open-source developer portal platform that centralizes software catalog management, documentation, and tooling into a unified developer experience. Originally built to solve Spotify's internal developer platform challenges, Backstage provides service discovery, technical documentation, deployment pipelines, and monitoring dashboards through an extensible plugin architecture. The platform has gained significant adoption among enterprises seeking to reduce cognitive load on development teams and standardize their internal tooling ecosystem.
This stack combines Backstage with PostgreSQL for persistent metadata storage, Redis for caching and session management, and NGINX for production-grade load balancing and SSL termination. PostgreSQL handles Backstage's service catalog data, user permissions, and plugin configurations with full ACID compliance, while Redis accelerates authentication sessions and caches frequently accessed catalog information. NGINX provides reverse proxy capabilities, enabling blue-green deployments and handling static asset delivery efficiently.
Platform engineering teams building internal developer platforms will find this configuration particularly valuable, as it addresses the complete infrastructure needs for a production Backstage deployment. The stack supports organizations with 50-5000+ developers who need centralized service discovery, automated documentation generation, and standardized deployment workflows across multiple engineering teams.
Key Features
- Backstage Software Templates for scaffolding new services with organizational standards and best practices built-in
- TechDocs integration with PostgreSQL storage for automated documentation generation from markdown files in service repositories
- Redis-powered authentication caching for faster login experiences and reduced database load during peak usage
- Service catalog with PostgreSQL-backed relationships, ownership tracking, and dependency mapping across microservices
- Plugin ecosystem support including Kubernetes monitoring, CI/CD pipeline visualization, and cost tracking integrations
- NGINX reverse proxy configuration enabling multiple Backstage instances for staging and production environments
- PostgreSQL JSON fields for flexible plugin configuration storage without schema migrations
- Redis pub/sub messaging for real-time updates to service catalog changes and deployment notifications
Common Use Cases
- 1Platform engineering teams establishing developer self-service portals for service creation and lifecycle management
- 2Organizations consolidating scattered internal tools (wikis, monitoring, CI/CD) into a single developer interface
- 3Engineering managers needing visibility into service ownership, dependencies, and documentation coverage across teams
- 4Companies implementing standardized deployment pipelines and security scanning through Backstage Software Templates
- 5DevOps teams providing developers with Kubernetes cluster access and resource monitoring without kubectl complexity
- 6Enterprises migrating from proprietary developer portals to open-source solutions with vendor independence
- 7Startups scaling beyond 20-30 services where manual service discovery and documentation becomes unsustainable
Prerequisites
- Minimum 4GB RAM available (1GB for Backstage, 1GB+ for PostgreSQL, 512MB for Redis, 256MB for NGINX)
- Node.js 18+ and Yarn package manager for Backstage application building and customization
- Understanding of Backstage's app-config.yaml structure for plugin configuration and authentication setup
- Basic knowledge of PostgreSQL schema management for Backstage database migrations and backups
- Familiarity with NGINX reverse proxy configuration for SSL certificates and custom domain setup
- Git repository access for integrating Backstage with GitHub, GitLab, or Bitbucket for service catalog discovery
For development & testing. Review security settings, change default credentials, and test thoroughly before production use. See Terms
docker-compose.yml
docker-compose.yml
1services: 2 backstage: 3 build: 4 context: .5 dockerfile: Dockerfile6 ports: 7 - "3000:3000"8 - "7007:7007"9 environment: 10 POSTGRES_HOST: postgres11 POSTGRES_PORT: 543212 POSTGRES_USER: ${POSTGRES_USER}13 POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}14 APP_CONFIG_app_baseUrl: http://localhost:300015 APP_CONFIG_backend_baseUrl: http://localhost:700716 depends_on: 17 postgres: 18 condition: service_healthy19 redis: 20 condition: service_started21 networks: 22 - backstage-net23 restart: unless-stopped2425 postgres: 26 image: postgres:16-alpine27 environment: 28 POSTGRES_USER: ${POSTGRES_USER}29 POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}30 POSTGRES_DB: backstage31 volumes: 32 - postgres_data:/var/lib/postgresql/data33 healthcheck: 34 test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER}"]35 interval: 10s36 timeout: 5s37 retries: 538 networks: 39 - backstage-net40 restart: unless-stopped4142 redis: 43 image: redis:7-alpine44 volumes: 45 - redis_data:/data46 networks: 47 - backstage-net48 restart: unless-stopped4950 nginx: 51 image: nginx:alpine52 ports: 53 - "80:80"54 - "443:443"55 volumes: 56 - ./nginx.conf:/etc/nginx/nginx.conf:ro57 depends_on: 58 - backstage59 networks: 60 - backstage-net61 restart: unless-stopped6263volumes: 64 postgres_data: 65 redis_data: 6667networks: 68 backstage-net: 69 driver: bridge.env Template
.env
1# PostgreSQL Configuration2POSTGRES_USER=backstage3POSTGRES_PASSWORD=secure_postgres_password45# Backstage Configuration6GITHUB_TOKEN=ghp_xxxx7BACKSTAGE_BASE_URL=http://localhost:3000Usage Notes
- 1Create Backstage app: npx @backstage/create-app
- 2Build Docker image from your Backstage app
- 3Frontend at http://localhost:3000
- 4Backend API at http://localhost:7007
Individual Services(4 services)
Copy individual services to mix and match with your existing compose files.
backstage
backstage:
build:
context: .
dockerfile: Dockerfile
ports:
- "3000:3000"
- "7007:7007"
environment:
POSTGRES_HOST: postgres
POSTGRES_PORT: 5432
POSTGRES_USER: ${POSTGRES_USER}
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
APP_CONFIG_app_baseUrl: http://localhost:3000
APP_CONFIG_backend_baseUrl: http://localhost:7007
depends_on:
postgres:
condition: service_healthy
redis:
condition: service_started
networks:
- backstage-net
restart: unless-stopped
postgres
postgres:
image: postgres:16-alpine
environment:
POSTGRES_USER: ${POSTGRES_USER}
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
POSTGRES_DB: backstage
volumes:
- postgres_data:/var/lib/postgresql/data
healthcheck:
test:
- CMD-SHELL
- pg_isready -U ${POSTGRES_USER}
interval: 10s
timeout: 5s
retries: 5
networks:
- backstage-net
restart: unless-stopped
redis
redis:
image: redis:7-alpine
volumes:
- redis_data:/data
networks:
- backstage-net
restart: unless-stopped
nginx
nginx:
image: nginx:alpine
ports:
- "80:80"
- "443:443"
volumes:
- ./nginx.conf:/etc/nginx/nginx.conf:ro
depends_on:
- backstage
networks:
- backstage-net
restart: unless-stopped
Quick Start
terminal
1# 1. Create the compose file2cat > docker-compose.yml << 'EOF'3services:4 backstage:5 build:6 context: .7 dockerfile: Dockerfile8 ports:9 - "3000:3000"10 - "7007:7007"11 environment:12 POSTGRES_HOST: postgres13 POSTGRES_PORT: 543214 POSTGRES_USER: ${POSTGRES_USER}15 POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}16 APP_CONFIG_app_baseUrl: http://localhost:300017 APP_CONFIG_backend_baseUrl: http://localhost:700718 depends_on:19 postgres:20 condition: service_healthy21 redis:22 condition: service_started23 networks:24 - backstage-net25 restart: unless-stopped2627 postgres:28 image: postgres:16-alpine29 environment:30 POSTGRES_USER: ${POSTGRES_USER}31 POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}32 POSTGRES_DB: backstage33 volumes:34 - postgres_data:/var/lib/postgresql/data35 healthcheck:36 test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER}"]37 interval: 10s38 timeout: 5s39 retries: 540 networks:41 - backstage-net42 restart: unless-stopped4344 redis:45 image: redis:7-alpine46 volumes:47 - redis_data:/data48 networks:49 - backstage-net50 restart: unless-stopped5152 nginx:53 image: nginx:alpine54 ports:55 - "80:80"56 - "443:443"57 volumes:58 - ./nginx.conf:/etc/nginx/nginx.conf:ro59 depends_on:60 - backstage61 networks:62 - backstage-net63 restart: unless-stopped6465volumes:66 postgres_data:67 redis_data:6869networks:70 backstage-net:71 driver: bridge72EOF7374# 2. Create the .env file75cat > .env << 'EOF'76# PostgreSQL Configuration77POSTGRES_USER=backstage78POSTGRES_PASSWORD=secure_postgres_password7980# Backstage Configuration81GITHUB_TOKEN=ghp_xxxx82BACKSTAGE_BASE_URL=http://localhost:300083EOF8485# 3. Start the services86docker compose up -d8788# 4. View logs89docker compose logs -fOne-Liner
Run this command to download and set up the recipe in one step:
terminal
1curl -fsSL https://docker.recipes/api/recipes/backstage-platform/run | bashTroubleshooting
- Backstage frontend shows 'Failed to load catalog' errors: Check PostgreSQL connection and verify POSTGRES_HOST environment variable matches service name
- Authentication sessions expire immediately: Ensure Redis is accessible from Backstage container and check Redis connection in app-config.yaml
- NGINX returns 502 Bad Gateway: Verify Backstage backend is running on port 7007 and update upstream configuration in nginx.conf
- PostgreSQL connection refused during startup: Add depends_on with health check condition and increase PostgreSQL startup timeout values
- Backstage plugins fail to load: Check plugin configuration in app-config.yaml and ensure required environment variables are set for external integrations
- TechDocs generation fails: Verify PostgreSQL has sufficient disk space and check techdocs.builder configuration in Backstage app-config
Community Notes
Loading...
Loading notes...
Download Recipe Kit
Get all files in a ready-to-deploy package
Includes docker-compose.yml, .env template, README, and license
Components
backstagepostgresqlredisnginx
Tags
#backstage#developer-portal#platform-engineering#service-catalog
Category
DevOps & CI/CDAd Space
Shortcuts: C CopyF FavoriteD Download