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. Versioned. I don’t keep a migrations table. I keep one number. SQLite already has it: PRAGMA user_version .…