Skip to main content

Delivery modes

A Backstage portal's config.mode decides what happens when a developer fills in a generated Template and clicks submit.

ModeWhat submitting doesUse when
push (default)The request is applied to the platform immediatelySelf-service should be instant
pull-requestThe request is raised as a pull request for reviewA human must approve before anything is created

The mode is set per portal, and applies to every Promise routed through it:

portals:
- name: prod
type: backstage
config:
mode: pull-request
info

config.mode is not the same setting as the Backstage plugin's backend-wide ske.mode. This one decides whether a request goes through review. ske.mode decides how the backend writes an approved request, and is covered in Configure Backstage.

Push mode

The generated Template asks for the resource name, namespace, and the Promise's own spec fields, then runs a single step that applies the request.

There is nothing for the developer to choose beyond the form itself, and no repository is involved. How the request is written, directly through the Kubernetes API as the signed-in user or committed to a Git repository, depends on the backend's ske.mode setting rather than on this mode.

Pull-request mode

The generated Template gains a Repository & Credentials page asking which repository the request should be raised against, and then runs three steps:

  1. Generate resource request, writing the request manifest.
  2. Pull Request, opening a pull request against the chosen repository.
  3. Record request, telling the Backstage backend that a request is now awaiting approval.

The request manifest lands in the repository at:

kratix-requests/<promise>/<namespace>/<name>.yaml

Nothing reaches the platform until that pull request is merged. Merging it commits the manifest, and your existing GitOps tooling applies it.

Branches and repositories

The developer picks the repository per run, so different teams can raise requests against their own repositories through the same Template. Pull requests target main by default.

Branches are named backstage/<promise>/<name>, and a re-run for the same resource reuses the existing branch and pull request rather than opening a second one. Deletions use a separate backstage/<promise>/<name>-delete branch, so requesting a deletion can never silently amend an in-flight update.

GitHub only

Pull-request mode uses GitHub's pull request API and the repository picker only accepts github.com. GitLab, Bitbucket and Azure repositories are not supported in this mode. Use push mode with the backend's ske.mode: gitops if you need a different provider.

Updating and deleting

Both go through review as well, from the Manage tab on the resource in Backstage:

  • Update re-opens the Template pre-filled with the resource's current values, with the name and namespace locked, and raises a pull request with the changes.
  • Delete raises a pull request that removes the request manifest. The resource stays until that pull request is merged, and the confirmation dialog says so.

Deletion only routes through review for resources that were themselves requested through pull-request mode. A resource created some other way, by kubectl or under push mode, is deleted immediately.

What a developer sees while waiting

Once a request is recorded, Backstage shows a pending request entity in the catalogue, carrying a link to the pull request that is awaiting approval. It disappears once the request is merged and the real resource entity appears in the catalogue.

There is a delay between the two, since Backstage has to re-read both the pending requests and your catalogue. Expect around a minute by default.

note

There is no link to the pull request on the scaffolder's completion page. Developers find their pull request through the pending request entity in the catalogue.

Customizations and pull-request mode

warning

Portal Patch recipes that target the ske-configure-resource step, including the hideNamespaceManifest recipe, do not work under pull-request mode. That step only exists in push mode, so the recipe matches nothing, fails, and aborts the sync, which means no entity ships at all.

If a portal uses pull-request mode, avoid recipes that target that step.

Recipes that only patch the generated documents, such as setting an owner, adding tags, or singleSpecPage, work in both modes.

Choosing

Start with push unless you have a reason not to. It is simpler, has no repository prerequisites, works with any Git provider through ske.mode: gitops, and has no interaction with Portal Patch to think about.

Move to pull-request when requests genuinely need human approval, and you are on GitHub.