Skip to main content

Delivery modes

For the complete setup and request lifecycle, see Send resource requests.

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 Send resource requests.

Push mode​

The generated Template asks for the resource name, namespace, and the Promise's own spec fields, then runs two steps. For a Promise whose kind is Postgresql they are named:

  1. Submitting your Postgresql request, applying the request to the platform.
  2. Registering your Postgresql request in the catalog, telling the Backstage backend a request has been submitted.

There is nothing for the developer to choose beyond the form itself, and no repository is selected in the form. 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.

To choose the namespace for developers instead of asking them to type it, see Request namespace.

Nothing is under review here, so the record exists only to make the request visible while the platform catches up. See What a developer sees while waiting.

Pull-request mode​

important

@syntasso/plugin-ske-backend must be at least v0.21.0, and @syntasso/plugin-ske-frontend at least v0.18.0. Earlier backend versions do not provide the action that pull-request mode uses to record a request, so a submission opens the pull request and then fails.

The generated Template gains a Repository & Credentials page asking which repository the request should be raised against, and then runs three steps. For a Promise whose kind is Postgresql they are named:

  1. Preparing your Postgresql request, writing the request manifest.
  2. Opening a pull request for review, against the chosen repository.
  3. Registering your Postgresql request in the catalog, 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 on the task page​

The step names above are the same for a create and an update, because one Template serves both. The frontend plugin's scaffolderModuleResourceRequestCopy module, which the install steps add to your app, renames the steps on the task page to say whether the run creates, updates or deletes the resource, for example "Updating dev-postgres Postgresql request". Tasks from other Templates are shown as Backstage shows them.

What a developer sees while waiting​

A resource takes time to reach the catalog: the platform has to create and reconcile it, the portal has to generate its entity, and Backstage has to discover it. Both modes fill that gap the same way, with a pending request entity published as soon as the request is recorded and withdrawn once the real resource entity appears.

ModeBannerLinks
pushSubmitted. Waiting for the platform to create this resource.None; nothing was opened
pull-requestWaiting for approval. This resource will be provisioned when the pull request is merged.The pull request awaiting approval

The recorded request appears and is withdrawn through events; ske.pendingRequests.refreshSeconds is a backstop. How long the real entity takes to arrive depends on those three steps. Under push with ske.mode: kubernetes that can be seconds. A mode that commits to Git adds your GitOps agent's sync interval, and Git-based catalog discovery adds its own polling interval.

Where a completed task leads​

When the run finishes, the task page includes links to the catalog item and open pull requests:

ModeLinks on the completed task
pushView in Catalog
pull-requestView in Catalog, then Pull Request

View in Catalog goes to the resource's own entity when the platform has already published one, and to the pending request otherwise. A create therefore lands on the pending request, since the resource does not exist yet; an update lands on the resource.

Customizations and delivery modes​

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.

warning

Both modes emit a record-request step carrying a copy of the request manifest. Under push mode, a hideNamespaceManifest recipe that targets only ske-configure-resource leaves that step referring to the objnamespace parameter the same recipe set deletes.

Nothing fails at sync time. The recorded namespace resolves to nothing, so the request no longer matches the resource entity the platform ships, and the pending request is never withdrawn from the catalog.

Patch the record step as well:

target:
kind: Template
list:
path: spec.steps
key: id
value: record-request
op: hideNamespaceManifest
field: input.manifest
defaultNamespace: my-namespace
---
target:
kind: Template
list:
path: spec.steps
key: id
value: record-request
patch:
input:
namespace: my-namespace

Only recipes reproducing hideNamespace need this. A Promise that sets the generator's own templateHideNamespace field gets a correct record step without any recipe at all.

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.