Skip to content

Migrations

Authara requires a PostgreSQL database schema.

Schema changes are managed through explicit migrations.

Authara does not automatically mutate the database schema at runtime.

Instead:

  1. migrations are applied explicitly
  2. Authara starts against the resulting schema
  3. Authara validates the schema version at startup

This behavior is intentional and keeps database changes predictable and operator-controlled.


Why migrations are separate

Database schema changes are part of the operational lifecycle of Authara.

They are not runtime behavior.

This means:

  • schema changes are applied explicitly
  • startup is deterministic
  • upgrades are controlled
  • runtime does not mutate shared state unexpectedly

Authara treats schema management as an operator responsibility.


Migration Image

Authara provides a dedicated migration image.

This image contains:

  • the SQL migration files
  • the migration runner
  • the logic required to apply schema changes

It does not start the Authara server.

It runs migrations and exits.


Applying migrations

Migrations are typically applied using the migration image before starting Authara.

Example:

docker run --rm \
  --env-file .env \
  ghcr.io/authara-org/authara-migrations:${AUTHARA_MIGRATIONS_VERSION:-v0.1.20} \
  up -env=default -config=/migrations/dbconfig.yaml

This applies all pending migrations and exits.

Use the migrations image listed in the Core release notes. The attached authara-images.env contains the same version and immutable image reference for deployment tooling.


Configuration

The migration image uses the same PostgreSQL connection variables as Authara Core.

Required variables include:

POSTGRESQL_HOST=postgres
POSTGRESQL_PORT=5432
POSTGRESQL_DATABASE=authara
POSTGRESQL_USERNAME=authara
POSTGRESQL_PASSWORD=authara
POSTGRESQL_SSL_MODE=disable

For TLS-enabled PostgreSQL, use the same values as Core:

POSTGRESQL_SSL_MODE=verify-full
POSTGRESQL_SSL_ROOT_CERT=/certs/postgresql-ca.pem

Mount a private CA file at that path in the migrations container. See the database connection documentation for all supported verification modes.

These variables may be provided through:

  • .env
  • container environment variables
  • CI secrets
  • orchestration platforms

Typical usage

Migrations should be applied:

  • before the first startup
  • before starting a newer Authara version with a changed schema
  • in CI when testing schema compatibility

Typical operational flow:

  1. Start PostgreSQL
  2. Run migrations
  3. Start Authara Core
  4. Start the gateway and application

Development

Migrations are required in development as well.

Even in local development, Authara expects the database schema to already exist.

This keeps development behavior consistent with staging and production.

Example local flow:

  1. Start PostgreSQL
  2. Run migrations
  3. Start Authara

Schema compatibility check

Authara validates the schema version at startup.

If the database schema does not match the version required by the running Authara binary, startup fails.

This prevents:

  • partially upgraded deployments
  • accidental runtime mismatches
  • undefined database behavior

In other words:

If Authara starts successfully, the schema version is compatible.


Rollbacks

Rollback behavior depends on the migrations that have been applied.

Schema rollbacks should be treated as an advanced operational task.

Before rolling back:

  • understand the migration contents
  • evaluate possible data loss
  • test the rollback path in a safe environment

Authara does not assume that rollbacks are always safe.


Summary

Authara migrations are:

  • explicit
  • operator-controlled
  • required in development and production
  • validated through schema version checks at startup

This keeps schema evolution predictable and prevents hidden runtime database changes.

Runtime-settings upgrade

Schema version 24 adds runtime_settings_state, runtime_setting_overrides, and the per-challenge minimum_resend_interval_ns column. Apply migration 024 before deploying the matching Core binary. With no override rows, effective behavior remains the same as the existing environment configuration and built-in defaults. The new column remains null on pre-v24 challenge rows so their resend delay continues to follow the effective policy, as it did before the value was persisted.

Session-bound email-change upgrade

Schema version 25 binds pending email changes to the session that initiated them. Applying migration 025 cancels existing email-change challenges because they cannot be safely attributed to an initiating session.

Durable email-delivery upgrade

Schema version 26 adds delivery deadlines, terminal failure metadata, and an index for reclaiming expired email-processing leases. Existing challenge email jobs inherit their challenge expiry; other existing jobs receive a deadline 72 hours after their original creation time. Apply migration 026 before deploying the matching Core binary.

Singleton cleanup upgrade

Schema version 34 adds the shared cleanup lease. Schema version 35 adds the supporting partial indexes with concurrent PostgreSQL index builds so existing table writes remain available during the migration. Apply both migrations before deploying the matching Core binary. Because migration 035 is non-transactional, it drops its own known index names before rebuilding them; this makes an interrupted run safe to retry even if PostgreSQL left an invalid concurrent index behind.