How Backstage templates publish to Azure DevOps repositories
Backstage publishes a new service to Azure DevOps by running an Azure-specific publish action inside the scaffolder, so the repository is created, populated from the skeleton, and ready for a pipeline in one template run. The target can be Azure DevOps Services or Azure DevOps Server, and the platform team should decide which one applies before any template is written, because the host URL, authentication and API behavior all depend on that choice. The publish step does not place the component in the catalog on its own. The template still needs a separate registration step that writes the new component's descriptor into the catalog, or the team will see a successful repository with no catalog entry, no owner and no visible pipeline link.
The exact action name, its options, and the npm package that provides the Azure module must be confirmed against the current Backstage scaffolder documentation and the Backstage version your portal runs. The scaffolder action set changes between releases, and the Azure module's parameter names (for example, how the project, repository and default branch are specified) are not covered by the facts available here. Check the module's documentation and the changelog for your release before you copy an example into a template, and confirm how the action treats an existing repository name, since a retried run can otherwise fail or create a partial result. Also confirm which Azure DevOps API version the module calls, because Azure DevOps Server releases lag the cloud service and older on-premises instances may not support every option.
Pairing the repository with a pipeline is the step most often left out. The template should create the pipeline definition file in the skeleton, then the team needs to confirm that the pipeline is registered in Azure DevOps, that its service connections and variable groups exist in the target project, and that the identity used by the publish step has permission to create repositories and pipelines there. Ask your Azure DevOps administrators to confirm the project structure and the permission model before the first template run, and record the pipeline URL in the template output so developers can find it. Test the whole chain in a non-production project first.
What you need before the first template run
Five things have to be in place before a Backstage template can create an Azure DevOps repository and pipeline. Each one is a decision or a check that the platform team should settle with the Azure DevOps administrators before writing the template.
Backstage version and Node.js line
Confirm which Backstage release line your instance runs and which Node.js versions that line supports before adding any Azure module. The versioning policy lists the supported Node.js releases for each line, and the Azure action module must be built for the same @backstage packages as the rest of the app. Mismatched packages are the most common cause of scaffolder startup failures, so plan the module version together with any pending upgrade.
Azure DevOps organization or Server URL
Decide whether you publish to Azure DevOps Services in the cloud or to an on-premises Azure DevOps Server, and record the exact base URL and organization or collection name. For Azure DevOps Server, confirm that the certificate chain from your internal certificate authority is trusted by the Backstage backend container, not only by developer workstations. A TLS failure at this stage usually looks like a generic connection error in the scaffolder log.
Project and repository permissions
Identify the Azure DevOps project where new repositories will be created and the service identity that will create them. That identity needs permission to create repositories, set repository policies where your template depends on them, and create pipelines in the same project. Ask the Azure DevOps administrator to confirm the permissions in writing, and keep the scope to the projects the templates actually target.
Scaffolder backend and Azure module installed
Check that the scaffolder backend is running and that the Azure DevOps action module is installed in the backend, not just listed in the frontend. Without it, the publish:azure action is missing and the template fails validation before any repository is created. Confirm the module version matches your Backstage release, and confirm that the built-in publish actions you plan to use appear in the action list of a running instance.
Network routes from the backend
Confirm that the Backstage backend, not the browser, can reach your Azure DevOps host on the required ports, and that any egress proxy or firewall allows the calls the action makes. Test the route from the same container or host that runs the backend. Also confirm the route for the catalog location URLs the template will register, because those are read by the backend after the repository is created.
Configure the Azure DevOps publish path, step by step
This sequence takes a Backstage instance from no Azure DevOps access to a template that creates a repository, pairs it with a pipeline, and registers the result in the catalog. Each step ends with a check so you can confirm it worked before moving on.
Choose Azure DevOps Services or Server and record the URL
Decide whether your organization uses Azure DevOps Services (cloud) or Azure DevOps Server (self-hosted), since the two use different host and collection URL formats. Record the organization URL for Services or the collection URL for Server, and confirm that the Backstage backend can reach it over the network from the environment where it runs. Ask your Azure DevOps administrator to confirm the exact URL format for your deployment, because the integration entry in app config depends on it. Done means you have one written URL and a successful HTTPS request to it from the Backstage backend host.
Create a dedicated identity and a narrowly scoped token
Create a service identity in Azure DevOps for Backstage rather than reusing a personal account, so that repository ownership and audit records stay with the platform team. Issue a personal access token for that identity and grant only the scopes needed to create repositories, read projects and set up pipelines in the target project, as described in the Azure DevOps documentation for your version. Set a short expiry date your team can rotate. Done means the token is created, its scopes are written down, and a plain API call to list projects with it returns the projects you expect and nothing outside them.
Store the token in backend secrets configuration
Place the token in your secrets store or environment variable and reference it from the backend configuration, so it never appears in app-config.yaml committed to Git. Use the secret name your deployment already uses for other integration credentials, and restrict read access to the Backstage backend runtime only. Confirm that the value is not printed in backend startup logs. Done means the backend starts with the secret injected, and a search of your configuration repository for the token string returns no matches.
Add the Azure integration entry to app config
Add an azureDevOps integration entry to the integrations section of app-config.yaml, using the host, organization or collection values you recorded and the secret reference from the previous step. Keep one entry per Azure DevOps host so the scaffolder can match a repository URL to its credentials. Restart the backend and check the startup output for integration errors. Done means the backend starts cleanly and the integration appears as configured when you run a repository URL check from the scaffolder's publish step in a test template.
Add the publish step with organization, project and repository parameters
In the template's template.yaml, add a publish action for Azure DevOps and expose parameters for the organization, project and repository name. Use the action name from the current Backstage Azure action module documentation and confirm its input names against the version you run, since they are not repeated here. Limit the repository name with a pattern so teams cannot create names that break your naming standard. Done means the template validates in the editor and the parameter form shows the three fields with the validation you set.
Run a test publish into a sandbox project
Create a sandbox project in Azure DevOps that holds no production repositories, and run the template against it using the dedicated identity. Use the dry-run approach described in your template testing process first, then run a real publish with a throwaway repository name. Watch the task log for the repository creation and any errors from the publish step. Done means the task finishes with a success status and the repository exists in the sandbox project with the initial content from the skeleton.
Pair the repository with a pipeline and confirm the catalog entry
Confirm that the template creates or registers the pipeline you expect, by opening the new repository in Azure DevOps and checking for the pipeline definition in its root. Then confirm that the template's register step added a Component entity to the catalog that links to the repository and the pipeline. Delete the sandbox repository afterwards, and record the token expiry date in your rotation calendar. Done means the catalog entry resolves, its links open the repository and pipeline, and the sandbox repository is removed.
Choosing credentials for Azure DevOps Services and Server
Choose the credential before you write the template, because it decides what the Azure action can create and how long template runs keep working. Backstage's Azure integration reads its connection settings from the integrations.azure block of the app configuration, where each host entry carries the base URL and a token. The token is usually a personal access token, and that is the option most teams start with. Confirm in the Azure integration documentation for your Backstage version which authentication methods are supported for the action you plan to use, because the list of options and the configuration keys can change between releases. Record the version you test against so the choice can be reviewed at upgrade time.
Use a service identity rather than a named user. A token issued to a person stops working when that person leaves, changes role or loses access to the project, and every template that depends on it fails at once. A dedicated service account, or a service principal where your tenant supports it, lets you scope the permissions to repository creation and project access only, and it keeps audit records pointing at the automation rather than an individual. Ask your Azure DevOps administrator which identity type your organization permits and who owns the rotation calendar. Store the token in a secret manager or environment variable, never in the template repository.
Expiry is the operational risk. A personal access token has a fixed lifetime that you set when you create it, so a template that worked last month can fail with an authentication error when the token lapses, and the failure appears in the task log rather than at configuration time. Plan rotation before expiry, test the new token against a dry run, and rotate on a schedule that your platform team can follow. For Azure DevOps Server, the differences are the base URL, which points at your own collection host rather than a Microsoft-hosted domain, the token type your server version supports, and certificate handling: if your server uses an internal certificate authority, Backstage must trust that CA or the connection fails before any authentication happens. Confirm the certificate and token options for your server version with your Azure DevOps administrator before setting up the integration.
Pairing each new repository with a pipeline
With this option, the template's skeleton directory includes an azure-pipelines.yml file, so the pipeline definition is committed to the new repository on the first push. The template author controls the build steps, triggers and the agent pool reference, and every repository created from that template starts with the same pipeline logic. Updates to the YAML reach only new repositories unless someone changes existing ones, so the template team usually owns a fleet of copies afterward.
- Who controls the content: the template author edits the YAML in the skeleton, and reviewers see it in the template repository before any developer runs it.
- Who maintains it: the owning team must propagate fixes to existing repositories, either by hand or through a separate change process.
- What breaks on rename: the YAML itself does not carry the pipeline's Azure DevOps name, so renaming the pipeline in the portal rarely breaks the file, but changing the repository name or default branch can.
- What breaks on agent pool change: a pool name hard-coded in the skeleton fails on every new repository until the template is corrected and existing repositories are updated.
- Check before rollout: confirm the pool name and service connections exist in the target organization and project, and test the template against a non-production project.
With this option, the template adds a later step that calls the Azure Pipelines API after the repository exists, creating a pipeline definition that points at the new repository's YAML file. The template controls the pipeline name, folder, repository reference and the YAML path, so the pipeline's identity is determined by template parameters. The platform team usually maintains the custom action or step that performs the call, since it runs with the credential the template uses.
- Who controls the content: the template and its custom step decide the pipeline name, folder and YAML path, which makes naming conventions enforceable.
- Who maintains it: the team that owns the action code and its credential, which must be kept current as the Azure DevOps API evolves.
- What breaks on rename: if a developer renames the pipeline in the portal, later template runs or cleanup scripts that look it up by name can fail or duplicate definitions.
- What breaks on agent pool change: the pool is referenced when the pipeline runs, so a deleted or renamed pool causes queued runs to fail rather than the creation step itself.
- Check before rollout: confirm the identity that calls the API has permission to create pipelines in the target project, and ask how the step behaves on a retry so duplicates are not created.
With this option, the template creates only the repository and leaves pipeline creation to the team that receives it, who define the pipeline in the Azure DevOps interface or commit their own YAML later. The template does not control the pipeline, so teams get flexibility, and the platform team has the least to maintain. The trade-off is that new repositories may ship without any build or deployment checks, and nothing in the catalog reveals whether that happened.
- Who controls the content: the receiving team controls triggers, stages and pool selection, with no template-level standard enforced.
- Who maintains it: the owning application team, which means the platform team has no direct responsibility for pipeline health.
- What breaks on rename: catalog links or documentation that point to a pipeline name can go stale, since the template never recorded it.
- What breaks on agent pool change: each team discovers the problem separately, often when a build queues indefinitely, and there is no central fix.
- Check before rollout: ask how the catalog records pipeline ownership, and whether a missing pipeline should block registration or only produce a warning.
Mapping template parameters to Azure DevOps objects
This table shows where each scaffolder value originates, whether from the form a developer fills in, the signed-in catalog user, or the template author's fixed choices, and which Azure DevOps field or catalog entry it lands in. Read each row as a checklist item to confirm in your template before the first test run. The main takeaway is that only the repository name and project placement should vary per request, while the organization URL and credentials stay under platform control.
| Template value | Source | Azure DevOps or catalog target |
|---|---|---|
| Component name | Form field, validated against your naming rules | Repository name and catalog metadata.name |
| Azure organization URL | Fixed by the template author or a platform-owned default | Organization in the Azure action host configuration |
| Azure project | Form field limited to an allowed list of projects | Project that receives the new repository |
| Repository name | Derived from component name in a step, not typed twice | Repository name in Azure Repos |
| Default branch | Fixed by the template author, confirm against your branch policy standard | Default branch set on first push |
| Owner | Signed-in catalog user, resolved through the sign-in resolver | Catalog annotation for owner and spec.owner on the Component |
| Owning group | Form field from groups in the catalog, or fixed by template | spec.owner as a Group reference and team in Azure DevOps |
| Catalog source location | Generated by the publish step from the new repository URL | backstage.io/source-location annotation on the Component |
| Pipeline definition path | Fixed by the template author, such as a YAML file in the skeleton | Pipeline created or linked to the repository after publish |
Securing the Azure DevOps publish path
A template that creates repositories is a write path into your source control, so the token, the people allowed to run it, and the policies applied afterward all need to be deliberate. Each card below names one control and the check that shows it is working in your Azure DevOps organization.
Least-privilege token scopes
Give the publishing credential only the Azure DevOps permissions the template needs, such as creating repositories in a named project and setting permissions on them, and nothing at organization level. Verify by running the token against a sandbox project and confirming that requests outside that project fail. Ask your Azure DevOps administrator to confirm which scopes the action module requires for your version, because the list changes over time.
Token stored only in backend secrets
Keep the Azure DevOps token in the Backstage backend configuration, sourced from your secret manager or environment, and never in template parameters, frontend config or the template repository. Verify by searching the built frontend bundle and the template YAML for the token value, and by confirming that the scaffolder task log does not print it. Treat any hit as a reason to rotate immediately.
Restricted access to publishing templates
Decide which groups may run templates that create Azure DevOps repositories, and restrict those templates to them rather than leaving every catalog user able to publish into your organization. Verify with a user outside the approved group, who should see the template hidden or get a denied response when they try to run it. Also confirm who may register new Template entities, since a registered template can carry its own publish steps.
Branch policies applied after creation
Creating the repository is not enough. Apply branch policies, such as required reviewers and build validation on the default branch, as a dedicated step after creation so the repository is protected from its first commit. Verify by opening the new repository's branch policies in Azure DevOps and comparing them with your standard. If the policy step fails, the run should report it rather than leave an unprotected repository without notice.
Audit logging of publish actions
Record who ran each publish, which template and parameters were used, and which repository was created. Use the Backstage scaffolder task history together with the Azure DevOps audit log for the organization, and confirm that both retain entries long enough for your review cycle. Verify by running a test publish and locating the matching entries in both places. Ask your Azure DevOps administrator whether audit logging is available for your edition and deployment.
Scheduled token rotation
Set an expiry for the publishing token and a rotation procedure that updates the backend secret without a code change. Rotate on a schedule and immediately after any suspected exposure or staff change. Verify by rotating the token in a test environment, restarting the backend, and confirming that publishing still works with the new value and that the old token is rejected. Agree the rotation interval with your security team.
Azure DevOps publish errors and how to fix them
This table lists the failures teams most often hit when a Backstage template publishes to Azure DevOps, with the likely cause and the fix for each. Work through the rows in order, since authentication and organization URL problems often produce errors that look like missing permissions. Confirm exact error text and scopes in your own Azure DevOps environment before changing configuration.
| Failure | Likely cause | Fix |
|---|---|---|
| Authentication rejected | The personal access token is wrong, expired or was copied with extra whitespace, so Azure DevOps refuses the request. | Issue a new token, store it in the secrets configuration the publish action reads, and restart the backend. Check the token expiry date when you create it. |
| Insufficient scope for repository creation | The token lacks the Code scope with write permission, so the action cannot create the repository. | Recreate the token with the Code scope granted for read, write and manage. Confirm the identity behind the token can create repositories in the target project. |
| Wrong organization or collection URL | The host or organization segment in the configured URL does not match the Azure DevOps organization, or Azure DevOps Server uses a collection path the URL omits. | Compare the configured host and organization name with the browser address for your project. For Azure DevOps Server, include the collection in the URL as your server is configured. |
| TLS trust errors on Azure DevOps Server | The server uses a certificate issued by an internal certificate authority that the backend container does not trust. | Add the internal root or intermediate certificate to the backend trust store and rebuild or redeploy the image. Confirm the chain with your infrastructure team rather than disabling verification. |
| Project not found | The project name in the template parameter differs in case or spelling from the Azure DevOps project, or the token identity cannot see that project. | Match the project name exactly as shown in Azure DevOps. Confirm the token identity is a member of the project with access to create repositories. |
| Repository name conflict | A repository with the same name already exists in the project, often from an earlier failed run or a manual create. | Check the project for the existing repository. Delete or rename it if it is abandoned, or change the template to add a unique suffix. Review your naming rule before rerunning. |
| Pipeline creation fails after the repository exists | The repository was created, but the pipeline step lacks permission to create pipelines, cannot find the YAML file, or refers to a missing service connection. | Grant the identity pipeline creation rights in the project, confirm the pipeline YAML path exists in the new repository, and verify the named service connection. The repository is already created, so plan a cleanup or a rerun approach before retrying. |
| Catalog registration points at a missing repository | The registration step ran with a repository URL built from parameters, but the publish step failed or wrote to a different location. | Do not register the component until the publish step succeeds. Confirm the repository URL in the catalog entry matches the created repository, then remove the stale entry if one was written. |
Questions teams ask before publishing to Azure DevOps
What drives the effort of publishing Backstage templates to Azure DevOps?
The main drivers are the number of templates, whether you run Azure DevOps Services or Azure DevOps Server, the identity model behind the credentials, how new repositories are paired with pipelines, and how much governance already exists. Each template that creates a repository needs its own parameters, permissions and pipeline wiring, so a portfolio of ten templates takes far more design work than one. Server deployments add work around hosting, certificates and network reachability from the Backstage backend. Existing branch policies, required reviewers and naming rules also shape the template steps, because the template has to satisfy them on the first run.
Can our internal team publish to Azure DevOps from Backstage without outside help?
Yes, a team with Backstage engineers who know the scaffolder and an Azure DevOps administrator who can manage projects, service connections and tokens can build this in-house. The harder parts are usually the credential model, which must be scoped tightly and rotated, and the pairing of new repositories with pipelines, which touches Azure DevOps permissions. Teams that have not written a custom action or tested templates before often spend most of their time on those two areas. An outside partner is most useful when the scope is fixed in writing and the team needs the work done alongside its own staff, with documented handover.
What do we need from our Azure administrators and Backstage engineers?
From Azure administrators you need the target organization or collection, the projects where new repositories will live, the permission model for the identity used, and the rules for branch policies and pipeline creation. From Backstage engineers you need access to the backend configuration, the ability to add an action module and register it, and a place to run template tests. Both groups should agree on who approves token or service principal creation and who owns the template repository. Early agreement on these points avoids rework when the first template is tested end to end.
How long does a fixed-scope Azure DevOps publishing piece take?
Duration depends on the scope agreed in writing: the number of templates, whether Services or Server is in use, how many projects and pipeline patterns must be covered, and how much existing governance must be respected. DeployOpen does not publish fixed durations, so ask for a timeline tied to a named deliverable list in the written scope. A good proposal will show which items are one-time build work, such as the action module and first templates, and which are repeated, such as adding templates later. Ask how dry-run testing and a review step are included in the timeline.
What should we ask for in a quote for this work?
Ask for a written scope listing each template, the Azure DevOps target (Services or Server), the identity and credential model, the pipeline pairing approach, and the testing and handover steps. The quote should separate one-time build work from any ongoing support or upgrade retainer, and it should state which parties are responsible for Azure DevOps administration and for Backstage changes. Ask what is excluded, how changes to scope are priced and approved, and what documentation and training are delivered. DeployOpen does not publish a price list, so a quote follows from that written scope.
How does the credential model affect security for Azure DevOps publishing?
The credential model decides what the Backstage backend can do in Azure DevOps, so it deserves review before any template runs. Use a dedicated identity with the narrowest permissions needed to create repositories in the approved projects, store its secret in your secrets system rather than in plain configuration, and plan for rotation and revocation. Confirm with Azure DevOps documentation which token or identity types your edition supports and how they are audited. Security reviewers will ask who can run templates that create repositories, so pair this with the template access rules in your Backstage setup.
What goes wrong when pairing new repositories with Azure pipelines?
The most common failures are pipelines created without the right service connection, pipelines that fail on first run because variable groups or agent pools are missing, and repositories that are created but never registered in the catalog. Another frequent issue is a template that creates a pipeline under a project where the identity lacks permission, which fails midway and leaves a partial result. Test each template against a sandbox project first, check the first pipeline run before announcing the template, and confirm that the catalog entry links to the correct repository and pipeline.
How DeployOpen scopes the Azure DevOps publish work
The scope of an Azure DevOps publish engagement is agreed in writing before any template is changed, and it fixes four things: which templates publish to Azure DevOps, which Azure target each one uses, how the scaffolder authenticates, and how each new repository is paired with a pipeline. The first decision is the target itself. Azure DevOps Services and Azure DevOps Server have different hosts, API surfaces and identity options, so the written scope names one of them, the organization or collection, and the projects that will receive new repositories. Templates that publish to a second target are listed as separate work items, not folded into the first. We also confirm which template owners will be involved and who signs off on each template before it reaches developers.
The credential model is the second decision and the one most often left vague. The scope should state which identity the Backstage backend uses to create repositories, which token or service connection type is permitted, what permissions that identity holds, and who rotates it and where the secret is stored. DeployOpen implements and hardens this inside your own infrastructure, so the scope also covers where the backend runs, how the secret reaches it, and how access is reviewed. Confirm these points with your Azure DevOps administrators before the work starts, because the answers determine which action module settings and which template parameters are needed. We do not issue audit reports, attestations or certifications. Independent auditors and certification bodies do that work, and our role is to prepare the integration and its evidence.
The last parts of the scope are pairing and testing. The written plan should say which pipeline definition, from which repository template, is created for each new repository, and whether the pipeline is created by the template or by an administrator. It should also define the test plan: dry-run coverage, a publish run against a non-production Azure project, verification of branch policies and pipeline triggers, and a final check that the catalog entry links to both the repository and its pipeline. Ask for a written list of acceptance checks in the quote so that completion is measured against something specific. Scope changes after signing, such as adding a second Azure target or changing the identity model, should be handled as written change requests with their own effort estimate.
How DeployOpen delivers Backstage Azure DevOps publishing
DeployOpen scopes, builds, tests, documents and hands over Azure DevOps publishing for Backstage templates inside your own infrastructure. Engagements are fixed-scope, with deliverables and timelines agreed in writing before work starts.
How we scope
- Confirm whether your target is Azure DevOps Services or Azure DevOps Server, since credentials and network paths differ
- List the templates that will create repositories and the project and repository naming rules they must follow
- Record which pipelines each new repository must be paired with and who owns those pipeline definitions
- Agree in writing which credential model, token scopes and service identities are in and out of scope
How we build
- Install and configure the Azure action module in your Backstage backend with credentials held in your secret store
- Write template steps that create repositories, push skeleton content and register the resulting component in the catalog
- Build a dry-run path so templates can be exercised without creating repositories or pipelines in Azure DevOps
- Add unit tests for custom handlers and review template changes before they reach developers
How we hand over
- Provide the written scope, configuration reference, template source and a record of every credential and its purpose
- Document the pipeline pairing pattern, rotation steps for tokens or service connections, and the rollback procedure
- Walk your platform and security teams through a test run in a non-production Azure DevOps organization or project
- Deliver runbook notes covering common failures such as permission errors and missing project identifiers
How we support
- Ongoing support, upgrades and continuous testing are available as retainers, scoped separately from the original build
- Review Backstage version bumps and Azure action module changes against your templates before rolling them out
- Re-test publishing paths after Azure DevOps permission or policy changes that affect your service identities
- Confirm the support boundary, response expectations and any retainer terms in the written agreement before work begins

