hj migrations
Run and manage HelloJohn database migrations from the CLI — apply, rollback, status, and best practices for zero-downtime upgrades.
hj migrations
The hj migrations command group manages database schema migrations. Migrations must be run after updating HelloJohn to a new version and before starting the server.
Commands
| Command | Description |
|---|---|
hj migrations status | Show current migration state |
hj migrations run | Apply pending migrations |
hj migrations rollback | Roll back the last migration batch |
hj migrations list | List all migrations and their status |
hj migrations validate | Validate database schema matches expected state |
hj migrations status
Check the current migration state of your database:
hj migrations statusDatabase: postgresql://user:***@host:5432/hellojohn
Schema version: 20240115_001
Pending migrations: 2
PENDING 20240601_001_add_passkey_support
PENDING 20240601_002_session_device_fingerprintIf there are no pending migrations:
✅ Database schema is up to date (version: 20240601_002)Flags:
| Flag | Description |
|---|---|
--database-url <url> | Override HELLOJOHN_DATABASE_URL |
hj migrations run
Apply all pending migrations:
hj migrations runRunning 2 pending migrations...
✅ 20240601_001_add_passkey_support (234ms)
✅ 20240601_002_session_device_fingerprint (89ms)
Migrations complete. Schema version: 20240601_002Flags:
| Flag | Description |
|---|---|
--database-url <url> | Override HELLOJOHN_DATABASE_URL |
--dry-run | Show what would be run without executing |
--timeout <duration> | Per-migration timeout (default: 5m) |
Dry Run
Preview migrations without applying:
hj migrations run --dry-runDRY RUN — No changes will be made
Would apply 2 migrations:
20240601_001_add_passkey_support
20240601_002_session_device_fingerprinthj migrations rollback
Roll back the most recently applied batch of migrations:
hj migrations rollback⚠️ Rolling back migration batch...
↩️ 20240601_002_session_device_fingerprint (56ms)
↩️ 20240601_001_add_passkey_support (120ms)
Rollback complete. Schema version: 20240115_001Most HelloJohn migrations are forward-only. Rollback support is limited to migrations that include a
downscript. Check the changelog for rollback compatibility.
Flags:
| Flag | Description |
|---|---|
--steps <n> | Number of batches to roll back (default: 1) |
--dry-run | Preview rollback without executing |
hj migrations list
List all migrations with their status:
hj migrations listVERSION STATUS APPLIED AT
20240115_001_initial_schema applied 2024-01-15 09:00:00
20240201_001_add_organizations applied 2024-02-01 12:30:00
20240301_001_mfa_totp applied 2024-03-01 15:45:00
20240401_001_passkeys applied 2024-04-01 10:00:00
20240501_001_webhooks applied 2024-05-01 11:22:00
20240601_001_add_passkey_support pending —
20240601_002_session_device_fp pending —hj migrations validate
Validate that the database schema matches what HelloJohn expects:
hj migrations validate✅ Schema validation passed
All 34 tables present
All indexes present
All constraints validIf validation fails:
❌ Schema validation failed
Missing table: hj_passkey_credential
Missing index: idx_hj_session_user_id_activeRun hj migrations run to apply missing migrations.
Deployment Workflow
Standard Deployment
The recommended workflow for upgrading HelloJohn:
# 1. Pull the new HelloJohn version
docker pull hellojohn/server:latest
# 2. Run migrations before starting new instances
docker run --rm \
-e HELLOJOHN_DATABASE_URL="$DATABASE_URL" \
hellojohn/server:latest \
hj migrations run
# 3. Deploy new instances
docker compose up -d hellojohnZero-Downtime Migrations
HelloJohn migrations are designed to be backward-compatible — old instances can run against the new schema while new instances are rolling out:
- Run migrations (new schema, old code still works)
- Roll out new HelloJohn instances (blue/green or rolling)
- Old instances continue serving during rollout
- Once all instances are updated, the migration window closes
What this means: Migrations never remove columns or tables in the same release they add replacements. Old columns are removed in a subsequent release only after all instances have been updated.
Kubernetes Deployment
Use an init container to run migrations before the main container starts:
initContainers:
- name: migrate
image: hellojohn/server:v2.0.0
command: ["hj", "migrations", "run"]
env:
- name: HELLOJOHN_DATABASE_URL
valueFrom:
secretKeyRef:
name: hellojohn-secrets
key: database-urlSee Kubernetes Deployment for a full example.
Troubleshooting
Migration stuck or timed out
If a migration times out, check for long-running PostgreSQL locks:
SELECT pid, now() - pg_stat_activity.query_start AS duration, query, state
FROM pg_stat_activity
WHERE (now() - pg_stat_activity.query_start) > interval '5 minutes';Cancel blocking queries:
SELECT pg_cancel_backend(pid);Migration failed partway through
Migrations run in transactions. If a migration fails, changes are rolled back automatically. Fix the underlying issue and run hj migrations run again.
Database URL not configured
Error: HELLOJOHN_DATABASE_URL is not setPass it explicitly:
hj migrations run --database-url "postgresql://user:password@host:5432/hellojohn"