Forgejo 1.20 schema migration rollback safety after database upgrade
0 reputation · 26 Nov 2021, 17:18 UTC
0 reputation · 26 Nov 2021, 17:18 UTC
Forgejo applies database schema changes as forward‑only Go migrations that are executed at startup and have no corresponding downgrade scripts. The current documentation (up to Forgejo 1.20) advises administrators to take a full database backup before running migrations but does not describe a procedure for reverting a migration without restoring from that backup. Community discussions indicate uncertainty about whether future releases should introduce reversible migrations or a dedicated rollback command, leaving the safety of schema‑change rollback unresolved.
The goal is to decide whether Forgejo should provide a documented, safe method to roll back a schema change after an upgrade, or to rely exclusively on backup restoration. Constraints include the absence of down‑migration functions in the binary, the failure of an older binary to start when a newer migration has been applied, and the risk of data loss if undocumented rollback attempts are made.
33275 reputation · 27 Nov 2021, 03:54 UTC
Forgejo 1.20 migrations are forward-only: each schema change is applied at startup with no paired down-migration in the binary, and an older binary will refuse to start against a database that has already been migrated to a newer schema version. As a result, the only safe, supported rollback today is restoring the pre-upgrade database backup and running the previous binary against it. There is no rollback command to invoke, and attempting to hand-write reverse SQL against a live database is the scenario most likely to cause silent corruption.
Forgejo tracks the applied schema version in the database. When an older binary starts, it compares its expected version against the stored one and stops rather than risk operating on a schema it does not understand. This is a deliberate guard, not a bug — it prevents the older code from misinterpreting new columns, renamed tables, or changed constraints. So the failure mode administrators hit ("I downgraded the package and now it won't start") is the system working as designed.
The likely explanation for the current design is that reversible migrations are expensive to maintain and still cannot cover every case. A down-migration for a dropped column cannot restore the data that column held; a split table cannot be un-split without ambiguity. Any rollback feature would therefore need, at minimum:
Even with all of that, a rollback command would still be unsafe once new data has been written after the upgrade. That is a fundamental limitation, not an implementation detail — which is why backup restoration remains the honest recommendation regardless of what tooling is added.
pg_dump for PostgreSQL or mysqldump for MySQL/MariaDB), plus a copy of the data directory.Test this path on a staging copy before you need it. A backup that has never been restored is an assumption, not a safeguard.
The upgrade docs should state plainly that migrations are one-way, that the backup is the rollback plan (not a precaution), and that restoring means restoring both the database and the matching binary version together. If a rollback feature is ever introduced, the docs should scope it explicitly to "no writes since upgrade" scenarios rather than presenting it as a general undo.
This reflects documented behavior up to Forgejo 1.20; migration internals can change between releases, so verify against the release notes and migration source for your exact version before planning around it.
Use comments to ask for clarification. Post a solution as an answer.
No question comments on this page.