Skip to content

Upgrading

Nabeel Wasif edited this page Sep 29, 2026 · 1 revision

Upgrading

What each upgrade asks of someone already running Anonify. The authoritative per-release notes are in CHANGELOG.md and summarised in Release History.


The general procedure

git pull
pnpm install
pnpm db:migrate:deploy        # safe to run every time; a no-op when nothing is pending
pnpm build                    # or: docker compose up -d --build --wait

With Docker Compose, docker compose up -d --build is enough: the migrate service applies migrations (and the workflow schema) before the app starts. On Vercel, run pnpm db:migrate:deploy from your machine against production before deploying.

Never change ENCRYPTION_KEY during an upgrade. It would make every stored document permanently unreadable. pnpm setup offers to keep it.


Migrations by release

Release Migration What it adds
≤ 1.0.0 db_init, add_settings, add_document_error_code, add_export_report, add_batches, add_document_preset, add_format_quotas, add_batch_exports, add_attachment_provenance, add_redaction_method, add_export_variant, add_export_vault the base schema, settings, failure codes, export reports, batches, presets, per-format quotas, batch-export runs, attachment provenance, methods, variants, batch vaults
1.6.0 add_encryption_format Document.encryptionFormat (v0 / v1)
1.7.0 add_normalized_index Document.normalizedIndex (page offsets)
1.9.0 add_pattern_rules, add_assistant_quota RegEx / match-case / whole-word / enabled on rules, OwnerRule, UsageRecord.assistantTokens

Documents stored before a migration keep working. A v0 document stays v0 until it expires, and a model without a page index is read whole. Nothing is backfilled.


Release-specific notes

→ 1.10.0

  • The batch download defaults to original format: one upload comes back as that file (e.g. inbox-redacted.mbox), not a zip. Scripts calling GET /api/batches/:id/download that expect a zip should pass output=processed or output=both, or check content-type.
  • The archive is no longer flat (folders by upload, message number and part path; reports under reports/).

→ 1.9.0

  • Run the migration.
  • A batch or global rule that matches too much of a newly processed document now fails that document with rule-too-broad. It is retryable, and the document still opens for review.
  • New rate-limit bucket search (ANONIFY_RATE_LIMIT_SEARCH), and a new quota ANONIFY_QUOTA_ASSISTANT_TOKENS (300,000 on demo, unlimited on self-hosted). Set it explicitly on a shared instance.
  • The session cookie now renews on upload and on rule changes.

→ 1.8.0

  • If you built standalone on a machine with local storage and copied .next/standalone elsewhere, delete that copy's .anonify-storage (it also contained .env). See Deployment §4.
  • Set ANONIFY_PUBLIC_URL for correct link previews, then rebuild the image.

→ 1.7.0

  • Run the migration (the image does it).
  • Memory needs drop sharply; revisit any container memory limits you raised for large files.

→ 1.6.0

  • Run the migration before starting.
  • New documents are sealed in chunks, and existing ones stay readable. New optional settings: ANONIFY_ENCRYPTION_CHUNK_SIZE, ANONIFY_STREAM_MEMORY_BUDGET. The app refuses to start if the budget cannot give every concurrent document two chunks. Lower ANONIFY_BATCH_PROCESSING or raise the budget.

→ 1.5.0

  • Re-upload PDFs that were analysed before 1.5.0 if you want tight redaction boxes. Their boxes cover whole text runs as a fallback (GHSA-h3hv-rpqw-7p84).
  • Next.js moved to 16.3.6 and patched transitive dependencies were pinned; run pnpm install.

→ 1.3.0: MinIO to RustFS (Docker Compose only)

The local stack replaced the archived MinIO Community Edition with RustFS. Compose mounts your existing anonify_minio-data volume, and RustFS imports MinIO's unencrypted on-disk format in place, one way. After RustFS writes to it, MinIO can no longer read it.

  1. Stop the stack: docker compose down
  2. Back up the volume:
    docker run --rm \
      -v anonify_minio-data:/source:ro \
      -v "${PWD}:/backup" \
      alpine:3.22.1 \
      sh -c "cd /source && tar czf /backup/anonify-object-storage-before-rustfs.tgz ."
  3. Rename host-port overrides in .env: MINIO_PORT → RUSTFS_PORT, MINIO_CONSOLE_PORT → RUSTFS_CONSOLE_PORT. The application's S3_* settings keep their names and values.
  4. Start and check:
    docker compose up -d --build --wait
    pnpm smoke:storage http://127.0.0.1:9000
    docker compose logs --no-color rustfs rustfs-init app

Rollback means restoring the pre-migration backup and the previous application version together.

If you enabled MinIO server-side encryption (SSE-S3/KMS/C), tiering or custom bucket features, do not use the in-place path. Run the old server on a private endpoint, start RustFS on an empty volume, and copy through the S3 API:

rclone copy legacy:anonify rustfs:anonify --checksum --progress
rclone check legacy:anonify rustfs:anonify --checksum

(Anonify's own envelope encryption is unaffected: to the S3 server it is opaque bytes.) Full guide: docs/migrate-object-storage-to-rustfs.md.

→ 1.3.0: AI providers

Existing Gateway configurations keep working with no change. To switch provider, run pnpm setup or pnpm ai verify. A non-Gateway provider needs AI_MODEL and the AI_MODEL_CAPABILITIES declaration those commands write.


See also

Clone this wiki locally