Appearance
Upgrading
Clean upgrade path
The recommended upgrade process follows the immutable-infrastructure model: new container image, same data volumes.
1. Read CHANGELOG → 2. Back up → 3. Bump image tag → 4. Redeploy → 5. Apply migrations → 6. Set new env vars1. Read the CHANGELOG
Before every upgrade, read CHANGELOG.md at the new version tag. Note:
- Breaking changes — env var renames, Docker identifier changes, config relocation
- New required env vars — boot will fail if missing
- Schema changes — additive columns are safe; renames/drops need a manual plan
2. Back up
Take a full backup before every upgrade. See Backup & Retention.
bash
docker exec postmill-postgres pg_dump -U postmill-user postmill-db-local > pre_upgrade_$(date +%Y%m%d).sql3. Bump the image tag
yaml
# docker-compose.yaml or your deployment config
services:
postmill:
image: ghcr.io/postmill-ai/postmill-app:v1.0.0 # pin a specific tag, not :latestPinning specific tags gives you a known rollback target. Using :latest means every restart may pull an untested version.
4. Redeploy
bash
# Docker Compose
docker compose pull postmill
docker compose up -d postmill
# Coolify / Portainer / Kubernetes
# Trigger a redeploy of the postmill service with the new image tag5. Apply migrations
The container runs prisma-generate on boot (via postinstall), regenerating the Prisma client to match the schema baked into the new image. It does not apply committed migrations automatically.
Postmill ships committed Prisma migrations under libraries/nestjs-libraries/src/database/prisma/migrations/. The canonical apply path is prisma migrate deploy:
bash
# Run inside the running container
docker exec postmill pnpm dlx prisma@6.5.0 migrate deploy \
--schema ./libraries/nestjs-libraries/src/database/prisma/schema.prismaFor a quick local reset only, you can use pnpm run prisma-db-push / pnpm run prisma-reset. Never use db push against a shared or production database.
If a release includes destructive changes (column/table drops, in-place renames), read the CHANGELOG carefully, take a backup, and follow the expand-contract path documented in Database.
6. Set new env vars
Check the CHANGELOG for any new env vars required by the release. Add them to your .env file, Docker Compose environment, or deployment config, then redeploy if needed.
v1.0.0
v1.0.0 ships with zero legacy support. Note these points when upgrading into it:
- Destructive migration —
20260830180000_no_legacy_v1drops theAIProviderConfigandProviderConfigurationtables, theAISystemSettingscolumnsactiveProvider/activeModel/scopeModels/rateLimitSettings, and theUserProfilecolumnssendSuccessEmails/sendFailureEmails/sendStreakEmails. It also removesmastra_ai_spans/mastra_evalsfrom the Prisma schema (Mastra still owns those tables at runtime). Applying it requiresALLOW_DESTRUCTIVE_SCHEMA=trueonmigrate deploy. Take the pre-upgradepg_dumpfirst — rollback means restoring that backup. - Automatic backfills — no manual data steps are needed. A ledger-gated boot step (
backfill:legacy secret re-encryption) re-encrypts any secrets stored under an older encryption format to AES-256-GCMv2:— now the only accepted ciphertext — before strict reads matter, and the migration backfillsIntegration.providerConfigId. Let the first boot of the new image complete before putting the instance under load. - Deprecated env-var warnings removed — the boot configuration checker no longer warns about deprecated environment variables (the warning lists were deleted). Fatal guards for missing required secrets still apply.
Manual schema sync
If you need an in-place schema sync outside the normal migration flow, use the helper script:
bash
# Safe additive sync (refuses data loss)
./tools/db/postmill-migrate.sh
# Destructive — back up first!
./tools/db/postmill-migrate.sh --accept-data-lossOr run directly in the container:
bash
docker exec postmill pnpm dlx prisma@6.5.0 db push \
--schema ./libraries/nestjs-libraries/src/database/prisma/schema.prismaAlways back up before
--accept-data-loss. See Backup & Retention and Database schema safety.
Schema change rules
Releases follow additive-schema-only rules so migrate deploy against a live database usually works without data loss:
- New tables are always safe
- New columns are nullable or defaulted — safe
- Renames/drops are destructive and uncommon — noted prominently in the CHANGELOG when they occur
Renames and drops — expand-contract
A destructive migration drops or renames a column/table and loses data. Never rename or drop a column or table in the same release that stops using it. Instead, spread the change across releases:
- Expand — add the new nullable column alongside the old one and deploy.
- Backfill — copy data from the old column to the new one (add a one-time step to
BackfillService,libraries/nestjs-libraries/src/database/seeds/backfill.service.ts). - Switch — point all reads and writes at the new column and deploy.
- Contract — only once nothing references the old column (prove it with a grep) drop it in a later release, after taking the pre-migration
pg_dump.
Rollback
Migrations are forward-only. To roll back a destructive change, restore the pre-upgrade pg_dump:
bash
# Stop the app first so nothing writes during the restore
cat pre_push_YYYYMMDD_HHMMSS.sql | docker exec -i postmill-postgres \
psql -U postmill-user -d postmill-db-localThen redeploy the previous image tag.
Drift check
After deploying, confirm the live database matches the committed schema. prisma migrate diff exits 2 when there is a difference, 0 when there is none:
bash
pnpm exec prisma migrate diff \
--from-schema-datamodel libraries/nestjs-libraries/src/database/prisma/schema.prisma \
--to-url "$DATABASE_URL" \
--exit-codeThe mastra_* tables are created at runtime by the Mastra chat agent, outside the Prisma schema, so they always appear as out-of-schema drift — that is expected noise, not a real diff.
Building from source
If you prefer to build the container image locally:
bash
# Build the image
./docker/docker-build.sh
# Or with the dev compose stack for local development
docker compose -f docker/docker-compose.dev.yaml up -d
# Build all apps from source
pnpm run buildRollback
If an upgrade causes issues:
- Set the image tag back to the previous version.
- Redeploy.
- Restore the database from the pre-upgrade backup if the upgrade applied destructive schema changes.
Related
- Backup & Retention — backup before upgrade
- Developer Docs: Database — schema management and safety
Verified against v1.0.0