Skip to content

Flyway is authoritative for database indexes

Every database index in any Arda back-end service is declared and managed by a Flyway migration. Exposed-level .index(...) declarations on table objects are decorative — they do not create indexes at runtime and must not be added.

Where indexes liveAuthoritative?
Flyway migration scripts (src/main/resources/.../database/migrations/V*.sql)Yes — single source of truth
Exposed Table declarations using .index(...)No — decorative; the schema-emit path is not invoked in any Arda deployment

When adding, modifying, or removing an index:

  1. Author a new Flyway migration with the appropriate CREATE INDEX, DROP INDEX, or ALTER INDEX statement.
  2. Do not add a chained .index(...) call on the Exposed Table declaration. Existing decorative declarations are scheduled for removal.
  3. If the index requires CREATE INDEX CONCURRENTLY (low-write-impact online deploys), use the executeInTransaction=false Flyway sidecar and ensure common-module’s DbMigration is configured with mixed=true + the non-transactional advisory-lock mode (both already true post-PDEV-490).

Exposed offers a .index("idx_name") method on column declarations that appears to create the index but is part of Exposed’s schema-emit / DDL generation path. That path is invoked only by Exposed’s SchemaUtils.createMissingTablesAndColumns(...) and equivalents — which are not called in any Arda deployment pipeline. Arda relies exclusively on Flyway to apply DDL.

A .index(...) declaration on an Exposed Table therefore:

  • Does not create the index at deploy time.
  • Does not ensure the index exists in any environment.
  • Misleads readers into believing an index is in place when only Flyway can guarantee it.

Two such decorative declarations existed in common-module prior to PDEV-490: AbstractScopedUniverse’s tenantId.index("TENANT_ID_INDEX") and similar patterns. Both have been removed; the Flyway tree carries the real tenant_id index for every consumer that uses one.

To verify that an Exposed ScopedTable consumer actually has the indexes it expects:

Terminal window
grep -rE "CREATE INDEX|create index" <service>/src/main/resources/**/database/migrations/

Or query the live database:

SELECT tablename, indexname, indexdef
FROM pg_indexes
WHERE schemaname = 'public'
AND tablename = '<table-name>'
ORDER BY indexname;

The PDEV-490 audit found that kanban_card was missing its tenant_id index despite an Exposed-level declaration — the index was added by Flyway as part of that project.


Copyright: (c) Arda Systems 2025-2026, All rights reserved