Core Concepts

Plan & Apply

See exactly what a change will do before it runs, and refuse to run it if the ground has moved underneath.

Most panels ask "are you sure?" and then do something you could not see. FlatRun lets you ask any mutating request for a preview instead: what will change, from what to what, and why. You review it, then apply it.

Asking for a plan

Add ?plan=true to a mutating call and it stops short of executing. You get back a plan instead of a result:

The CLI exposes the same control on every operation that declares plan support:

flatrun deployments delete staging --plan \
  -q delete_ssl=true \
  -q delete_database=true \
  -q delete_vhost=true
  • Changes: each affected resource, whether it is created, updated, deleted, or left alone, the before and after values, and the reason.
  • Summary: how many of each, so a one-line change and a fifteen-resource change are distinguishable at a glance.
  • Snapshot: a hash of every file the change depends on.
  • Who and when: the actor who created it, and when it expires.

Values marked sensitive come back as [redacted], so a plan for an environment change is safe to paste into a ticket or a review thread.

Applying it

POST /api/plans/:id/apply runs the request the plan was made from. It is not a fresh execution of whatever you happen to send: the plan carries the original request, so what runs is what you reviewed.

Before anything happens, the snapshot is re-checked. If a file has changed since the plan was created, the apply is refused with the list of paths that drifted and the plan is marked obsolete. Create a new plan, read it, apply that. A stale plan cannot quietly overwrite someone else's work.

Plans expire after 24 hours by default (plans.ttl), and an expired one is refused rather than run. A plan is single-use: once applied, failed, or obsolete, it cannot be applied again.

Requiring a plan

Preview is optional per request, but a deployment can be set to require it. With that on, a direct mutating call is refused with plan_required and the only way through is to create a plan, read it, and apply it. Use it on the deployments where an accident is expensive: the client's production site, the shared database, the box the business runs on.

What can be planned

Area Actions
Deployment Environment update, compose update, delete
Services Start, stop, restart, pull, rebuild
Domains Add, update, delete
Proxy Setup
Agent Configuration update

Endpoints

  • GET /api/plans: plans that exist, with their status.
  • GET /api/plans/:id: one plan, with sensitive values redacted.
  • POST /api/plans/:id/apply: run it.
  • DELETE /api/plans/:id: discard one you decided against.

Applying a plan needs the same permission the original action needed, checked again at apply time. A plan is a preview, never a way around authorization.

Star us on GitHub