Change History

What It Is

Every environment keeps a change history: an entry for each state its configuration has been in. An entry records:

WhatThe configuration (data model, roles and permissions, queries, views, automations and the rest of the tenant tree) and the release live for each Custom App
WhoThe people who made the change
From whereThe builder, the in-app AI assistant, the CLI, MCP, the REST API — or an operation: an apply from git, an app deploy or promotion, a restore, a package import
WhenWhen the change began and when it was recorded
MessageWritten by the platform ("added property client.vat_id; changed 2 grants of role sales"), or the commit subject when the change came from git

The History screen (Administration → History) lists the entries. A version is an entry with a name.

Why It Matters

  • One record of what happened, whether the change was made in the builder, by an assistant, or applied from a repository.
  • Restore any entry: the configuration and the apps' releases go back together.
  • Git sees every change. jetstack tenant pull brings each entry into the team's repository as its own commit, with its author and message.
  • Production can be guarded. A change policy decides whether production may be changed directly.

How It Works

Recording

  • Direct changes — in the builder, through the AI assistant, MCP, the REST API or the CLI — are recorded in the background, about a minute after they stop. A burst of edits becomes one entry that names everyone involved; the Event Log still says exactly who changed what. A change that goes on for ten minutes is recorded then, and the rest follows in the next entry.
  • Operations record their own entry when they end: an apply (with the commit it came from), a restore, a package import, a promotion (the tree and the apps together, with the commit). App deploys and rollbacks are recorded within a minute, with the release.
  • Nothing changed, no entry. An entry is recorded only when the state differs from the newest one. The exception is data migrations: restoring never undoes them, so the history says where they happened.
    • A migration that finished with a deploy or a promotion is listed on that entry.
    • Migrations that finished on their own get an entry of their own, Data migration. Examples are an app's background migration, or the platform's migrations after an upgrade.

Records, users, files and secrets are not part of the history: it describes how the platform is shaped, not what is inside it.

Comparing

Each entry shows what changed against the entry before it: entities added (+), changed (~, with the fields), removed (-), renamed, and app releases that changed. Any two entries can be compared with jetstack history diff.

Restoring

Restoring an entry makes the environment what it was then:

  • Configuration. The entry's configuration is planned against the live one and applied, like an apply from git. Entities added since are removed, including grants and translations.
  • Apps. Each app goes back to the release that was live in the entry. Apps the entry did not know stay as they are.
  • Always forward. The result is recorded as a new entry, "restored entry #N". Nothing in the history is erased, so a restore can itself be undone by restoring the entry before it.

The restore shows its plan first. Removing a type, property, role or another entity that holds records needs explicit consent, as in an apply, and records are not restored: a type removed since the entry comes back empty.

Neither are data migrations: they only go forward. The plan lists the migrations that ran after the entry and stay applied, on the restore page and in jetstack restore.

Git Mirrors The History

In a workspace, jetstack tenant pull --env prod replays production's entries since the last pull:

  1. Each entry becomes a commit on a branch of its own, jetstack/prod, with the entry's author, time and message, and a Jetstack-Entry: prod/<id> trailer.
  2. That branch is merged into yours. A conflict is an ordinary git conflict in one file of tenant/.
  3. The environment learns that the entries are in git, so they stop waiting for review.

jetstack tenant apply and app deploys send the commit they come from, and the entry records it: the next pull knows that state is already in git.

.jetstack/sync.json remembers, per environment, the last entry taken and the commit that holds it. Commit it with the workspace.

Production Change Policy

How production's configuration may change is the tenant's choice:

PolicyDirect changes to productionApplying to production
Open (default)Allowed and recordedGoes ahead
ReviewedAllowed, recorded and marked needs reviewWaits until those entries are pulled into git or acknowledged in History
LockedRefused, with a message pointing to development and promotionGoes ahead
  • Development is always open. The policy applies to the production environment only.
  • Under Locked, the builder, the AI assistant, MCP, the REST API and the CLI's direct changes are refused on production. Applies from git, app deploys and promotions, and restores still work. A superuser can unlock production for 30 minutes on the History screen, giving a reason; changes made meanwhile are recorded with it and marked needs review.
  • Under Reviewed, an apply to production is refused (409) while direct changes wait for review, so it cannot overwrite them unseen. Pull them (jetstack tenant pull --env prod), or acknowledge them on the entry's page.

