Versioning and breaking changes
An update should add capability without asking you to migrate your data by hand or reinstall anything. That is a design rule with teeth, and here is how it is kept.
Migrations are additive first
- Every schema change ships as a numbered SQL migration that runs on the api's first boot after the update.
- Each migration runs inside its own transaction, so it either applies fully or not at all. A partial change is never left behind.
- The rule is add, don't rewrite. A new feature adds a column or a table. It does not drop or rename one out from under the running app.
- An older image keeps working against a newer schema (the extra column it does not know about is simply ignored), which is what makes stepping back to a previous version safe. See Rollback.
How a removal is split across releases
When a change does have to remove something, it is split across releases: an earlier release adds the new shape and writes to both old and new, a later one switches reads over, and only a release after that drops the old column.
Renaming a field never moves your data
- Fields are stored by a stable internal name, and the label you see is a presentation layer resolved when a form loads.
- Renaming changes the label, not the storage key, so the values stay exactly where they were. There is no data migration on a rename, ever.
- The same holds for hiding, reordering, or recoloring a field.
Self-heal, not reinstall
When a shape does change, the fix runs itself.
- On boot the api reconciles each workspace against the current code. A module that added a migration after a workspace enabled it gets caught up automatically, and a workspace that predates a newer structure is brought forward in place.
- You are never asked to uninstall and reinstall a module or a workspace to pick up a change. If an update ever did require that, it would be a bug, not a procedure.
What "breaking" means in practice
For a self-hoster, the change that hurts is one that requires manual work or loses data on the way up. The discipline above is aimed squarely at removing both.
- Read each release's notes before moving: pin
COBBLR_VERSIONrather than always taking the latest. Your own instance's/changelogpage carries them, and the tagged releases on the repository mirror them. - A one-time action is called out when a release needs one. The default
assumption is that
docker compose pull && up -dis all an update takes.