Backstage and GitHub integration

Connect Backstage to GitHub or GitHub Enterprise for catalog discovery, org data and webhook-driven updates, with the credential model chosen before the build starts.

On this page

How Backstage reads GitHub for catalog discovery and org data

A platform team that wants service ownership in Backstage to match what already exists in GitHub needs to treat the GitHub connection as a catalog data source, not as a sign-in method. The GitHub integration in Backstage reads catalog-info.yaml files from repositories, discovers repositories that carry them, and imports members and teams as catalog users and groups. These jobs run on the backend through the GitHub integration configuration and the GitHub discovery and org entity provider modules described in the Backstage documentation. Sign-in to the portal is configured separately through the authentication system, so a user can log in with one GitHub identity while the catalog is populated from another set of credentials. Keep that separation in mind when you plan who owns the integration.

The first decision is the credential type. The Backstage GitHub integration supports GitHub Apps and personal access tokens, and the documentation covers the configuration keys for each, including how to point the integration at GitHub Enterprise Server hosts. A GitHub App is generally the better fit for a shared platform because its permissions are scoped per installation and it is not tied to an individual's account, but you should confirm the exact permissions your discovery and org import need against the current Backstage documentation. Map each GitHub organization that will feed the catalog to an installation, and record who holds the private key and how it is rotated, since that key is a secret that the backend reads at runtime. Ask your GitHub administrators to confirm that the App can see every repository that should be discoverable, because repositories outside the installation will silently never appear in the catalog.

Before enabling discovery across an organization, run it against a small, agreed set of repositories and check the imported entities against what the owning teams expect. Confirm which catalog-info.yaml path and branch the discovery reads, and decide how archived and forked repositories are handled. For org data, verify that team membership maps to the group entities your ownership model needs, and that users who have left the organization are removed on the next sync rather than lingering as owners. Webhook-driven updates and scheduled runs both change the catalog, so agree on which mechanism is authoritative for each entity type before go-live. Finally, have the team confirm the exact version of the Backstage release they are running, because the GitHub modules and their options are tied to the release line in use.

GitHub App or token credentials: which fits your organization

A GitHub App is registered once, installed on the organizations or repositories it needs, and acts under its own identity with permissions granted at installation. A personal access token is tied to a human user account and inherits that user's access, which means the token can see whatever that person can see. For Backstage, the practical difference is who the integration is and how far its reach extends. Confirm the current permission requirements for catalog discovery and org data reads in GitHub's own documentation, since permission sets change over time.

  • Access scope: An app's access is limited to the installations and permissions you grant. A token carries the full scope you select, and it can break if the owning user loses access.
  • Installation: An app is installed per organization or per selected repository. A token is created by a user and has no installation step.
  • Rotation: App credentials are a private key and app identifiers that you rotate under your own procedure. Tokens expire or are revoked manually and need replacement wherever they are configured.
  • Audit ownership: App actions appear under the app's identity in the audit trail. Token actions appear under the person who created it, which complicates reviews when that person changes roles.
  • Lifecycle risk: A token stops working when its owner leaves or is deprovisioned, which can silently stop catalog discovery.

Before choosing, ask your GitHub administrator who can register and install apps in your organization, and whether your policy allows personal tokens for service integrations.

What you need before connecting Backstage to GitHub

Five things need to be in place before any GitHub connection is configured: a supported Backstage release, a GitHub account boundary, a named owner for credentials, network paths from the backend, and a secret store. Each card below covers one of them and the checks to run before you start building.

Supported Backstage release line

Start from a Backstage release that is still inside the project's support window. The main release line ships monthly and the next line ships weekly, so pin one line and plan regular bumps. Check the versioning policy and the releases page to confirm which version is current and which Node.js versions it supports before you build. Do not copy GitHub configuration from an older tutorial without checking it against the version you run.

Node.js version within policy

Backstage supports exactly two adjacent even-numbered Node.js releases at a time. Confirm which pair matches your Backstage version, then install that runtime on the build and backend hosts. Mismatched Node.js versions are a common cause of failed installs during the first GitHub integration build, so verify the runtime before debugging connector code.

GitHub organization or Enterprise Server

Identify the exact GitHub boundary Backstage will read: a github.com organization, or a GitHub Enterprise Server instance with its own hostname. Decide which organizations and repositories are in scope before anything is installed. Enterprise Server deployments need their own host configuration, so confirm the hostname, API endpoint and certificate chain with the server administrator.

Owner for app or token issuance

Name one accountable person who can install a GitHub App on the organization or issue a token with the required scopes. That owner approves the permissions requested, records the installation and rotates credentials. If nobody holds that authority, the integration stalls at the first credential step, so resolve it before scheduling the build.

Network path from the backend

The Backstage backend, not the browser, calls GitHub to read catalog files and receive events. Confirm outbound HTTPS from the backend host to the GitHub API endpoint, and inbound HTTPS from GitHub to the backend if you plan to use webhooks. Ask your network team about proxies, egress allow-lists and any firewall rules that inspect TLS. Test reachability from the same runtime the backend will use.

Secret store for credentials

Keep the GitHub App private key, client secret or personal access token in a secret store that your platform controls, and inject it into the backend as environment configuration at runtime. Do not commit credentials to the app repository or place them in a catalog file. Agree on who can read, rotate and revoke these values, and how a leaked credential will be replaced before go-live.

Configuring GitHub discovery and org import in sequence

This sequence connects Backstage to GitHub in a fixed order, so each layer is verified before the next one depends on it. The result is a catalog that discovers catalog-info files from chosen repositories and imports members and teams as users and groups.

  1. Choose and register the GitHub credential

    Decide between a GitHub App and a personal access token before editing any configuration. A GitHub App is the usual choice for an organization-wide setup because it is installed on the organization and grants scoped, revocable access. A token is simpler for a proof of concept but ties access to one person. Register the App or create the token under an account your organization controls, store the App private key and webhook secret in your secrets store, and confirm that the installation covers the organization you plan to scan. Done when you can authenticate to the GitHub API with the credential from the Backstage backend host.

  2. Add the GitHub integration host

    In the backend configuration, add an integrations.github entry for github.com or your GitHub Enterprise host, referencing the App settings or token through environment variables rather than literal values. Backstage uses this entry to fetch files and build URLs for every later provider, so a mistake here affects discovery and org import. Verification: start the backend and check the log for a clean startup with no integration configuration errors, then confirm the credential resolves for the host you configured.

  3. Set repository discovery filters

    Before enabling discovery, decide which organizations, repositories, branches and paths the provider may read. Scope the search to the organization, limit it to the default branch, and restrict the catalog file path, typically catalog-info.yaml at the repository root, so forks, archived repositories and experiments are not ingested by accident. Write these filters down as the agreed scope for your review. Verification: the filter values are reviewed against a list of repositories your platform team expects to appear, and any surprises are resolved in the configuration before the provider runs.

  4. Add the repository discovery provider

    Register the GitHub discovery entity provider in the catalog configuration, using the scoped organization and path settings from the previous step, and add the matching catalog module to the backend. Discovery reads repositories that contain catalog descriptors and creates Location entities that the catalog processes into components, APIs and systems. Verification: restart the backend and look for log lines from the GitHub discovery provider reporting the repositories it scanned. A repository with a valid descriptor should produce a Location entry visible in the catalog.

  5. Add the GitHub org entity provider

    Add the GitHub organization provider so members and teams become User and Group entities. Map GitHub teams to Group entities under the namespace you chose, and confirm that the credential has read access to organization members and teams. Team membership is what makes catalog ownership fields resolve to real people, so check a few known teams in the output. Verification: after the next scheduled run, search the catalog for one team you know exists and confirm its member count and parent group match GitHub. If members are missing, check the App permissions for organization members and teams first.

  6. Confirm entities appear in the catalog

    Open the catalog and compare what appears with the filter scope you wrote down. Check that catalog-info files from in-scope repositories created components with the expected owner and system, that users and groups match the GitHub organization, and that out-of-scope repositories are absent. Count entities by kind and record the counts as your baseline. Verification: the baseline matches your expected inventory, and any entity without an owner or with an unresolved reference is traced to its descriptor or to the org import before you go further.

  7. Note refresh behavior before adding webhooks

    Until webhooks are configured, the catalog learns about changes on a schedule. Each provider runs on the schedule you set in configuration, so a new descriptor, a renamed repository or a team change appears only after the next run. Record the schedule for each provider, decide whether that delay is acceptable for ownership and discovery, and tell repository owners how long they should expect to wait. Confirm the current webhook options and event handling in the Backstage documentation for your release before you change the design, since event support is configured separately. Done when the schedules and expected delays are written down for the team.

How GitHub members, teams and repositories map to Backstage entities

This table shows which GitHub object becomes which Backstage entity, the key each one uses, and the fields that must agree for ownership to resolve. Read it row by row before you write any catalog files, because a mismatch in one field usually shows up later as an entity with no owner. The main takeaway is that the GitHub login, team slug and organization prefix must be chosen once and kept consistent across every catalog file.

GitHub objectBackstage entity and keyFields that must agreeCommon failure to check
Organization memberUser entity, named by GitHub loginmetadata.name matches the login used in spec.memberOf references and the sign-in resolverDisplay names or emails used as names, so owners never match the user record
Organization teamGroup entity of type team, named by team slugspec.parent points to the parent group and spec.children lists child teams, if nestedTeam names with spaces or capitals used as keys, which break references from other files
Team membershipspec.members on the Group, and spec.memberOf on the UserEach member login appears in both places, or the relation is built by the GitHub org data sourceMembers added on GitHub but absent from the catalog until the next scheduled ingestion
Repository with catalog-info fileComponent, API, Resource or System, named in catalog-info.yamlmetadata.name is unique within its namespace, and spec.owner names an existing Group or UserTwo repositories declaring the same component name, so one silently overwrites the other
Owner reference on a componentspec.owner on the Component, set to a team slug or user loginThe reference uses the same kind and namespace as the target entity, usually group:default/team-slugOwner written as a team display name, leaving the component orphaned in the catalog
Organization name prefixAnnotations and namespaces, for example github.com/project-slug set to org/repoThe org segment matches the exact GitHub organization name, including case where your setup is sensitiveRepositories moved or renamed on GitHub, so discovery and annotations point to stale paths
Repository topic or type metadatametadata.tags and spec.type on the ComponentValues use the lowercase vocabulary your portal filters on, such as service or libraryFree-text types that defeat catalog filters and ownership reports

Why webhook-driven updates beat polling for large GitHub estates

Webhook-driven updates are the better default for a large GitHub estate because they make catalog changes visible within moments of a push, while scheduled polling only notices changes at the next run. Polling also spends API quota on repositories that have not changed. Across hundreds of repositories, a full scan on every cycle can consume a large share of your rate limit before any real work happens, and the cost grows with every repository you add. A webhook sends a request only when something relevant happens, so the catalog stays current without spending calls on silence.

Webhooks trade that efficiency for new failure modes. A delivery can fail when the Backstage backend is unreachable, when a firewall or ingress rule blocks GitHub's source addresses, or when the receiver rejects a payload. GitHub records delivery attempts, so the platform team should confirm which event types the GitHub App subscribes to (for push and repository changes), that the webhook secret in the App settings matches the value Backstage uses to verify signatures, and that the endpoint is reachable from GitHub over HTTPS at the path the Backstage integration expects. Test each of these with a real push to a sample repository before relying on them, and confirm the exact event names and endpoint path against the current Backstage GitHub integration documentation rather than from memory.

Because a dropped delivery leaves the catalog silently stale, plan a scheduled reconciliation pass as a backstop. Run a slower discovery on a fixed interval to catch missed events, deleted repositories and catalog files renamed outside the normal path. Size that interval to your tolerance for drift and your remaining API quota, not to the webhook volume. Ask any implementation partner to show how missed deliveries are detected, how the reconciliation run is logged, and how alerts reach the team that owns the portal.

Securing the GitHub credential, webhook and org data

The GitHub connection gives Backstage read access to source repositories and organization records, so its scope decides what the portal can see and change. The cards below cover the credential, the webhook, the repositories in scope and the consistency between sign-in and catalog ownership.

Scope the GitHub App to read-only needs

Grant the Backstage GitHub App only the repository and organization permissions that catalog discovery and org ingestion require, and review them against the integration docs before install. Scaffolder publishing needs write access, so keep that in a separate app or installation if you do not want the catalog reader to create repositories. Ask your team to list every permission and the reason for each one. Re-check the list after each Backstage upgrade.

Limit installations to chosen repositories

When you install the app, select specific repositories or organizations rather than all repositories. Discovery follows what the installation can see, so a broad install makes every private repository a catalog candidate. Pair this with catalog file patterns and filters so that only repositories that carry a descriptor are registered.

Store and rotate the app private key

The app private key and any personal access tokens belong in a secrets manager or Kubernetes secret, injected as environment variables, never in app-config.yaml committed to Git. Document who can read the key, where each copy lives and the rotation procedure, and rehearse a rotation in a non-production instance. Your security team should confirm the storage model against your own policy.

Validate webhook signatures

Set a webhook secret on the GitHub App and configure the Backstage backend to verify the signature on each delivery. Reject deliveries that fail validation and alert on repeated failures, since they may indicate a misconfigured or spoofed sender. Keep the secret out of the frontend bundle and rotate it with the same process as other credentials.

Keep sign-in and org data aligned

The authentication docs advise sign-in resolvers that map every provider to the same identity, and advise against guest access in production. Make the GitHub user that signs in resolve to the same catalog user that org ingestion creates, so ownership refs do not split one person into two entities. Test this with a real account from each team before go-live.

Audit access and removals

Record which installation, repositories and groups were imported and when, and review them on a fixed schedule. When a member leaves GitHub or a team is removed, confirm the catalog user and group entities are removed or orphaned on the same schedule, so departed staff do not keep ownership of services.

Common GitHub integration failures and how to fix them

This table lists the failures teams most often hit when connecting Backstage to GitHub or GitHub Enterprise, with the likely cause and the fix for each. Use the symptom column to find the row that matches what you see, then check the cause before changing credentials or configuration. Most failures trace back to a path or branch filter, a host URL, or an identity mismatch rather than to Backstage itself.

SymptomLikely causeFix
Catalog entities missing after discoveryPath or branch filter in the GitHub discovery configuration does not match where catalog-info.yaml lives, or the file is on a non-default branch the filter skipsConfirm the catalog file path and branch name in the repository, then adjust the discovery filter and run a refresh on one repository to verify it is picked up
Authentication errors or entities stop refreshingGitHub App installation token expired, personal access token was revoked or expired, or the credential lacks read access to the target repositoriesReissue or regenerate the credential, grant read access to the repositories in scope, and confirm the GitHub App is installed on the right organization
Discovery works for some organizations but not othersCredential is scoped to one organization or installation, so repositories in other organizations return no resultsInstall the GitHub App on every organization in scope or issue credentials for each one, then re-run discovery
Requests fail against a GitHub Enterprise hostHost URL in the integration configuration differs from the URL users and API calls actually use, such as a missing API path or a mismatched hostnameCopy the exact host and API endpoint from your GitHub Enterprise setup, update the integration entry, and test the connection before re-enabling discovery
Catalog updates arrive late or not at allWebhook delivery failed on the GitHub side, the receiver URL is unreachable from GitHub, or the secret does not matchCheck recent deliveries in the GitHub webhook settings, confirm the endpoint is reachable from GitHub, and verify the shared secret on both sides
Discovery runs slowly or stops partwayAPI rate limits reached because scheduled discovery polls many repositories at a short interval across installationsLengthen the polling schedule, narrow the discovery filter, and rely on webhooks for routine changes so polling covers only gaps
Same person appears as two usersSign-in identity and imported GitHub user do not resolve to the same catalog user because the username or email differs across sourcesAlign sign-in resolvers and user identifiers across providers, remove the duplicate entity, and reconcile ownership references in the catalog
Ownership shows a user or group that does not existTeam or member import used a different organization slug or identifier than the owner reference in catalog filesMatch owner references to the imported group names, correct the descriptors, and confirm the import covers the organization that owns the repository

How to test the GitHub integration before ownership depends on it

Before any team relies on Backstage to show who owns a service, run a test plan against a small, known slice of GitHub. Start with a canary organization or a fixed set of repositories that you control, and write down the expected entity count for each catalog file location before the first import. Compare what the portal shows against that list, not against what looks plausible. Any extra entity usually means a discovery pattern is too broad, and any missing entity usually means a catalog file is malformed, on the wrong branch, or outside the path the integration reads. Confirm the exact discovery settings and file locations against your own Backstage configuration and the current GitHub integration documentation, since those settings are what the test is checking.

Next, test the update path rather than only the first import. Push a change to a catalog file in a canary repository, such as a description or an owner reference, and confirm that the entity changes in the portal without a manual refresh. This verifies that the webhook delivery reaches Backstage and that the event is processed. Then test a failure case: stop or misconfigure the webhook receiver for a short window, push another change, and confirm how the portal recovers. Your team should know whether a missed event is picked up later, and by which mechanism, before it depends on the portal for ownership questions. Remove a canary team from the GitHub organization and verify that the corresponding group and its membership change in the catalog, since stale team membership is a common source of incorrect ownership.

Finally, check how orphaned entities are handled. Delete or rename a canary repository and confirm whether its entity is removed, marked as orphaned, or left in place, and whether that behavior matches the policy you intend to apply. Define acceptance criteria in your own scope before running these tests: the expected entity counts, the maximum acceptable delay for a webhook-driven change, the required outcome for a removed team, and who reviews orphaned entities. Record the results so the same tests can be repeated after credential rotation or a Backstage upgrade. Ownership should only depend on the integration once every criterion has passed on the canary set and the failure cases have been understood.

Questions teams ask before connecting Backstage to GitHub

What drives the cost of connecting Backstage to GitHub?

The main drivers are how many GitHub organizations and repositories the catalog must read, how many catalog descriptor files already exist and how consistent they are, whether you run GitHub.com or GitHub Enterprise Server, and how much identity mapping is needed between GitHub accounts and your directory. Each added organization adds permission and installation decisions. One-time work covers design, app registration, configuration, testing and handover. Recurring work is the team that operates Backstage and the upgrades that touch the integration. Backstage itself is open source under the Apache License 2.0, so the software carries no license fee. When you request a quote, ask for discovery, credentials, webhook setup and user ingestion to be priced as separate line items.

How long does a Backstage GitHub integration take?

Duration follows scope. A single organization with an existing Backstage instance and agreed catalog file conventions is the smallest case. Adding several organizations, GitHub Enterprise Server, group and team import, or webhook handling each adds design and test work. Time also depends on how quickly a GitHub owner approves the app and how many repositories still need catalog files written. Ask for milestones in the written scope: credentials and discovery working in staging, webhook verification, user ingestion, then production cutover. Each milestone gives your team a clear point to review before the next one starts.

What access does our team need to provide for the GitHub integration?

The work needs three things from your side:

  • GitHub owner or organization admin access to register and install a GitHub App, or a token issued by an account with the right permissions for each organization.
  • A secret store for the app private key, the webhook secret and any client secrets, so credentials stay out of configuration files and repositories.
  • A network path from the Backstage backend to the GitHub API endpoint, plus inbound HTTPS from GitHub to Backstage if you use push webhooks.

You also need a named owner who approves permission scopes and can answer questions about repository naming and catalog file locations during the build.

Can our internal team connect Backstage to GitHub without a partner?

Yes, a team with Node.js, Backstage and GitHub administration experience can complete the integration, because it uses documented configuration. The harder parts are design decisions rather than syntax: choosing a GitHub App or token credentials, setting the minimum permission scope, deciding how GitHub identities resolve to catalog users, and securing the webhook endpoint. Teams without recent experience with these decisions often spend most of their time on them. Ask any partner to show which decisions they will document and which they expect you to make. Plan for ownership after launch as well, because Backstage packages upgrade together and the integration must keep working through each upgrade.

Do users have to sign in with GitHub to use Backstage?

No. Backstage ships 19 built-in authentication providers, including GitHub, GitLab, Google, Azure, Okta and generic OIDC, so reading catalog files from GitHub is a separate setup from signing users in. Discovery needs credentials that the Backstage backend uses to read repositories. Sign-in needs an auth provider. Many organizations use GitHub for both, but the Backstage authentication documentation advises configuring sign-in resolvers so every provider resolves to the same identity, and does not recommend guest access in production. Decide which system is authoritative for people and team ownership before you configure either one.

Does GitHub Enterprise Server need extra work for Backstage?

Usually yes, mostly in configuration and testing. The host and API base URL must point to your server, and the Backstage backend must trust the certificate authority that signed your internal certificate. The backend also has to reach the server over your network, which may involve proxies or firewall rules that were not designed for it. Confirm the GitHub Enterprise Server version you run and test discovery from the same runtime network where Backstage will run, not from a laptop. Also confirm how your server handles API rate limits for the number of repositories you plan to scan, since large discovery runs are the usual source of throttling.

Should Backstage use webhooks or polling for GitHub catalog updates?

Use webhooks where your deployment can receive them, and keep a scheduled reconciliation as a safety net. Webhooks reduce the delay between a commit to a catalog file and the catalog update, and they reduce repeated API reads across many repositories. They require an inbound HTTPS endpoint reachable from GitHub, verification of the shared webhook secret on every delivery, and a plan for deliveries that fail or arrive late. Polling is simpler to operate behind a restrictive network but consumes more API calls as the repository count grows. Ask your team to confirm which endpoints GitHub can reach from its network, then test a deleted or renamed repository so orphaned entities are handled as designed.

How DeployOpen scopes and delivers a Backstage GitHub integration

DeployOpen plans, implements, tests, documents and supports self-hosted open-source platforms inside your own infrastructure, including Backstage. For a GitHub integration, we agree the credential model, discovery scope and identity import in writing before any configuration changes, then deliver a working connection your team can operate.

How we scope

  • Confirm whether you run github.com, GitHub Enterprise Cloud or GitHub Enterprise Server, and where Backstage will be hosted.
  • Decide between a GitHub App and token credentials, with the owners, permissions and rotation process for each option.
  • Define which organizations, repositories and branches are scanned for catalog-info files, and which are excluded.

How we build

  • Configure the GitHub integration and catalog discovery in a non-production Backstage instance first, with secrets kept out of configuration files.
  • Set up member and team import as users and groups, and align them with the sign-in resolver so ownership matches identity.
  • Enable webhook-driven updates and test that pushes, renames and deletions reach the catalog without relying on polling alone.

How we hand over

  • Document the credential setup, permission scopes, discovery filters and webhook endpoints as configuration your team can review.
  • Walk through test results for catalog discovery, group import and webhook handling, including known edge cases we found.
  • Provide a runbook for rotating credentials, adding organizations and diagnosing a catalog entity that fails to appear.

How we support

  • Ongoing support, upgrades and continuous testing are available as a retainer, scoped in writing after the initial delivery.
  • Plan the GitHub integration changes that accompany Backstage version bumps, which move all @backstage packages together.
  • Confirm with your GitHub administrators and security team who approves app installation and permission changes over time.

Talk to our team.

Tell us what you're working on, whether it's a deployment, an audit, a security test or a cyber range. You'll speak with an engineer who can help you scope it.

  • 30-minute call: free, with no obligation.
  • NDA on request: we can sign before you share details.
  • Clear next steps: a scope and plan after the call.