Terraform uses providers to talk to external systems over APIs. The Terraform Provider for Backstage lets you manage and query your Backstage catalog with the same workflow you use for infrastructure. You keep catalog data and infrastructure code in one place, under version control.
The plugin exposes Backstage entities as Terraform data sources. You can read Component, API, System, Domain, Resource, Group, User, and Location data. Metadata, relations, and spec fields are available to your plans. It also includes a resource for managing catalog locations so you can treat catalog entries as code. A fallback option lets pipelines keep running if your Backstage instance is unavailable.
Common use cases are simple. Sync owners, tags, and system links from the catalog into cloud tags. Create namespaces and service accounts with names and labels pulled from Backstage. Drive access rules or dependencies in other providers based on catalog facts. Generate or validate relationships between services before you apply. Feed catalog context into CI so teams do not jump between tools.
If you run a self hosted Backstage, this plugin helps keep the portal as the source of truth. Pipelines read the same data the portal shows. Platform teams get repeatable catalog changes. Engineers get consistent names and ownership across services, infrastructure, and docs.
Installation Instructions
These instructions apply to self-hosted Backstage only.
What you will set up
You will use the Terraform Backstage provider to manage your Backstage catalog over HTTP. It runs outside Backstage. It does not add any UI inside your Backstage app. There is no Backstage package to install.
Prepare Backstage to accept writes
If you plan to use the backstage_location resource, your Backstage instance must not run in read only mode.
Set this in your Backstage config
# app-config.yaml
catalog:
  readonly: falseRestart your Backstage backend after the change.
Create a Terraform workspace
Create a folder for your Terraform files. Add these files.
# versions.tf
terraform {
  required_version = ">= 1.5.0"
  required_providers {
    backstage = {
      source  = "datolabs-io/backstage"
      version = "~> 0.4"
    }
  }
}# provider.tf
# Basic provider config
provider "backstage" {
  base_url = "https://your.backstage.example"
  # optional
  default_namespace = "default"
  # optional headers
  headers = {
    # set what your Backstage expects for auth
    # a common case
    Authorization = "Bearer YOUR_TOKEN"
  }
  # optional tuning
  retries         = 2
  timeout_seconds = 30
}You can also set provider values with environment variables
export BACKSTAGE_BASE_URL="https://your.backstage.example"
export BACKSTAGE_DEFAULT_NAMESPACE="default"
export BACKSTAGE_HEADERS='{"Authorization":"Bearer YOUR_TOKEN"}'
export BACKSTAGE_RETRIES="2"
export BACKSTAGE_TIMEOUT_SECONDS="30"Read data from the catalog
Fetch a single component
# data_component.tf
data "backstage_component" "example" {
  name      = "example-component"
  namespace = "default"
}
output "component_owner" {
  value = data.backstage_component.example.spec.owner
}Fetch many entities with filters
# data_entities.tf
data "backstage_entities" "default_users_and_groups" {
  filters = [
    "kind=User,metadata.namespace=default",
    "kind=Group,metadata.namespace=default",
  ]
}
output "first_entity_kind" {
  value = data.backstage_entities.default_users_and_groups.entities[0].kind
}Other available data sources
- backstage_api
- backstage_domain
- backstage_group
- backstage_location
- backstage_resource
- backstage_system
- backstage_user
Each has name and namespace inputs that match the Backstage descriptor format. See the examples above and use the same pattern.
Register a catalog location
Use the resource to add a catalog location in Backstage. Backstage must not be in read only mode.
# location.tf
resource "backstage_location" "example" {
  target = "https://raw.githubusercontent.com/yourorg/your-repo/main/catalog-info.yaml"
  # type defaults to url
}The provider will create the location through the Backstage catalog HTTP API.
Run Terraform
From the folder with your Terraform files
terraform init
terraform plan
terraform applyNo frontend components to import
This provider does not ship any React components. There is nothing to add to your Backstage frontend. No yarn commands are needed.
Backend notes legacy backend
- You do not install a Backstage backend plugin for this provider
- The provider calls the catalog HTTP API on your running backend
- Ensure your backend exposes the catalog endpoints
- If your backend requires auth, set the right headers in the provider config
Backend notes new backend system
- Same as the legacy case
- No backend module install is required
- Ensure the catalog module is enabled and reachable
- Provide the right auth header in the provider config
Minimal end to end example
This example reads a system and registers a location
terraform {
  required_providers {
    backstage = {
      source  = "datolabs-io/backstage"
      version = "~> 0.4"
    }
  }
}
provider "backstage" {
  base_url = "https://your.backstage.example"
  headers = {
    Authorization = "Bearer YOUR_TOKEN"
  }
}
data "backstage_system" "payments" {
  name      = "payments"
  namespace = "default"
}
output "payments_owner" {
  value = data.backstage_system.payments.spec.owner
}
resource "backstage_location" "service_catalog" {
  target = "https://raw.githubusercontent.com/yourorg/services/main/catalog-info.yaml"
}Set up Backstage in minutes with Roadie
Focus on using Backstage, rather than building and maintaining it.
