Skip to main content

In-Place Upgrades

When the template a stack was launched from has been updated to a new version, you can adopt those changes without tearing the stack down. The upgrade engine diffs the running stack's snapshotted descriptor against the latest template version, classifies each resource's delta, and applies only the changes that are safe to make non-destructively.

How the engine classifies changes

Every resource in the diff receives one of three classifications:

ClassificationMeaning
unchangedThe resource's spec is identical in both versions. The engine does not touch it.
in_placeA safe, non-destructive change the engine can apply to the running resource.
blockedA change that would recreate, shrink, or fundamentally alter a stateful resource. A fresh stack is required.

If any resource is blocked, the entire upgrade is blocked. The engine will not apply the in_place changes either. You must launch a new stack to adopt those changes.

What can be upgraded in place

The set of spec keys the engine treats as in_place differs by resource kind:

KindIn-place keysAction label
appimage_ref, env, auth, domainredeploy_app
appplan_namescale_app
databaseplan_name (compute resize)scale_service
inference(none; any change is blocked in the current version)
files(none; any change is blocked in the current version)

Changes to any other spec key on any kind are blocked. The intent is conservative: the engine cannot recreate or shrink a stateful resource (a database or a bucket) in place, so those paths are entirely refused.

What is always blocked

The following changes are always blocked, regardless of kind:

  • Adding a resource. A new resource in the target template has no running counterpart. Adding it during an upgrade is not supported; launch a fresh stack.
  • Removing a resource. Removing an existing resource would leave no path to tear it down gracefully within the upgrade. Launch a fresh stack.
  • Changing a resource's kind. For example, changing a database resource to a files resource.
  • Changing a database engine, version, storage size, or storage tier. Any key on a database resource other than plan_name is blocked.
  • Any change to an inference or files resource. Support for in-place inference key reminting and files quota adjustment is planned but not yet available.

Step 1: Preview the upgrade

Always preview before applying. The preview computes and returns the classified plan without changing any state:

curl -X POST https://api.foundrydb.com/stacks/$STACK_ID/upgrade/preview \
-H "Authorization: Bearer $FOUNDRYDB_TOKEN"

Example response for an unblocked upgrade:

{
"from_version": "1.0.0",
"to_version": "1.1.0",
"changes": [
{
"symbolic_name": "db",
"kind": "database",
"change": "unchanged"
},
{
"symbolic_name": "app",
"kind": "app",
"change": "in_place",
"action": "redeploy_app",
"target_spec": {
"attachment_kind": "open-webui",
"image_ref": "ghcr.io/open-webui/open-webui:0.4.5"
}
}
],
"new_monthly_cost": 87.00,
"current_monthly_cost": 87.00,
"cost_delta": 0.0,
"blocked": false,
"blocked_reasons": []
}

Example response for a blocked upgrade:

{
"from_version": "1.0.0",
"to_version": "2.0.0",
"changes": [
{
"symbolic_name": "db",
"kind": "database",
"change": "blocked",
"reason": "changing \"version\" on a database resource requires a fresh stack (it could recreate or resize stateful data)"
},
{
"symbolic_name": "app",
"kind": "app",
"change": "in_place",
"action": "redeploy_app"
}
],
"blocked": true,
"blocked_reasons": [
"db: changing \"version\" on a database resource requires a fresh stack (it could recreate or resize stateful data)"
]
}

When blocked is true, no upgrade path is available. Launch a new stack from the updated template and migrate your data manually.

Step 2: Apply the upgrade

Once you have reviewed the plan and accepted the new monthly cost:

curl -X POST https://api.foundrydb.com/stacks/$STACK_ID/upgrade \
-H "Authorization: Bearer $FOUNDRYDB_TOKEN" \
-H "Content-Type: application/json" \
-d '{"accepted_monthly_cost": 87.00}'

Response semantics:

HTTP statusMeaning
202 AcceptedUpgrade accepted. The reconciler is applying changes. Response body is a StackMigration record.
200 OK with {"status":"up_to_date"}No changes to apply. The stack is already on the latest template version.
409 ConflictAn upgrade is already in progress, or the accepted cost drifted from the current estimate by more than $0.01. Re-preview and resubmit.
422 Unprocessable EntityThe plan is blocked. Launch a fresh stack to adopt these changes.

Monitoring the upgrade

While the upgrade is in progress, the stack's status moves to Upgrading. The StackMigration record returned by the 202 response tracks the upgrade's lifecycle:

Migration statusMeaning
AcceptedUpgrade accepted, reconciler not yet started.
ApplyingThe reconciler is applying in-place changes.
CompletedAll changes applied. The stack is back to Running.
FailedA single step failed (see below).

Retrieve the stack to see the current status:

curl https://api.foundrydb.com/stacks/$STACK_ID \
-H "Authorization: Bearer $FOUNDRYDB_TOKEN"

Failure behaviour

A failed upgrade rolls back only the in-flight change and returns the stack to Running. It never triggers a full stack teardown. Your data and the other running resources are unaffected.

The migration record's status moves to Failed and status_detail describes what went wrong. After reviewing the migration record, you can re-preview and reapply once you have resolved the issue, or leave the stack on its current template version.

Cost gate

The upgrade endpoint enforces the same cost gate as the launch endpoint. accepted_monthly_cost must be within $0.01 of the estimate returned by the upgrade preview. If the template's resources have changed price between preview and apply, you receive 409 Conflict and must re-preview.

Deciding between upgrade and a fresh stack

Use in-place upgrade when:

  • The only changes are app redeployments (new image version) or compute plan resizes.
  • You want zero-data-migration path.

Launch a fresh stack when:

  • The upgrade preview returns blocked: true.
  • The template adds or removes resources.
  • The database engine, version, storage size, or storage tier changes.
  • You want a clean-slate environment before migrating traffic.