Platform teams keep running into the same wall: developers can spin up a Kubernetes cluster or a new microservice in minutes, but nobody can find who owns it, what it depends on, or where its docs live six months later. Backstage, the open-source internal developer portal that Spotify built and handed to the Cloud Native Computing Foundation, was created to fix exactly that problem. As of August 2026 the project sits at version 1.54.0, ships a software catalog, a template-driven scaffolder, and a plugin framework with more than 260 directory-listed integrations, and has become the default reference point whenever engineering leaders discuss “platform engineering” at KubeCon and internal tech talks alike. The project is hosted by the Cloud Native Computing Foundation, alongside Kubernetes and Prometheus.
This tutorial walks through installing Backstage from scratch using the project’s official getting started documentation as a baseline, wiring up the software catalog, connecting a CI/CD plugin, adding authentication, and deploying the result to a production Kubernetes cluster with PostgreSQL as the backing store. Expect roughly 100 to 120 minutes end to end if you follow along on a machine that already has Node.js and Docker installed. Along the way we will hit the exact errors most first-time Backstage operators hit, and show how to get past them without re-reading the entire documentation tree.
Don't miss new tech stories on Google
Add Tech Insider once in the Google app and our stories appear in your news suggestions.
What Backstage Actually Solves
Backstage is not a monitoring tool, not a CI system, and not a cloud provider console. It is a single web application that pulls metadata from all of those systems and renders them behind one consistent UI, organized around a software catalog. Every service, library, website, or data pipeline in your organization becomes an “entity” in that catalog, described by a small YAML file called catalog-info.yaml that lives next to the code it describes. Once that entity exists, Backstage can attach ownership information, dependency graphs, TechDocs documentation, CI status, on-call rotations, and cost data to it, all pulled live from the systems that actually hold that data.
The pitch that gets platform teams to adopt it is straightforward: instead of building yet another internal wiki page that goes stale, or another custom Slack bot for triggering deploys, you build a scaffolder template inside Backstage once, and every team gets a self-service “create a new service” button that already applies your security, tagging, and CI standards. Spotify’s own engineering org, along with companies like American Airlines, Netflix, and Expedia, have talked publicly about running Backstage at scale for exactly this reason: it turns tribal knowledge about “how we do things here” into a machine-readable, enforceable template.
Where Backstage differs from commercial internal developer portal products such as Port, Cortex, or OpsLevel is licensing and control. Backstage itself is free and open source under the Apache 2.0 license, so there is no per-seat fee for the software, but you own the hosting, the upgrades, and the plugin maintenance. Commercial IDPs trade that operational burden for a subscription. For teams with an existing platform engineering function and a Kubernetes cluster to run it on, self-hosting Backstage is usually the cheaper long-term option; for teams without spare platform engineering capacity, a hosted competitor can get you a working portal faster.
Why 2026 Is a Different Moment for Backstage
Two changes this year matter for anyone starting fresh. First, the New Frontend System, which spent roughly two years in development, reached release-candidate status with version 1.49.0 in March 2026 and is now the default scaffolding path, which means most plugin installation is declarative YAML instead of hand-edited React wiring. Second, the project shipped its “AI superpowers” work in the same window: an Actions Registry and Model Context Protocol server support, announced at BackstageCon co-located with KubeCon + CloudNativeCon Europe in Amsterdam on April 20, 2026. That second piece matters because it turns the catalog from a passive metadata store into something an AI coding agent can query and act on directly, a capability none of the earlier 1.4x releases had.
Prerequisites and Version Requirements
Before starting, make sure the following are installed and available on your PATH. Backstage’s own create-app scaffolder now checks several of these automatically and will refuse to continue if a version is too old, which saves you from debugging a broken install later. Check the Node.js release schedule if you are unsure which line is the current active LTS.
| Tool | Minimum / Recommended Version | Why It’s Needed |
|---|---|---|
| Node.js | Active LTS release (Node 22.x as of August 2026) | Backstage’s backend and frontend build tooling run on Node; the CLI now checks for an LTS release before scaffolding |
| Yarn | Yarn 4.x (Berry, via Corepack) | Backstage’s monorepo dependency management uses Yarn workspaces, not npm |
| Docker | 24.x or newer | Used to containerize the backend for deployment and to run PostgreSQL locally |
| PostgreSQL | One of the last five major released versions (16 or 17 recommended) | Production catalog storage; SQLite is fine for local dev only |
| kubectl + a Kubernetes cluster | 1.29+ (EKS, AKS, GKE, or a local kind cluster) | Target environment for the production deployment step |
| Git | 2.40+ | Backstage reads catalog files directly from Git repositories |
You will also need a GitHub organization (or GitLab/Bitbucket if you prefer, the steps are analogous) where you have permission to create an OAuth application, since Backstage’s default authentication flow and catalog discovery both lean on your Git provider. If you are testing this on a personal account, a free GitHub account with one or two throwaway repositories is enough to complete every step in this guide.
Step 1: Scaffold a New Backstage App
Backstage does not ship as an installable package the way a typical framework does. Instead, you generate your own application from a template, and that generated repository becomes “your” Backstage instance, which you customize and redeploy over time. Start by confirming your Node version, then run the official scaffolder.
node --version
# should print v22.x.x or newer LTS
corepack enable
npx @backstage/create-app@latest --path my-backstage-app
The scaffolder asks for an application name, then generates a monorepo with two workspaces: packages/app (the React frontend) and packages/backend (the Node.js backend). As of the 1.54.0 release, the generated app also includes a ready-to-use GitHub Actions CI workflow that runs linting, type checking, tests, and a Docker build, plus a pre-configured home page, so you do not need to hand-roll that pipeline yourself.
Once scaffolding finishes, move into the directory and start the app in development mode:
cd my-backstage-app
yarn install
yarn dev
This launches the frontend on localhost:3000 and the backend API on localhost:7007, backed by an in-memory SQLite database. If both processes start without errors and the browser shows the default Backstage homepage with a search bar and an empty catalog, the scaffold succeeded and you are ready to start wiring in real data.
Step 2: Understand the Project Structure
Before adding plugins, it helps to know where things live, because Backstage’s file layout trips up a lot of first-time users coming from single-package frameworks.
app-config.yaml— the base configuration file: database connection, auth providers, catalog locations, and integrations all live here.app-config.production.yaml— overrides applied only whenNODE_ENV=production, typically pointing at PostgreSQL instead of SQLite and pulling secrets from environment variables.packages/backend/src/index.ts— the backend entry point, where you register each backend plugin as a single line of code.packages/app/src/App.tsx— the frontend entry point, where frontend plugins and routes are registered.catalog-info.yaml— not part of the app itself, but the file you will add to every repository you want Backstage to track.
Since the New Frontend System went to release-candidate status in version 1.49.0 and became adoption-ready by mid-2026, newly scaffolded apps default to the newer declarative frontend wiring, which lets you add most plugins by editing app-config.yaml rather than hand-editing React imports. Older tutorials floating around the web still show the legacy imperative wiring in App.tsx; if a plugin’s install instructions look like they belong to a different app structure than the one you just generated, check whether the plugin has published New Frontend System-compatible install steps.
Step 3: Configure PostgreSQL for Production Storage
SQLite is fine for a local proof of concept but is not suitable once more than one person is using the portal, since Backstage’s catalog processor writes constantly and SQLite does not handle concurrent writers well. Spin up PostgreSQL locally with Docker for testing the production config path:
docker run -d --name backstage-postgres \
-e POSTGRES_USER=backstage \
-e POSTGRES_PASSWORD=changeme \
-e POSTGRES_DB=backstage_plugin_catalog \
-p 5432:5432 \
postgres:17
Then point app-config.production.yaml at it:
backend:
database:
client: pg
connection:
host: ${POSTGRES_HOST}
port: ${POSTGRES_PORT}
user: ${POSTGRES_USER}
password: ${POSTGRES_PASSWORD}
database: backstage_plugin_catalog
Backstage creates a separate schema per plugin automatically on first boot, so you do not need to hand-write migrations for the catalog, scaffolder, or auth plugins. The 1.54.0 release also added automatic retry behavior for PostgreSQL deadlocks during entity provider mutations, which matters once you have several catalog ingestion sources writing to the same tables at once — earlier versions could occasionally fail a catalog refresh cycle under concurrent writes without retrying.
Step 4: Set Up GitHub Authentication
Backstage ships with a guest login for local development, but any real deployment needs an actual identity provider. GitHub OAuth is the most common starting point because it doubles as the catalog data source. Create a new OAuth App under your GitHub organization’s developer settings, set the callback URL to http://localhost:7007/api/auth/github/handler/frame for local testing, and note the client ID and secret.
auth:
environment: development
providers:
github:
development:
clientId: ${AUTH_GITHUB_CLIENT_ID}
clientSecret: ${AUTH_GITHUB_CLIENT_SECRET}
Export the two secrets as environment variables rather than committing them, restart the backend, and the sign-in screen should now offer a “Sign in with GitHub” button instead of the guest-only flow. This is also the point where most teams decide whether to sync GitHub team membership into Backstage’s own user and group catalog, which controls who can see what, and who is allowed to run which scaffolder templates.
Step 5: Register Your First Service in the Catalog
Pick an existing repository and drop a catalog-info.yaml file in its root. This is the minimum viable entity description:
apiVersion: backstage.io/v1alpha1
kind: Component
metadata:
name: payments-api
description: Handles card and wallet payment processing
annotations:
github.com/project-slug: your-org/payments-api
backstage.io/techdocs-ref: dir:.
spec:
type: service
lifecycle: production
owner: group:payments-team
system: checkout
Commit and push that file, then in the Backstage UI go to Create → Register Existing Component, paste the raw GitHub URL to the file, and click Analyze. Backstage fetches the file, validates the schema, and adds the entity to the catalog. Within a minute the service shows up in the catalog list with its owner, lifecycle stage, and a placeholder for CI status and docs, both of which get filled in once you enable the matching plugins in the next two steps.
Step 6: Add a CI/CD Plugin
The plugin directory listed 269 entries as of mid-2026 — 5 core plugins maintained by the Backstage team, roughly 210 active community plugins, and 59 marked inactive — covering everything from GitHub Actions and Jenkins to ArgoCD, Terraform, Pulumi, and Crossplane. Installing the GitHub Actions plugin is a good first integration because most teams already have workflow data to display. Add it to the frontend package:
Core Plugins vs. Community Plugins
It is worth understanding the distinction before you standardize your rollout on any given plugin. The 5 core plugins (catalog, scaffolder, search, TechDocs, and permissions) ship inside the main Backstage repository, follow the project’s own release cadence, and get security fixes on the same schedule as the core. The roughly 210 active community plugins live in separate repositories, maintained by individual companies or contributors, and can lag behind a core version bump for days or weeks. Before wiring a community plugin into a production rollout, check its last commit date and whether it has been updated for the New Frontend System; a plugin that has not shipped a release in over six months is a real risk for a component you plan to depend on long-term, since Backstage’s core team does not guarantee backward compatibility for community integrations across major version bumps.
yarn --cwd packages/app add @backstage-community/plugin-github-actions
Then register the plugin’s route and card in your app config (or in App.tsx if your generated app still uses the legacy wiring), and add a github.com/project-slug annotation, which you already have from the previous step. Reload the entity page for payments-api and a new tab appears showing the last several workflow runs, their status, and duration, pulled live from the GitHub Actions API using the same OAuth token from your login step.
Step 7: Enable TechDocs
TechDocs is Backstage’s built-in documentation system: you write Markdown in the same repository as your code, Backstage builds it with MkDocs, and serves the rendered site inside the portal next to the service’s catalog entry. This solves the classic problem of documentation living in a wiki that nobody updates because it is disconnected from the code review process.
techdocs:
builder: local
generator:
runIn: docker
publisher:
type: local
Add a minimal mkdocs.yml and a docs/index.md to the same repository as your catalog-info.yaml, then trigger a rebuild from the entity’s Docs tab. For production you will want to switch the publisher type from local to an object storage backend such as Amazon S3 or Google Cloud Storage, since local disk storage does not survive a pod restart on Kubernetes.
Step 8: Build a Scaffolder Template
The scaffolder is what turns Backstage from a read-only catalog into a self-service platform. A template is a YAML file describing an input form and a sequence of actions, most commonly “fetch a skeleton repo, template a few variables into it, and publish a new GitHub repository.”
apiVersion: scaffolder.backstage.io/v1beta3
kind: Template
metadata:
name: node-microservice
title: New Node.js Microservice
description: Creates a new service repo with CI, catalog-info.yaml, and Dockerfile pre-wired
spec:
owner: group:platform-team
type: service
parameters:
- title: Service details
required: [name, owner]
properties:
name:
type: string
description: Unique service name
owner:
type: string
description: Owning team
steps:
- id: fetch
name: Fetch skeleton
action: fetch:template
input:
url: ./skeleton
values:
name: ${{ parameters.name }}
owner: ${{ parameters.owner }}
- id: publish
name: Publish to GitHub
action: publish:github
input:
repoUrl: github.com?repo=${{ parameters.name }}&owner=your-org
- id: register
name: Register in catalog
action: catalog:register
input:
repoContentsUrl: ${{ steps.publish.output.repoContentsUrl }}
catalogInfoPath: /catalog-info.yaml
Register this template’s YAML path under catalog.locations in your app config, and it appears in the Create page as a form. Fill it in, submit, and Backstage creates a real GitHub repository, seeded from your skeleton, and automatically registers it back into the catalog. This is the mechanism that lets a platform team encode security scanning, standard CI, and mandatory ownership metadata into every new service without writing a review checklist that people skip.
Step 9: Package the Backend for Deployment
Backstage ships a build command that produces a production-ready backend bundle and a Dockerfile template you can build directly:
yarn build:backend
docker build . -f packages/backend/Dockerfile --tag my-backstage-app:1.0.0
The generated Dockerfile produces a multi-stage image with the compiled backend and frontend static assets bundled together, since Backstage’s backend also serves the built frontend in production rather than requiring a separate static host. Push the resulting image to your container registry (Amazon ECR, Google Artifact Registry, or Azure Container Registry all work identically here) before moving to the Kubernetes step.
Step 10: Deploy to Kubernetes
A minimal production deployment needs a Deployment, a Service, and a Secret holding your GitHub OAuth credentials and database password. Here is a trimmed manifest that covers the essentials:
apiVersion: apps/v1
kind: Deployment
metadata:
name: backstage
spec:
replicas: 2
selector:
matchLabels:
app: backstage
template:
metadata:
labels:
app: backstage
spec:
containers:
- name: backstage
image: your-registry/my-backstage-app:1.0.0
ports:
- containerPort: 7007
envFrom:
- secretRef:
name: backstage-secrets
env:
- name: NODE_ENV
value: "production"
resources:
requests:
cpu: 250m
memory: 512Mi
limits:
cpu: 1
memory: 1Gi
---
apiVersion: v1
kind: Service
metadata:
name: backstage
spec:
selector:
app: backstage
ports:
- port: 80
targetPort: 7007
Apply it with kubectl apply -f backstage-deployment.yaml, front it with an ingress or load balancer, and point your organization’s internal DNS at it. Running two replicas is a reasonable starting point; because Backstage’s catalog processing is stateless and reads from PostgreSQL, horizontal scaling works without any special session affinity configuration.
Step 11: Automate Catalog Discovery
Manually registering each repository does not scale past a handful of services. Once you have more than roughly 20 to 30 repositories, switch to the GitHub organization discovery provider, which scans your org for any repository containing a catalog-info.yaml file and registers it automatically on a schedule.
catalog:
providers:
github:
providerId:
organization: 'your-org'
catalogPath: '/catalog-info.yaml'
filters:
branch: 'main'
schedule:
frequency: { minutes: 30 }
timeout: { minutes: 3 }
This is also the point to enforce standards: many platform teams add a CI check in their organization’s shared workflow templates that fails a pull request if a new repository does not include a valid catalog-info.yaml, so the discovery provider never has to deal with malformed or missing entities.
Step 12: Add Cost and Kubernetes Visibility
Two of the most requested additions once a Backstage rollout gets past the pilot stage are Kubernetes runtime data and cloud cost data on the entity page. The community Kubernetes plugin queries your cluster’s API for pods, deployments, and resource usage tied to a given entity via label selectors, while cost plugins such as the community Kubecost integration surface per-service spend directly next to ownership information, closing the loop between “who owns this” and “what does it cost to run.”
yarn --cwd packages/app add @backstage/plugin-kubernetes
yarn --cwd packages/backend add @backstage/plugin-kubernetes-backend
Configure a cluster locator pointing at your kubeconfig or a service account token, add a backstage.io/kubernetes-id annotation to your entities matching your deployment labels, and the entity page gains a live pod status view. Combined with the CI plugin from Step 6, a single entity page now answers “is it deployed, is it healthy, and who do I ask” without anyone opening a separate dashboard.
Setting Up Role-Based Access Control
Once the scaffolder can create real GitHub repositories and trigger real deployments, “anyone with a login can run any template” stops being an acceptable default. Backstage’s permissions framework is one of the 5 core plugins, and it works by intercepting requests to other plugins (catalog, scaffolder, and so on) and evaluating a policy you define in code before the action is allowed to proceed.
Static Permission Policies
The simplest starting policy denies scaffolder template execution to anyone outside a specific group, while leaving read access to the catalog open to every authenticated user:
export class PlatformPermissionPolicy implements PermissionPolicy {
async handle(request: PolicyQuery, user?: BackstageIdentityResponse) {
if (isScaffolderAction(request.permission)) {
const isPlatformTeam = user?.identity.ownershipEntityRefs
.includes('group:platform-team');
return isPlatformTeam
? { result: AuthorizeResult.ALLOW }
: { result: AuthorizeResult.DENY };
}
return { result: AuthorizeResult.ALLOW };
}
}
Register this policy class in the backend’s permission plugin configuration, and the scaffolder UI immediately reflects it: templates that a user is not authorized to run either disappear from the Create page or return a clear “not authorized” error on submission, depending on how strict you want the UI feedback to be.
Conditional Rules for Catalog Entities
Beyond static allow/deny decisions, the permissions framework supports conditional rules evaluated per-entity, which is what you need for a policy like “engineers can edit catalog entities they own, but not entities owned by other teams.” Rather than writing that logic by hand, Backstage lets you compose conditional rules from existing rule sets (such as isEntityOwner) shipped by the catalog plugin, which keeps the policy declarative and easier to audit during a security review than an equivalent hand-written authorization function scattered across the codebase.
Monitoring Backstage Itself in Production
A portal that goes down without anyone noticing defeats its own purpose fast, since developers who hit an error once tend not to come back. Treat the Backstage instance as a production service with the same observability standards you would apply to anything else in the catalog it manages. The backend exposes a standard /healthcheck endpoint for liveness and readiness probes, which should already be wired into the Kubernetes deployment from Step 10 via livenessProbe and readinessProbe stanzas pointed at that path.
For deeper visibility, Backstage’s backend supports OpenTelemetry instrumentation out of the box, which means metrics on catalog processing duration, plugin request latency, and database query time can flow into the same observability stack you already run for other services, rather than requiring a separate dashboard just for the portal. Watch three numbers in particular during the first month of a rollout: catalog full-refresh duration (which grows with entity count and should stay well under your configured processing interval), backend memory usage during refresh cycles, and PostgreSQL connection pool saturation, since all three tend to be the first signs that a growing catalog needs the backend split into separate processing and serving replicas described in the scaling tips below.
Common Pitfalls When Running Backstage
These are the mistakes that come up most often in postmortems of failed or stalled Backstage rollouts.
- Treating the pilot catalog as optional metadata. If ownership and lifecycle fields are inconsistently filled in, the catalog becomes noise instead of a source of truth, and adoption stalls because nobody trusts the data.
- Skipping the discovery provider. Manual registration works for a demo with five services; it silently breaks down once developers stop remembering to add new repositories by hand.
- Running SQLite in production. It works right up until two people hit “create” at the same time, then catalog writes start failing intermittently in a way that is hard to reproduce.
- Mixing New Frontend System and legacy plugin instructions. Copying install steps from an older blog post into a newly scaffolded 1.5x app produces confusing type errors; always check a plugin’s README for the frontend system it targets.
- No plan for plugin maintenance. Community plugins are not guaranteed compatibility across Backstage core version bumps; budget time for testing plugin updates before jumping several minor versions at once.
- Underestimating GitHub API rate limits. A large catalog with hundreds of entities polling CI status and discovery on tight schedules can hit secondary rate limits; use a GitHub App token instead of a personal access token for anything beyond a small pilot.
- Forgetting TechDocs storage durability. The default local publisher writes to container-local disk, which is wiped on every pod restart; switch to S3 or GCS before telling anyone their docs are “in Backstage now.”
- No RBAC plan before opening self-service. The scaffolder can create real infrastructure; without group-based permissions on templates, anyone with a login can trigger anything, which is rarely what a security team wants.
Sample Output: What a Working Catalog Entity Looks Like
Once Steps 5 through 12 are complete for a service, its entity page in the Backstage UI shows a consistent set of tabs: Overview (ownership, lifecycle, description, links to source), CI/CD (recent workflow runs and status), Docs (rendered TechDocs site), Kubernetes (live pod and deployment status), and Dependencies (a graph of the APIs and components this service consumes or exposes). A typical catalog listing view for a mid-sized organization with, say, 80 registered services renders as a filterable table with columns for name, owner, lifecycle, and type, searchable by any of those fields, plus free text search across descriptions and tags.
Troubleshooting Backstage Setup Issues
Here are the errors and symptoms that show up most frequently, in the order you are likely to hit them.
- “Node version not supported” during create-app. The scaffolder now checks for an active LTS Node release before generating the app; install the current LTS with a version manager such as nvm or fnm rather than fighting the check.
- Backend fails to start with a database connection error. Confirm the PostgreSQL container is actually accepting connections with
docker logs backstage-postgres, and thatPOSTGRES_HOSTresolves from inside the backend’s network context, not just from your host machine. - GitHub OAuth redirect loop. The callback URL registered in the GitHub OAuth App must match exactly, including protocol and trailing path, what Backstage sends; a mismatch here is the single most common auth failure.
- New entity does not appear after “Register Existing Component.” Check the backend logs for a catalog processing error; a malformed
catalog-info.yaml(usually a YAML indentation issue or a missing required field) fails silently in the UI but logs a clear error server-side. - TechDocs build fails with a Docker socket error. The
runIn: dockergenerator needs access to the Docker socket from wherever the backend runs; on Kubernetes this typically means switching to therunIn: localgenerator with mkdocs pre-installed in your image instead. - Plugin installs but its tab never renders. Most often this means the plugin was added to the wrong package (frontend plugin in the backend package or vice versa), or the corresponding annotation is missing from the entity’s YAML.
- Catalog discovery finds zero repositories. Double-check the GitHub App or token has read access to the target organization and that at least one repository actually has a
catalog-info.yamlon the branch configured in the provider filter. - Deployment crash-loops on Kubernetes but works locally. Almost always a missing environment variable from the Secret, since local development pulls values from a
.envfile that is not present in the container image by design. - Search returns stale results after a catalog update. Backstage’s search index refreshes on its own schedule separate from catalog ingestion; check the search collator’s configured interval if results lag behind visible catalog changes.
Advanced Tips for Scaling Backstage
Once the basic rollout is stable, a few practices separate portals that stay useful from ones that quietly get abandoned. First, assign a real owning team to the Backstage instance itself, not just to the services inside it; a portal with no maintainer drifts out of date within a quarter. Second, wire catalog ownership data into your existing incident and on-call tooling rather than duplicating it, since a second source of truth for “who owns this” will inevitably disagree with the first one. Third, track adoption with a simple metric such as percentage of production services with a valid catalog entry, and report it the same way you would report test coverage; portals that are optional tend to stay empty.
On the technical side, as your entity count grows past a few hundred, watch backend memory usage during full catalog refresh cycles and consider splitting the catalog processing into its own backend replica separate from the one serving UI traffic, since Backstage supports running plugins as independent backend processes for exactly this kind of horizontal scaling. Teams running infrastructure-as-code heavy organizations increasingly wire Terraform, Pulumi, or Crossplane state directly into the catalog as additional entity kinds (Resource entities, in Backstage’s model), which extends the “who owns this and what does it cost” question from services down to the cloud resources backing them.
Backstage vs. Commercial Internal Developer Portals
The decision between self-hosting Backstage and buying a commercial IDP usually comes down to existing platform engineering capacity rather than feature checklists, since the commercial products (Port, Cortex, OpsLevel, and Spotify’s own hosted Portal offering built on Backstage internals) largely converge on the same core idea: a software catalog plus self-service actions plus scorecards.
| Factor | Self-Hosted Backstage | Commercial IDP (Port, Cortex, OpsLevel) |
|---|---|---|
| Software licensing cost | Free (Apache 2.0) | Per-seat or per-service subscription |
| Hosting and operations | You run and patch it | Vendor-hosted SaaS |
| Plugin ecosystem | 269+ directory-listed plugins, open source | Vendor-built integrations, closed source |
| Customization ceiling | Full source access, any level of customization | Bound by vendor’s extensibility model |
| Time to first working portal | Days to weeks depending on team experience | Typically hours to days |
| Best fit | Orgs with an existing platform engineering team | Orgs wanting a portal without dedicated maintainers |
Building the Complete Working Project
Putting every step above together, a complete working project consists of: a scaffolded Backstage monorepo with the New Frontend System enabled, a PostgreSQL 17 backing store, GitHub OAuth authentication, a GitHub Actions CI plugin, TechDocs with S3-backed storage, a working scaffolder template that creates and registers new services, GitHub organization discovery running on a 30-minute schedule, and a two-replica Kubernetes deployment behind an internal load balancer. That combination covers the full loop platform teams actually care about: developers self-serve new services from a template, those services auto-register into the catalog, CI and Kubernetes status flow back into the same page, and documentation lives next to the code instead of in a separate wiki nobody maintains.
From here, the natural next steps are adding scorecards (automated checks like “has an on-call rotation” or “passes our security baseline” scored per service), wiring in a cost plugin, and expanding the scaffolder template library to cover your organization’s most common project types beyond a single Node.js microservice. None of that requires re-architecting anything from this guide; it is additive on top of the same catalog, the same plugin framework, and the same deployment you just stood up.
Frequently Asked Questions
Is Backstage free to use in production?
Yes. Backstage is licensed under Apache 2.0 and free to self-host with no per-seat fee. Your costs are the infrastructure you run it on (compute, PostgreSQL, storage) and the engineering time to maintain it.
What is the current Backstage version as of August 2026?
Backstage is at version 1.54.0, released August 19, 2026, according to the project’s own release notes. The source is maintained in the backstage/backstage GitHub repository.
Does Backstage require Kubernetes to run?
No. Kubernetes is a common production deployment target because of its scaling and rollout tooling, but Backstage’s backend is a standard Node.js application that can run on any container platform, a VM, or a PaaS that supports Docker images.
Can Backstage replace our existing wiki entirely?
For service-level documentation, yes, via TechDocs, since docs live in the same repository as the code and render inside the catalog. Broader organizational documentation not tied to a specific service or team is usually better left in a general-purpose wiki.
How many plugins does Backstage support?
The plugin directory listed 269 entries as of mid-2026: 5 core plugins maintained by the Backstage team, roughly 210 active community plugins, and 59 marked inactive, covering CI/CD, cloud providers, infrastructure-as-code tools, and observability platforms.
Do we need PostgreSQL, or can we use MySQL?
Backstage officially documents and supports PostgreSQL for production use, currently across the last five major released versions in a rolling support window. SQLite is supported for local development only.
How is Backstage different from Port, Cortex, or OpsLevel?
Backstage is open source and self-hosted with full source-level customization; Port, Cortex, and OpsLevel are commercial, vendor-hosted SaaS products with subscription pricing that trade some customization depth for faster setup and no operational burden.
What is the New Frontend System and do I need to worry about it?
It is Backstage’s newer, more declarative way of wiring plugins into the frontend, which reached release-candidate status in version 1.49.0 and became the default for newly scaffolded apps. If you generate a new app today, you get it automatically; older apps can migrate incrementally.


