How Database Migrations Are Managed in Akash Console: A Complete Guide to Drizzle ORM
Akash Console manages database migrations using Drizzle ORM's built-in migrator, storing versioned SQL files in apps/indexer/drizzle/ and automatically applying pending changes on application startup via the Postgres provider.
Akash Console is a complex multi-application repository that relies on PostgreSQL for data persistence. To keep the database schema synchronized with the evolving codebase, the project implements a robust migration system using Drizzle ORM. This approach ensures that schema changes are version-controlled, reproducible, and automatically applied across production and test environments.
Migration Architecture Overview
The migration system in Akash Console follows a file-based approach where each schema change is stored as a numbered SQL file. The Drizzle ORM migrator compares these files against a metadata table in the database (drizzle_meta) to determine which migrations have already been applied and which need to run.
This architecture separates the concerns of schema definition, migration generation, and runtime execution across different applications within the monorepo.
Where Migration Files Are Stored
All migration files reside in the indexer application directory:
apps/indexer/drizzle/
├── 0000_chunky_rattler.sql
├── 0001_add_bseq_to_bid_and_lease.sql
├── 0002_add_provider_attributes.sql
└── ...
SQL File Structure and Naming Convention
Migration files follow a strict numeric prefix pattern (0000_, 0001_, etc.) that ensures sequential execution. Each file contains raw SQL statements that modify the database schema, such as CREATE TABLE, ALTER TABLE, or CREATE INDEX commands.
The Drizzle ORM migrator reads these files in alphabetical order, ensuring that dependencies between schema changes are respected.
Configuration and Schema Definition
Drizzle-Kit Configuration File
The migration generation process is controlled by apps/indexer/drizzle.config.ts. This configuration file specifies:
- The path to the TypeScript schema definition (
schema.ts) - The output directory for generated SQL migrations
- Database connection parameters for introspection
When developers modify the schema in schema.ts, they run the Drizzle-Kit CLI to generate new SQL migration files based on the differences between the current schema and the database state.
Environment Configuration
The runtime migration system is configured through apps/api/src/core/config/env.config.ts:
DRIZZLE_MIGRATIONS_FOLDER: z.string().optional().default("./drizzle"),
This environment variable allows operators to override the default migrations folder location if needed, though the standard deployment uses the default path pointing to apps/indexer/drizzle.
Runtime Migration Execution
Automatic Migration on Startup
When the API service starts, it immediately runs pending migrations before accepting traffic. This ensures the database schema is always compatible with the application code version.
The migration logic resides in apps/api/src/core/providers/postgres.provider.ts.
The migrate() Function Implementation
The provider creates a dedicated migration client and invokes Drizzle's migrate function:
// apps/api/src/core/providers/postgres.provider.ts
import { drizzle } from "drizzle-orm/postgres-js";
import { migrate } from "drizzle-orm/postgres-js/migrator";
const pgMigrationDatabase = drizzle(migrationClient, getDrizzleOptions(config));
await migrate(pgMigrationDatabase, {
migrationsFolder: config.DRIZZLE_MIGRATIONS_FOLDER,
});
This code:
- Creates a Drizzle client connected to PostgreSQL
- Calls
migrate()with the database instance and migrations folder path - Automatically applies any SQL files not yet recorded in
drizzle_meta
The migration runs with a maximum of one connection ({ max: 1 }) to prevent conflicts during schema changes.
Testing with Migrations
Isolated Test Database Setup
Both the API and notifications services use migration-aware test helpers to ensure test databases match the production schema.
In apps/api/test/services/test-database.service.ts:
import { drizzle } from "drizzle-orm/postgres-js";
import { migrate } from "drizzle-orm/postgres-js/migrator";
import { join } from "path";
export async function createTestDatabase() {
const migrationClient = postgres(process.env.TEST_POSTGRES_URI, { max: 1 });
const pgMigrationDatabase = drizzle(migrationClient);
const migrationsFolder = join(process.cwd(), "../indexer/drizzle");
await migrate(pgMigrationDatabase, { migrationsFolder });
return drizzle(migrationClient);
}
A similar pattern appears in apps/notifications/test/services/test-database.service.ts. This ensures every test run starts with a fresh, fully-migrated database instance.
Creating New Migrations
Developers generate new migrations using the Drizzle-Kit CLI. When schema changes are made to apps/indexer/drizzle/schema.ts, run:
# From the repository root
npx drizzle-kit generate:pg --schema ./apps/indexer/drizzle/schema.ts \
--out ./apps/indexer/drizzle \
--migration-name add_new_column_to_user
This creates a new numbered SQL file (e.g., 0006_add_new_column_to_user.sql) containing the necessary ALTER TABLE or CREATE statements. The file will be automatically applied on the next application startup.
Summary
- Migration files are stored as versioned SQL in
apps/indexer/drizzle/with numeric prefixes ensuring sequential execution. - Drizzle ORM provides the migration engine, configured via
drizzle.config.tsand executed through themigrate()function. - Automatic execution occurs on every API startup via
postgres.provider.ts, ensuring schema consistency before traffic is served. - Environment configuration in
env.config.tsallows customization of the migrations folder path viaDRIZZLE_MIGRATIONS_FOLDER. - Test isolation is maintained by running the same migration logic against temporary databases in both API and notifications test suites.
Frequently Asked Questions
What migration tool does Akash Console use?
Akash Console uses Drizzle ORM with its built-in postgres-js migrator. This tool compares migration files against the drizzle_meta table in PostgreSQL to determine which schema changes need to be applied, then executes the corresponding SQL files sequentially.
Where are migration files stored in the repository?
Migration files are stored in apps/indexer/drizzle/ as plain SQL files with numeric prefixes (e.g., 0000_chunky_rattler.sql, 0001_add_bseq_to_bid_and_lease.sql). This location is referenced by the DRIZZLE_MIGRATIONS_FOLDER environment variable, which defaults to ./drizzle in apps/api/src/core/config/env.config.ts.
How does Akash Console handle migrations in test environments?
Both the API and notifications services implement test database helpers that create isolated PostgreSQL instances and run the full migration suite before executing tests. The test-database.service.ts files in apps/api/test/services/ and apps/notifications/test/services/ use the same migrate() function from Drizzle ORM to ensure test databases match the production schema exactly.
Can I customize the migrations folder location?
Yes. While the default location is ./drizzle (pointing to apps/indexer/drizzle in the standard deployment), you can override this by setting the DRIZZLE_MIGRATIONS_FOLDER environment variable in apps/api/src/core/config/env.config.ts. This allows flexibility for custom deployment scenarios or monorepo restructuring.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →