How Backstage creates GitHub repositories from a template
Platform teams usually want every new service to arrive with the right repository, branch protections and catalog entry already in place, so developers do not have to set these up by hand. In Backstage, the supported way to do this is the scaffolder GitHub action module. When a template runs, the scaffolder calls the GitHub API to create the repository, apply its settings and publish the initial content, and it then hands the result to the catalog. This section covers the integration itself: how the module authenticates, which GitHub deployment it talks to, and what must be in place before the first template run succeeds. The same pattern applies to GitHub Enterprise, with the host and API endpoint pointed at your own instance.
The first decision is how the scaffolder authenticates to GitHub. The module can use a GitHub App installation or a personal access token, and the two behave differently. A GitHub App acts as its own identity, can be scoped to the organizations and repositories it needs, and its permissions are granted explicitly when the app is installed. A token is simpler to set up but is tied to a user or service account, so its access follows that account and its lifecycle becomes your responsibility. Confirm the exact permissions each option needs against the current Backstage GitHub integration documentation and your GitHub Enterprise version, because required scopes can change between Backstage releases. Record which identity owns the credential, who can rotate it, and where it is stored, since a single credential will create repositories across the whole organization.
Before you rely on the integration, check three things in a non-production organization: that the credential can create repositories in the target organization, that the repository settings and branch protection rules you expect are applied on creation, and that the new component is registered in the catalog with a usable link back to GitHub. Confirm whether your GitHub plan supports every protection setting your template applies, since some options depend on the plan or the repository visibility. Also confirm how your Backstage instance reads the GitHub host configuration for Enterprise Server, because a mismatch in the host or API URL usually shows up as failed repository creation rather than a clear configuration error. Plan the credential and the test organization before writing the template steps, so the template is built against a setup you have already verified.
What you need before connecting Backstage to GitHub
Repository creation from a template depends on a Backstage version you can keep current, a GitHub target you control, a credential that can create repositories, and a production deployment that can reach GitHub. Work through these cards before you write the GitHub action step, so the first template run tests the template rather than the environment.
Backstage version and Node.js support
Pick a Backstage release line before you start. The main line ships monthly and the next line ships weekly, so choose the line your team can upgrade on a predictable schedule. Backstage supports two adjacent even-numbered Node.js releases, which as of Backstage 1.46.0 are Node.js 22 and 24. Check the current versioning policy for the Node.js pair in force on the day you build, and align your container image and CI runners with it.
GitHub organization or Enterprise Server host
Decide which GitHub target receives new repositories: a github.com organization or a GitHub Enterprise Server instance. The target determines the API base URL, the owner names templates will use, and whether repositories land in one organization or several. Confirm the GitHub Enterprise API URL for your instance and the organization naming rules with your GitHub administrators before you write any template parameters that reference them.
GitHub App or token credentials
The scaffolder authenticates to GitHub with either a GitHub App installation or a personal or fine-grained token. A GitHub App is usually the better fit for a shared platform because its permissions are scoped to installed repositories and its tokens are short-lived, while a token ties actions to one person's account. Ask GitHub administrators which credential model your organization permits, and store the secret in your secrets manager rather than in the repository that holds your app configuration.
Repository creation permissions
The credential must hold the permissions needed to create repositories, set topics and settings, and apply branch protection in the target organization. Permission names and scopes change between GitHub features and between github.com and Enterprise Server, so confirm the exact list against the current documentation for the action module you plan to use. Test the credential against a sandbox organization first, and record which permissions the platform team granted and why.
Outbound access to the GitHub API
Backstage runs the scaffolder from its backend, so the backend host, not the developer's browser, calls the GitHub API. Confirm that your network allows outbound HTTPS from the backend to the GitHub API endpoint for your target, and that any egress proxy, firewall rule or DNS entry for an internal Enterprise Server host is in place. Blocked calls usually appear as failed scaffolder steps during the first run, so verify connectivity from the backend pod or host before testing a template.
PostgreSQL-backed production deployment
Run the template task history on a production deployment that uses PostgreSQL, not the SQLite setup used for local development. The architecture overview describes each backend plugin getting its own logical database through Knex, so plan database provisioning, backups and access before go-live. A repository created by a template that fails halfway is hard to reconcile without reliable task records, so confirm where those records live and who can read them.
Configuring the GitHub action module step by step
This sequence takes a Backstage instance from no GitHub connection to a template that creates a repository, applies its settings and registers the result in the catalog. Each step closes with a check so problems surface before any developer runs a template.
Choose the GitHub App or token credential
A platform engineer decides how Backstage will authenticate to GitHub or GitHub Enterprise. A GitHub App is generally the better fit for an organization because its permissions are scoped to installed organizations and its tokens are short-lived, while a personal access token ties actions to one person's account. Confirm the current permission names and token behavior in GitHub's own documentation for your edition before choosing. The step is complete when the team has written down the credential type, the target organization and the repository permissions the template needs, such as creating repositories and managing settings.
Register the GitHub App or create the token
Someone with owner rights on the GitHub organization registers the GitHub App, sets its repository and organization permissions, generates a private key and installs the app on the target organization. If you use a token instead, create it with the minimum scopes the publish action needs and record which account owns it. Check the result by confirming the app appears under the organization's installed apps with the expected repository access, or by calling the GitHub API with the token and receiving the authenticated user or app details back.
Store credentials as secrets
Place the App ID, installation details, private key or token in the secret store your Backstage deployment reads at runtime, such as environment variables injected from a vault or Kubernetes secret. Keep credentials out of the template repository and out of any committed configuration file. The step is done when the Backstage backend starts with the secret references resolved and no credential value appears in the logs or in the catalog. Ask your security team to confirm the storage and rotation approach you chose.
Add the integration host to Backstage configuration
In the Backstage app configuration, add a GitHub integration entry for github.com or your GitHub Enterprise host, referencing the secret values through the configuration keys documented for the GitHub integration. This is the entry the publish action uses to find the host and its credentials. Validate the configuration with the Backstage configuration check before starting the backend. The step is complete when the backend starts cleanly and the integration reports the host as configured.
Install the GitHub action module
A backend developer adds the GitHub scaffolder action module to the Backstage backend package, registers it in the backend index file and rebuilds the backend. The module provides the publish action that creates repositories and applies settings. Confirm the package version matches your Backstage release line, since the @backstage packages move together. The step is done when the backend log shows the publish action among the registered scaffolder actions, which you can also confirm in the actions listing of the scaffolder.
Reference the publish action in a template
A template author adds a publish step to the template.yaml file that names the GitHub publish action, sets the repository name and owner from the form parameters, and declares repository settings such as visibility, default branch, topics, and whether the repository is created with a README or from a skeleton. Add the branch protection options only as the action version supports them, and verify each option against the action's documentation. The step is complete when the template passes schema validation and the publish step lists every setting the team expects.
Register the result in the catalog
Add a register step after publish that uses the repository URL output to create a catalog-info.yaml file in the new repository, then registers it as a location so the new component appears in the software catalog. Confirm the catalog entity path matches what your catalog provider expects. The step is done when the registered location is listed in the catalog with the owner and lifecycle values from the template parameters.
Run a test creation against a sandbox organization
Run the template end to end against a non-production GitHub organization or a test namespace, using a sample service name that you delete afterward. Check that the repository exists with the expected visibility, default branch and topics, that branch protection is applied as configured, that the catalog entity is registered and that the output links open the right pages. Review the task log for warnings. The step is complete when a clean run produces the expected repository and catalog entity, and any gaps are recorded as fixes before production templates use this configuration.
GitHub App versus token credentials
A GitHub App is the usual choice when repositories will be created across an organization on a regular basis. The app is registered once, installed on the organization or on selected repositories, and granted only the permissions the scaffolder needs. Backstage then authenticates as the app installation rather than as a person, so repository creation no longer depends on one employee remaining in the company.
- Installation-scoped permissions: You grant repository administration and contents permissions at the installation level, and you can limit the installation to specific organizations or repositories.
- Ownership by the platform team: The app belongs to the organization, so the platform team can rotate its private key without asking an individual to reissue anything.
- Traceable actions: Repositories created by the app show the app as the actor, which makes the creation path easier to explain during an access review.
- Setup effort: Registration, installation and private key storage are one-time tasks, but they require a GitHub organization owner to approve the app.
- Dependency on the app lifecycle: If the app is deleted or its installation is removed, template runs fail until the configuration is restored.
Confirm the current permission names and installation steps against GitHub's own documentation for GitHub Apps before you configure the scaffolder.
A personal access token or a service account token is simpler to set up and suits small teams, trial environments and early template development. The token is created once, stored as a secret and passed to the GitHub action module. The effort is low, but the credential is tied to whoever created it, so its reach and its lifespan depend on that person's account and role.
- Fast to start: A token can be created and placed in configuration in minutes, which helps during template prototyping.
- Person-bound ownership: When the creator leaves or changes roles, the token may stop working or may need to be replaced in every environment that uses it.
- Broad scope risk: Tokens often carry more repository permissions than a single template requires, so least privilege is harder to enforce.
- Manual rotation: Rotation depends on someone remembering to reissue the token and update Backstage, which makes expiry a common cause of failed runs.
- Weaker attribution: Audit records point to the individual account, which can blur the line between a person's action and an automated process.
If you use a token outside a test environment, confirm with your security team which token type and expiry rules your GitHub organization accepts.
Least privilege is the main reason to prefer an app for production. A GitHub App requests specific permissions for specific resources, while a token usually inherits the full reach of the account that issued it. The difference matters when a scaffolder action or a plugin is compromised, because the blast radius of the credential determines what an attacker can change.
- Permission boundaries: An app can be restricted to repository creation and the minimum content permissions, while a token may be able to administer many repositories.
- Key rotation: App private keys can be rotated on a schedule owned by the platform team, and the old key can be revoked after the new one is deployed.
- Token expiry: Tokens can be set to expire, but each expiry requires a coordinated update across every Backstage environment that depends on it.
- Secret handling: Whichever credential you choose, store it in your secret manager and keep it out of template files and version control.
- Review cadence: Record who approved each permission and when it was last reviewed, so that the grant can be traced during an audit.
Ask your GitHub administrators which rotation and approval processes apply to apps and tokens in your organization.
Ownership decides who answers for the credential when something breaks or when an auditor asks how repositories were created. An app is owned by the organization and administered by a small group of owners. A token belongs to a person, and that person's access changes are reflected in what the scaffolder can do. Either way, the audit trail should show that a template run created the repository and which template produced it.
- Named owner: Assign an accountable team to the app or to each token, with a documented backup owner.
- Change records: Keep records of installation changes, permission changes and key rotations in your change management system.
- Template attribution: Pair the repository creation event with the template entity and the run identifier in Backstage so you can trace each repository to its origin.
- Offboarding: Include the credential in your offboarding checklist, since a departing employee's token can silently stop working or remain active.
- Separation of duties: Decide whether the team that approves templates is the same team that controls the credential.
Confirm with your auditors which evidence they expect for automated actors before you finalize the design.
Mapping template parameters to repository settings
This table maps the common template parameters to the GitHub action inputs they usually feed and to the catalog descriptor fields they populate. Read each row as a checklist: confirm the input names and required status against the GitHub action module version your Backstage release ships, because these inputs change between releases. The main takeaway is that owner, visibility and the catalog fields are the values teams most often get wrong, so validate them in the parameter form, not after the repository exists.
| Template parameter | Typical action input or setting | Required or optional | Where it appears in the catalog |
|---|---|---|---|
| Repository owner or organization | repoUrl host and owner segment, set in the publish step | Required, confirm against the module's current input schema | Used for the component's source location annotation |
| Repository name | Part of repoUrl, often built from the component name parameter | Required, validate allowed characters in the form | Usually matches metadata.name in catalog-info.yaml |
| Visibility (private, internal, public) | Repository visibility setting passed to the publish action | Optional in most templates, confirm default and allowed values | Not stored in the descriptor; record it in a template parameter review |
| Topics | Repository topics list passed to the action | Optional, confirm the input exists in your module version | Can mirror tags on the component entity |
| Default branch | Default branch name passed to the action or set after creation | Optional, confirm whether the action applies it at creation | Not stored in the descriptor; confirm branch protection targets it |
| Component owner | Written into the descriptor file by the fetch step | Required for registration, use a group or user reference | spec.owner in catalog-info.yaml |
| System | Written into the descriptor file by the fetch step | Required if your model uses systems, optional otherwise | spec.system in catalog-info.yaml |
| Lifecycle and type | Written into the descriptor file by the fetch step | Required in the descriptor, usually fixed by the template | spec.lifecycle and spec.type in catalog-info.yaml |
Setting branch protection and repository defaults at creation
Decide up front which repository settings the template should apply at creation and which must be handled afterwards, because the GitHub action module you use determines what a single scaffolder run can set. Repository-level options such as visibility, default branch name, merge method rules and whether issues or wiki are enabled are typically the easiest to standardize in the template. Branch protection is different: the rule set you need, including required pull request reviews, required status checks and whether administrators are bound by the rules, depends on the exact options the module exposes and on the permissions of the credential that runs it. Confirm each option name and its behavior against the documentation for the GitHub action module in your Backstage version before you write the template, and record which settings are applied by the action and which are applied by a later step.
The platform team owns three decisions that shape these defaults. First, how many approving reviews a new repository requires and whether code owner review is mandatory. Second, which status checks must pass before merge, and whether those checks exist yet on a brand-new repository, since a required check that never reports can block every pull request. Third, whether repository administrators are subject to the protection rules. Enforcing rules on administrators is stricter but can block an emergency fix if no break-glass path is defined. Write these choices down as platform standards, and give template authors one default set rather than letting each template invent its own.
Do not assume protection was applied because the scaffolder run succeeded. A run can report success while a rule was skipped, silently ignored for a branch that did not yet exist, or overridden by an organization ruleset. After each run, or in a periodic check, read the branch protection or ruleset state through the GitHub API or the GitHub interface and compare it with the standard. Include this check in your dry run and test environment, and make the template output link to the new repository's settings so reviewers can confirm it. Plan for drift as well, since a protection rule changed by hand after creation will not be restored by the template.
Securing the GitHub credentials and scaffolder runs
The scaffolder acts on GitHub with whatever credentials it holds, so every repository it creates is only as well controlled as the app or token behind it. The cards below cover the credential choice, its permissions, where secrets live, who may run templates, what gets logged, and how credentials are rotated.
Scope the GitHub App permissions
Grant the integration only the repository and organization permissions that template actions need, such as creating repositories and setting branch protection, and nothing broader. Review the list against each action the templates call. A broad app installed on every organization is the most common way a portal ends up with more reach than its templates require. Confirm the installation scope with your GitHub administrators before the first template goes live.
Keep secrets out of app-config
Store the GitHub App private key, client secret and any token in a secret manager or environment variables injected at runtime, and reference them from configuration instead of writing values into app-config.yaml or the repository that holds it. Configuration files are often copied into images, tickets and support bundles. Check that no credential appears in committed config, container images or logs.
Restrict who runs repository templates
Any signed-in user can run a template unless you restrict it, so a template that creates repositories in a production organization needs an explicit allow list. Use the permission framework to limit the template and the scaffolder actions it calls to the teams that own the process. Also decide who may register new Template entities, because a registered template defines what the scaffolder will do with your credentials.
Review the scaffolder threat model
The Backstage hardening guidance identifies scaffolder and proxy risks that matter here, because template steps run server-side with the credentials the portal holds. Work through them before exposing repository creation, and record which template parameters can influence repository names, owners or visibility. Treat any free-text field that reaches an action as untrusted input and validate it in the template schema.
Audit repository creation
Each scaffolder run records a task with its steps, parameters and outcome, but the portal's task log is not a substitute for GitHub's own audit trail. Confirm which events your GitHub organization records for app installations and repository creation, and forward both sources to your log platform. Ask who can read task logs in the portal, since parameters may include sensitive project details.
Rotate GitHub credentials on a schedule
Set a rotation procedure for the GitHub App private key and any personal access token, with an owner, a schedule and a tested cutover that keeps running templates working. Rotate immediately after staff changes or any suspected exposure. Confirm with GitHub how key and secret rotation is performed for your app type, and rehearse the change in a non-production portal before rotating production.
Common GitHub repository creation failures and fixes
This table lists the failures teams most often hit when a Backstage template creates a GitHub repository, with the likely cause and the first fix for each. Work down the rows in order, since authentication and installation problems hide the others. Confirm each cause against your own GitHub organization and Backstage configuration before changing anything.
| Failure | Likely cause | First fix |
|---|---|---|
| 401 or bad credentials from the publish step | The GitHub App private key, App ID or client credentials in the Backstage configuration are wrong, or the token is expired or revoked | Check the App ID and private key values in the integrations config and confirm the secret is loaded by the backend process that runs the scaffolder |
| 404 when reading the target organization | The GitHub App is not installed on the target organization, or it was installed on a different account | Install the App on the organization that will own the repository and grant it access to the repositories it needs |
| 403 when creating a repository | The App or token lacks repository administration or organization member permissions, or the organization restricts repository creation for apps | Grant the App the required repository permissions, reinstall or accept the updated permissions, and check the organization's repository creation policy |
| 422 saying the repository name already exists | A repository with the same name already exists in the organization, including archived or deleted-but-retained repositories | Change the name parameter in the template or confirm the existing repository is not in use before choosing a different name |
| 429 or secondary rate limit errors | Many template runs or retries in a short window exhaust GitHub API quota for the App or token | Wait for the reset time in the response headers, then retry the failed task rather than rerunning the whole template |
| Requests fail on a GitHub Enterprise instance | The integration entry points at github.com or the wrong API host instead of your Enterprise API base URL | Set the host and API base URL in the GitHub integration config to your GitHub Enterprise server, then confirm the App was created on that instance |
| Repository is created but the component is missing from the catalog | The template did not register the new catalog-info.yaml, the location was not added, or the catalog processor has not refreshed yet | Check the register step output, confirm the catalog-info.yaml path exists on the default branch, and trigger a refresh on the new location |
| Repository exists with default settings and no branch protection | The template omitted the settings or branch protection parameters, or the token lacks administration permission on the repository | Add the protection settings to the publish step and confirm the App has administration permission before the next test run |
Questions teams ask before creating GitHub repositories from Backstage
What drives the cost of creating GitHub repositories from Backstage templates?
The main cost drivers are template complexity, the number of GitHub hosts you need to support, the governance rules you must enforce, and the amount of testing required. A template that only creates a repository with a README is far cheaper to build than one that also sets branch protection, creates teams, adds secrets, and registers the component in the catalog. Each additional GitHub Enterprise Server instance adds its own credentials, network path and test cases. Ask any partner for a quote that lists each template, each host, each rule and the test plan separately, so you can see which items drive the total. Backstage itself is free to license, so the spend is on people and environments, not on the framework.
Can our team create GitHub repositories from Backstage templates without outside help?
Yes, a capable platform team can do this with the Backstage documentation and a dedicated test GitHub organization. The GitHub action module and the scaffolder documentation cover the basic flow. Outside help adds the most value in two places: designing credentials, meaning whether a GitHub App or a token fits each use case, and turning your repository policies into template steps that hold up under review. If your team has not run a GitHub App before, or has no one who has reviewed GitHub permission scopes, that is the part to plan carefully or delegate.
How long does a GitHub repository template project take?
Duration depends on scope and environment more than on the template format itself. The variables that matter most are how many templates you are publishing, whether you run github.com, GitHub Enterprise Cloud or GitHub Enterprise Server, how quickly your GitHub administrators can approve a GitHub App, and how long your security review of permissions takes. Teams with an existing test organization and a clear list of repository standards tend to move faster than teams that must first agree on naming, ownership and branch rules. Ask for a timeline in the written scope, with the dependencies on your administrators listed as client tasks.
What do we need to provide before the work starts?
You need GitHub administrator access, or a named administrator who can install a GitHub App and grant it organization permissions. You also need a test GitHub organization where templates can create repositories without touching production projects. Each template needs a named owner who can approve parameters, default settings and changes. Finally, provide your repository standards, such as naming rules, required status checks, branch protection expectations and team structure. Without these, the template design stalls at the points where choices must be made.
Does Backstage licensing add cost when we publish to GitHub?
Backstage is released under the Apache License 2.0 (SPDX: Apache-2.0), and the project itself does not offer a paid edition. The license cost is therefore zero, but you should still plan for the costs that come with self-hosting: infrastructure, operations, upgrades and the people who maintain templates. GitHub's own licensing and seat costs are separate and depend on your GitHub plan, so confirm those with your GitHub account team. Any third-party plugins you add should have their own license reviewed before installation.
Which credential should we use: a GitHub App or a personal access token?
For shared organizational templates, a GitHub App is usually the better fit because its permissions are scoped to the installed organization and its activity is not tied to one person. A personal access token is simpler to start with but ties actions to an individual account, which complicates offboarding and audit. Confirm the current permission model and installation steps in the Backstage GitHub integration documentation and with your GitHub administrators before choosing. Document the decision so reviewers can see why each template uses the credential it does.
What goes wrong most often with GitHub repository creation from templates?
The most common problems are insufficient GitHub App permissions, templates that fail partway through and leave a repository without its settings, and branch protection rules that are applied before the first commit exists. Teams also find that catalog registration fails because the descriptor is missing or the repository name does not match the template parameter. Test each template in a sandbox organization, check the permissions the credential actually needs, and confirm that a failed run can be understood and retried without creating duplicates.
How DeployOpen scopes and delivers the GitHub integration
DeployOpen plans and implements self-hosted open-source platforms inside your own cloud accounts, data centers or air-gapped networks, and that includes Backstage software templates that publish repositories to GitHub or GitHub Enterprise. Most engagements are fixed-scope, with the scope, deliverables and timelines agreed in writing before work starts.
How we scope
- Confirm whether you use github.com or GitHub Enterprise Server, and which organizations and teams receive new repositories
- Agree whether the scaffolder authenticates with a GitHub App or a token, and who owns that credential
- List the repository settings, branch protection rules and catalog registration steps the written scope covers
How we build
- Build the GitHub action module configuration and template steps against your own organization's naming and visibility rules
- Test each template run in a non-production Backstage instance and a sandbox GitHub organization before release
- Document the credential scopes, permissions and failure states so your team can review the integration
How we hand over
- Deliver the template files, configuration, test results and runbook as documented artifacts in your own repositories
- Walk your platform and security teams through how new repositories are created, protected and registered in the catalog
- Record which GitHub permissions, app installations and branch protection settings must be reviewed on a regular schedule
How we support
- Ongoing support, upgrades and continuous testing are available as a retainer after handover
- Review the integration when Backstage or the GitHub action module is upgraded, and when GitHub permissions change
- Confirm with the vendor and your own environment which GitHub features your plan supports before committing to a design

