Radius — Delete a Deployment or Environment
Two distinct teardown flows are available from the Radius canvas:
- Delete a deployment dispatches the committed
delete-application.ymlGitHub Actions workflow, which spins up an ephemeral k3d Radius control plane, connects to the target AKS cluster, restores persisted state, runsrad app delete, and persists the updated state again before tearing the control plane down. Deleting the deployment also deletes that application's resources (running their recipes' delete path against the target cluster and cloud). - Delete an environment is a tracked async operation that tears down the cloud state behind the environment, not just the GitHub record. It (1) dispatches the Azure-only
delete-environmentworkflow to delete the Radius environment on the cluster while the federated credential still exists (the workflow authenticates with it), (2) removes the per-environment Azure federated credential only when immutable Radius provenance and immediate live revalidation prove that deletion is safe, (3) deletes the GitHub deploy environment (its stored variables and secrets) via the GitHub API, and (4) deletes the environment's dedicated private/internal GHCR state package after validating its repository linkage. The Microsoft Entra app registration is left in place because it can be shared; the completion acknowledgement links inline to the Azure Portal if it is no longer needed. The flow refuses to start while an application is still deployed, and only Azure-backed environments can be deleted today.
When to use this skill
- "Delete my app" / "Remove application X from env Y" / "Tear down the deployment"
- "Delete the environment" / "Remove the dev environment"
- "Retry the environment deletion"
Prerequisites
Before invoking this skill:
- A GitHub deploy environment configured with cloud credentials → use the
radius-environmentskill if missing. - For a deployment delete: the application was deployed to that environment at least once (the delete restores persisted state to know what to remove).
- Authenticated
ghCLI access to dispatch workflows. The extension shells out togh, which uses your stored GitHub credential (the keyring credential fromgh auth token) and falls back to it when an injected token lacks theworkflowscope — there is no separate extension-managed PAT to configure.
How to invoke
Open the canvas hub and use the deployed-application view:
- Reuse the existing Radius canvas instanceId when one is open; otherwise use
radius-panel:open_canvas({ canvasId: "radius", instanceId: "<radius-instance>", input: { page: "environment", repo: "<owner/repo>" } }) - Select the environment (and, for a deployment delete, the deployed application).
- Click Delete Deployment to tear down the app, or use Delete Env to run the tracked environment cleanup. Live status streams until success / failure / timeout.
If a previous delete of that application failed, the canvas first asks the server whether it failed with the stranded-resource conflict below. Only when the failed run's rad-delete-result artifact proves it does the button offer the force delete confirmation, which warns that forcing may orphan cloud resources and dispatches the workflow with force: true. The server does not trust that offer: before dispatching, it re-reads the artifact itself and refuses force unless the deployment is in the delete-failed state and the failure is still provably this conflict. A delete that failed for credential, network or workflow-configuration reasons cannot be forced, and neither can one whose artifact is missing, expired or unreadable. If the failed run was itself a forced delete, forcing stays available — it is the only escape — but the confirmation says the conflict survived one force already, so leftover provider resources are likely.
The extension keeps the committed delete workflow files current before dispatching, so a run never executes a drifted copy.
What the deployment-delete workflow does
- Commits/updates the application-delete workflow files if they've changed — the
delete-application.ymldispatcher plus thedelete-azure.ymlprovider workflow. The extension commits only the Azure provider workflow and strips the dispatcher'saws:job. - The dispatcher calls the Azure provider workflow, which authenticates to the cloud via OIDC and connects to the target AKS cluster.
- Installs
k3d+ theradCLI + Terraform and installs Radius on the ephemeral control plane wired to the target cluster (same setup as deploy). - Projects GitHub OIDC tokens into the pods and registers the cloud identity with
rad credential register, so recipe deletes can reach the target cluster and cloud. - Authenticates to GHCR with the repository
GITHUB_TOKEN, exports environment-scopedRADIUS_STATE_BACKEND,RADIUS_STATE_REGISTRY, andRADIUS_STATE_ARCHIVE, then runsrad startupto restore the control-plane databases and Terraform recipe-state Secrets persisted by the previous run — this is what tells the delete which environment, recipe packs, resources, and Terraform state exist. Unlike deploy, it does not recreate the environment, recipe pack, or registry credentials. - Runs
rad app delete <name> --yes --preview(--previewswitches the CLI to the deployed-application API path) via thedelete-resourcecomposite action, which writes arad-delete-resultartifact (JSON:outcome,exitCode,resourceType,name,forced,output). When the dispatch carriesforce: true, the action adds--forceand recordsforced: true. - After a successful application delete, lists every remaining
Radius.Coreapplication and its resources. The workflow retains the managed shared Gateway while any application still has aRadius.Compute/routesresource. After the last routes app is removed, it deletes only Gateway infrastructure proven to be Radius-owned. Pre-existing resources are never adopted; CRDs are removed only when Radius installed them and no Radius or non-Radius Gateway API objects remain. Before uninstalling Contour, it also inventories Kubernetes Ingresses and objects from all five Contour CRDs managed by the chart, preserving the controller and CRDs if any consumer remains. If discovery is incomplete, cleanup fails closed and preserves the infrastructure. Deploy, application-delete, and environment-delete workflows serialize Gateway lifecycle operations across every Radius environment in the repository. rad shutdown(if: always()) persists the post-delete control-plane databases and Terraform recipe-state Secrets back to the OCI-backed state archive, pushed to the GHCR repository inRADIUS_STATE_REGISTRYunder theRADIUS_STATE_ARCHIVEtag (defaultradius-state). On failure, logs are uploaded as theradius-logsartifact; the k3d cluster is always deleted.
What the environment-delete flow does
Deleting an environment runs as a tracked operation through the same progress panel as environment creation. Only Azure-backed environments are supported; deleting an AWS (or any non-Azure) environment is refused up front with a clear message and nothing is torn down. Any AWS-related deletion code is unsupported framework scaffolding, not a compatibility contract, and may change or be removed when AWS support is designed.
- Refuses to proceed while an application is still deployed to the environment (its cloud resources would be orphaned), and points you at the deployment-delete flow first.
- Stage 1 — Radius environment: dispatches the Azure-only
delete-environmentworkflow, which connects to the target AKS cluster and runsrad env delete. This runs first, while the federated credential still exists, because the workflow authenticates with it. If this cannot be confirmed (dispatch failed, run not found, timeout, or a non-guard failure), the whole deletion stops fail-closed and is reported as a retryable partial failure — the credential and GitHub environment a retry needs are left in place. - Stage 2 — federated credential: removes the per-environment Azure federated credential only after immutable tenant, application-object, credential-object, repository, subject-configuration, issuer, and audience evidence proves Radius created it for this consumer and immediate live revalidation still matches. Reused, shared, unproven, changed, or insufficiently scoped custom credentials are retained with guidance; a confirmed-missing credential is an idempotent success.
- Stage 3 — GitHub environment: deletes the GitHub deploy environment (its variables and secrets) via the GitHub API.
- Stage 4 — GHCR state package: derives the environment-exclusive package path, verifies that the package is private/internal and linked to the target repository, deletes it through the GitHub Packages API, and confirms it is absent. Missing
delete:packagesaccess stops the operation as a retryable partial failure only after the earlier teardown has completed; grant the scope and retry, or delete the named package manually and retry. Every attempt reloads the active GitHub CLI package credential, so retry uses the token updated bygh auth refreshrather than the failed attempt's cached token. An already-absent package is idempotent success. - Stage 5 — app registration: leaves the app registration in place. Radius never deletes a Microsoft Entra app registration; it records an informational step and, after a concluded deletion, includes an inline Azure Portal link in the acknowledgement if the registration is no longer needed.
An incomplete deletion exposes only Retry deletion. Retry reopens the same durable operation, preserves succeeded stages, resets unresolved stages, and resumes through the idempotent runner. Delete operations are not pausable and never expose the create flow's Stop setup, Continue setup, rollback, or exit controls. While deletion is in progress, Delete Env is disabled and the environment cannot be selected for deployment.
After a successful delete
- Tell the user it succeeded and include the workflow run URL (for a deployment delete).
- If the delete was forced, tell the user to verify in the cloud provider that no orphaned resources remain: resources in non-terminal states may leave external resources that require manual cleanup.
- Note that deleting a deployment removed the app's resources. If it was the last managed routes app, the workflow also removed unused Radius-owned Gateway infrastructure while retaining pre-existing or shared CRDs. For environment deletion, report the operation's actual steps: the Radius environment, GitHub deploy environment, and private GHCR state package were removed; a proven-safe credential was removed or a retained credential was explained; and the Entra app registration was left in place with the acknowledgement's Azure Portal link.
Common failure modes
OCI archive repository is not configuredor GHCR authentication/visibility errors → Recreate or update the deploy environment soRADIUS_STATE_BACKEND=oci, package-onlyRADIUS_STATE_REGISTRY, andRADIUS_STATE_ARCHIVE=radius-stateare present. Confirm the delete workflow logs in toghcr.iobeforerad startup, haspackages: write, and that the state package is private or internal.Environment deletion cannot delete the GHCR state package → Refresh the active GitHub CLI credential with
gh auth refresh --hostname github.com --scopes delete:packages, then use Retry deletion. Earlier teardown stages are not replayed. Alternatively, delete the package named in the failure manually in GitHub Packages and retry so Radius can confirm it is absent.The target resource is in progress state: Updating(409 Conflict) on delete → A resource was stranded in a non-terminal state by a prior run whose control plane was torn down before its async operation finished. The persisted state restores it stillUpdating, and no operation completes it, so every ordinary delete 409s. Press Retry Delete and accept the force delete confirmation the canvas offers: it reruns the workflow asrad app delete --preview --force, which drops the stranded records instead of waiting for an operation that will never finish. Afterwards, tell the user to check the cloud provider for orphaned resources — forcing deletes resources in non-terminal states from Radius, but may leave their external resources behind for manual cleanup. → The offer depends on the failed run'srad-delete-resultartifact, which is retained for one day. If it has expired, the canvas cannot prove the failure and shows only the ordinary confirmation; run the delete once more to produce a fresh result, then force.The application was deleted but managed Gateway cleanup failed → Treat the workflow as failed and read the cleanup diagnostic. Discovery and ownership checks are deliberately fail-closed: the workflow retains Gateway infrastructure rather than guessing that no other Radius or non-Radius route uses it. Repair the listed CLI, Kubernetes, Helm, or ownership failure, then rerun cleanup; do not manually delete shared CRDs without first proving that no Gateway API objects remain.
Environment deletion stopped partway → Use Retry deletion in the progress panel. Do not start a second deletion or look for Stop setup; the existing durable operation resumes only unresolved stages and keeps successful work.
Related files
- The delete workflow templates are canonical in
radius-project/ai-extensionsat.github/extension/—delete-application.ymlanddelete-environment.yml(dispatchers),delete-azure.yml/delete-aws.yml/delete-environment-azure.yml(providerworkflow_callworkflows), andactions/*(shared composite actions includingsetup-control-plane,restore-state,delete-resource, Gateway lifecycle management, andteardown). A released extension fetches every delete template at its baked source commit and fills every first-party composite-actionuses:with that same full commit SHA. It commits the dispatchers and Azure provider workflows into the user repo at.github/workflows/; no generated action reference follows a mutable branch, channel tag, or local plugin asset. - Environment deletion orchestration lives in
packages/adapter-canvas/src/server/services/environment-deletion.ts; operation retry/control policy lives inpackages/adapter-canvas/src/operations.tsandpackages/adapter-canvas/src/server/routes/operations-control.ts. - The implemented safety and sharing boundaries are documented in
docs/design/2026-08-environment-deletion-cloud-cleanup.md.