Upgrading
Deploying a new version safely, including the migrations that must run before traffic returns.
The procedure
- 1
Back up the database
Before anything else, and verify the backup completed rather than assuming it did.
- 2
Enter maintenance mode
bashphp artisan down --render="errors::503" --retry=60 - 3
Pull and install
bashgit pull composer install --no-dev --optimize-autoloader npm ci && npm run build - 4
Migrate
bashphp artisan migrate --force - 5
Rebuild caches
Every one of these, in this order. A stale route cache after a release that added routes produces 404s on the new endpoints only, which is a confusing thing to debug.
bashphp artisan config:cache php artisan route:cache php artisan view:cache php artisan event:cache - 6
Restart the workers
They hold the old code in memory and will keep running it otherwise.
bashphp artisan queue:restart - 7
Come back up
bashphp artisan up - 8
Verify
Sign in, read a secret back, and check the operations page. Then check that a queued email actually arrives.
Migrations that change behaviour
Most migrations only alter schema. A few backfill state, and skipping one changes what customers experience rather than breaking the deployment outright - which makes them easy to miss.
| Migration | What it does | If it does not run |
|---|---|---|
Backfill onboarding state | Backdates existing members from their join date. | Every existing customer is pushed into first-run setup on their next visit. |
Add current organization | Adds the workspace pointer. | The workspace switcher has nothing to point at. |
Convert billing schema | Moves billing onto Paddle. | Subscription state cannot be read. |
php artisan migrate --force runs all of them. They are listed here so that a partial or manual migration is recognisable as the cause when something looks wrong afterwards.
One-off tasks after upgrading
Some releases add a command that must be run once. Check the release notes; the current one is:
php artisan encryption:rewrapMigrates master keys from the legacy APP_KEY wrapping onto SHORTSPAN_MASTER_KEY. Both wrappings resolve correctly, so this is not urgent for correctness - but until it runs, APP_KEY is still load-bearing for the secret store and must not be rotated.
The operations health check reports how many keys remain on the legacy wrapping, so you can confirm it finished rather than assuming.
Upgrading the CLI
The CLI and the application version independently. A newer CLI works against an older application, and vice versa, within the v1 API.
If you distribute your own build, publish it through the pipeline API so shortspan upgrade finds it. If you do not, leave SHORTSPAN_RELEASE_TOKEN unset - the endpoint is then closed, and clients simply never see an upgrade.
Rolling back
Check out the previous tag, reinstall dependencies, rebuild caches, and restart workers. Migrations are the hard part: not all are reversible, and a migrate:rollback that drops a column drops the data in it.
In practice, restoring the database backup and the previous code is safer than unwinding migrations, and is why the first step of the procedure is the backup.
Something here wrong or missing? Tell us.