I ship schema changes in an offline-first Expo app.
I run migrations inside a single SQLite transaction.
I use PRAGMA user_version as my only “migration table”.
I added a tiny verifier to catch broken migrations fast.
Context
I’m building a React Native fitness app. Expo. SQLite. Offline-first.
Workouts must log without internet. Always.
Then the real problem hits. Schema changes.
I started with “I’ll just add a column”. Brutal.
One bad ALTER in production and you’ve got users stuck on an old schema, with data you can’t read, and no easy way to recover.
I tried keeping migrations in my head. That lasted 2 days.
Then I spent 4 hours debugging “no such column: sets.rpe”. Most of it was wrong.
What finally worked: PRAGMA user_version + transactional migrations + a startup verifier.
No ORM. No magic.
1) I treat migrations like app code.…