⚠️ Porta is in beta — APIs and features may change before v1.0
Skip to content

Migrations

Porta uses node-pg-migrate for database schema management. All migrations are SQL files located in the migrations/ directory.

Running Migrations

Via CLI

bash
# Apply all pending migrations
porta migrate up

# Roll back the last migration
porta migrate down

# Check migration status
porta migrate status

Via Yarn

bash
# Apply migrations
yarn migrate

# Roll back
yarn migrate:rollback

# Check status
yarn migrate:status

# Create a new migration
yarn migrate:create my_migration_name

Migration Files

Migrations are numbered sequentially and applied in order:

#FileDescription
001001_extensions.sqlPostgreSQL extensions (pgcrypto, citext) and trigger_set_updated_at() function
002002_organizations.sqlOrganizations table with branding, status, super-admin constraint
003003_applications.sqlApplications and application_modules tables
004004_clients.sqlOIDC clients table with full OIDC configuration fields
005005_users.sqlUsers table with OIDC Standard Claims profile fields
006006_roles_permissions.sqlRoles, permissions, role_permissions, and user_roles tables
007007_custom_claims.sqlClaim definitions and user_claim_values tables
008008_config.sqlSystem configuration key-value table
009009_audit_log.sqlAudit log table with indexes on action, entity, actor
010010_oidc_adapter.sqlOIDC payload storage for long-lived tokens (PostgreSQL adapter)
011011_seed.sqlInitial seed data (signing keys table)
012012_two_factor.sqlTwo-factor authentication tables (TOTP, email OTP, recovery codes)
013013_client_secret_sha256.sqlSHA-256 pre-hash column for client secrets
014014_login_methods.sqlLogin methods columns on organizations and clients
015015_signing_key_encryption.sqlAdds KEK encryption columns to signing_keys table (preparation for future at-rest encryption)
016016_failed_login_count.sqlAdds failed_login_count and last_failed_login_at columns to users table for account lockout
017017_audit_retention.sqlAdds audit_retention_days entry to system_config for configurable audit log cleanup
018018_admin_api_enhancements.sqlAdds branding_assets table (org logo/favicon storage) and admin_sessions table (session tracking for admin viewer/revocation)
019019_invitation_details.sqlAdds details JSONB column and invited_by UUID column to invitation_tokens for enhanced invitations with role/claim pre-assignment

Writing Migrations

Conventions

  • File format: NNN_description.sql (3-digit zero-padded number)
  • Language: Pure SQL (no JavaScript migrations)
  • Idempotent: Use IF NOT EXISTS where possible
  • Reversible: Include both UP and DOWN sections

Template

sql
-- Up Migration
CREATE TABLE IF NOT EXISTS my_table (
    id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    name TEXT NOT NULL,
    created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
    updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);

-- Add auto-update trigger
CREATE TRIGGER set_updated_at
    BEFORE UPDATE ON my_table
    FOR EACH ROW
    EXECUTE FUNCTION trigger_set_updated_at();

-- Down Migration
DROP TRIGGER IF EXISTS set_updated_at ON my_table;
DROP TABLE IF EXISTS my_table;

Creating a New Migration

bash
yarn migrate:create add_my_feature

This creates a new file like migrations/015_add_my_feature.sql with UP and DOWN sections.

Environment Configuration

Migrations require the DATABASE_URL environment variable:

bash
DATABASE_URL=postgresql://user:password@localhost:5432/porta

Or pass it directly via the CLI:

bash
porta migrate up --database-url postgresql://user:password@localhost:5432/porta

Released under the MIT License.