Setting The Policy

A tenant administrator or superuser sets production's policy, in one of two ways:

  • On production's History screen, under the current policy: choose Open, Reviewed or Locked, optionally say why, and choose Change.
  • With the CLI: jetstack history policy reviewed --env prod --reason "Changes go through git from now on". Without a policy, jetstack history policy --env prod shows the current one.

Each change goes into the Event Log with the reason. Pipeline tokens cannot change the policy, so a pipeline never loosens its own rules. Development has no policy: it is always open.

Data Migrations On Production

Next to the change policy, production's History screen sets what data migrations need before they run on production (setting productionMigrationApproval):

SettingA deploy or promotion that runs data migrations on production
Confirmation (default)The person deploying sees each migration in the plan and confirms it explicitly: a checkbox in the browser, a question of its own in the CLI. A script passes --allow-migrations; --yes alone is not enough.
A second person's approvalThe deploy waits, as for an app that requires approval. Another person approves it after reviewing the migrations and their code. A configuration apply (or promotion) whose tree has migrations waits as a request at the top of production's History screen: Review shows the migrations' code, then Approve and apply or Reject (jetstack approve --tenant in the CLI).

Production asks once per migration. A migration an earlier deploy or apply there already let run is not asked about again while its code stays the same: a background migration still going, or a blocking one that failed and runs again. The plan shows it as already queued here.

A tenant administrator or superuser changes it on production's History screen (Data migrations), or with jetstack migrations policy approval --env prod --reason "…". Each change goes into the Event Log. The Data migrations page beside it lists every migration of the environment — the platform's, each app's and the tenant configuration's — with its state, progress and error, and retries a failed one.

How To Use It

Find Out Who Changed Something

Open History and look for the entry, or run jetstack history --env prod. The entry page lists what changed. For the exact steps, open the Event Log at the entry's time.

Undo A Change On Production

  1. Find the last good entry on History.
  2. Open it and choose Restore.
  3. Read the plan, especially removals, and confirm.

From the CLI: jetstack restore <entry> --env prod. Then pull the result into git: jetstack tenant pull --env prod.

Keep Production In Git

  1. Connect a workspace to the tenant.
  2. Set the policy to Reviewed, so nothing reaches production unseen.
  3. Make changes on development, pull them into tenant/, review them in a pull request, and apply to production from the merged branch.
  4. When someone changes production directly, pull it before the next apply.

Switch to Locked once every change goes through git.

Example

Acme keeps its tenant in git, with the Reviewed policy.

  1. On Friday evening, a support lead adds a "VAT ID" field to the client type directly on production. History records entry #212, "added property client.vat_id", by the support lead, marked needs review.
  2. On Monday, a developer's jetstack tenant apply --env prod is refused: entry #212 is not in git yet.
  3. The developer runs jetstack tenant pull --env prod. Entry #212 arrives as a commit by the support lead and merges cleanly, and the field is now in tenant/types/client.json.
  4. The apply goes ahead, recorded as entry #213 "Add invoice numbering", with the commit it came from.

Best Practices

  • Publish a version (a named entry) at each release that integrations should know about; backend.version reports the newest.
  • Pull production into git regularly, and always before applying to it.
  • Restore rather than repair by hand: the plan shows exactly what changes, and the history keeps both states.
  • Use Locked only when the whole team works through development and git; an override is for emergencies.
  • Keep database backups for records: a restore brings back the configuration, never the data.

Tenant Settings

These keys are not on the Application settings screen; set them in the tenant configuration.

productionChangePolicy

How production's configuration may change: open (default), reviewed or locked. See Production Change Policy. Set it on production's History screen or with jetstack history policy (see Setting The Policy). It has no effect on a development environment.

Whether a tenant is production comes from its setup in isolated environments, and from environmentRole elsewhere.

productionMigrationApproval

What running data migrations on production needs:

  • confirm (default): the person deploying or promoting confirms them explicitly;
  • approval: a second person approves them, after seeing their code.

See Data Migrations On Production. Set it on production's History screen or with jetstack migrations policy. It has no effect on a development environment, which runs migrations as they are deployed.

configHistoryRetentionDays

How long entries are kept, in days (default 365). Older entries are removed, except:

  • named entries (versions);
  • entries that came from git or were pulled into git;
  • entries still waiting for review;
  • the newest entry.

0 keeps everything.