Portal Controller
Overview
The Portal Controller syncs Kratix Promises and Resource requests into a developer portal, such as Backstage or Cortex, from a single, unified integration. It replaces the Backstage Controller and SKE Cortex Controller, which are now deprecated in its favour. See Portal Controller for the full documentation.
The release manifest is available at:
http://syntasso-enterprise-releases.s3-website.eu-west-2.amazonaws.com/#ske-portal-controller/
Release Notes
v0.2.0 (2026-07-30)
The first release of the Portal Controller: one integration for every developer portal your platform exposes.
Until now, each portal needed its own controller, its own SKEIntegration, and its own customization CRD. Adding a second portal meant running a second controller, and the two
had little in common. The Portal Controller replaces that with a single integration that declares every portal on one resource, generates entities through one pipeline, and gives
Promise authors one way to shape what those entities look like.
Both the Backstage Controller and the SKE Cortex Controller are deprecated as of this release. They continue to work, so you can migrate when it suits you. See Migrating from Backstage and Migrating from Cortex.
What you gain over the standalone controllers
The Portal Controller generates the same entities the standalone controllers did. What changes is everything around them:
| Standalone controllers | Portal Controller | Portals | |
|---|---|---|---|
| Portals per platform | One SKEIntegration per type, so one Backstage and one Cortex | Every portal on one SKEIntegration, including two Backstage instances side by side | Both |
| Opting a Promise in | Per-portal wiring | One label, kratix.io/portal-<type>, and a single Resource can opt back out | Both |
| Customizing what is generated | Backstage had BackstageEntityCustomization, one pipeline shared by the Promise and its Resources. Cortex had a handful of annotations and no way to edit the generated documents | PortalCustomization with independent promise and resource lanes, for every portal type | Both |
| Expressing a customization | Typed entityGenerationOptions fields, or a hand-written container | Declarative Portal Patch recipes, with your own container still available | Both |
| Reporting | Per-controller | One PortalBindingReady condition plus a per-type sync condition and an entity URL annotation | Both |
| Reviewing requests | Not available: submitting a form applied it immediately | pull-request delivery mode raises the request as a pull request, and update and delete go through review too | Backstage |
| Where entities are written | A Destination you create and label environment: backstage beforehand | The portal creates and owns its Destination and state store, or adopts an existing one | Backstage |
For Cortex specifically, the headline change is customization. The standalone controller
generated its entity and workflows the one way it knew how, and the only levers were annotations.
A Cortex portal now runs the same generate → configure → writer pipeline as every other portal, so
you can reshape the generated entity and workflows at both the Promise and the Resource level. See
Cortex examples.
Two things become portal-wide rather than per-Promise: the Cortex fixed namespace, previously the
kratix.io/cortex-fixed-namespace annotation, and the Backstage single-page form. Both are now
adapterConfig.generate.args flags on the portal. Where you need them per Promise, the
hideNamespaceManifest and singleSpecPage Portal Patch recipes do that job.
Features
-
One integration, many portals. Declare every portal your platform exposes on a single
SKEIntegrationoftype: portal-controller. Portals of the same type can coexist, so a staging and a production Backstage are two entries rather than two installations. See Installation. -
Opt in with a label. A Promise or Resource request joins a portal by carrying
kratix.io/portal-<type>, instead of needing a dedicated resource per portal. A single Resource can opt back out without affecting its Promise. See Bind a Promise to a portal. -
Request review with pull-request delivery. Backstage portals can run in
pull-requestmode, where submitting the generated form raises a pull request against a Git repository instead of applying the request directly. Nothing reaches the platform until a human merges it, and updates and deletions go through the same review. Currently GitHub only. See Delivery modes. -
Backstage portals manage their own destination. A portal can create and own the Kratix Destination and state store it writes entities to, rather than requiring you to wire one up beforehand. Platforms that already manage Destinations can adopt an existing one instead. See Backstage.
-
Customizable Cortex entities and workflows. A Cortex portal runs the same
generate → configure → writerpipeline as every other portal type, so the generated entity and workflows can be reshaped at both the Promise and the Resource level. It also runs a status exporter and a setup Job that provisions the shared entity and relationship types the integration depends on. See Cortex. -
Shape entities declaratively. The new
PortalCustomizationresource, which replacesBackstageEntityCustomization, runs containers that edit generated documents before they ship, with separate lanes for the Promise and its Resources. Paired with Portal Patch, most customizations are a few lines of declarative recipe rather than a hand-written script. See Customization.
Known issues
- Portal Patch recipes that target the
ske-configure-resourcestep, includinghideNamespaceManifest, fail underpull-requestdelivery mode, because that step only exists inpushmode. A recipe that matches nothing aborts the sync, so no entity ships.
