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:

  1. Creates a Drizzle client connected to PostgreSQL
  2. Calls migrate() with the database instance and migrations folder path
  3. 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.ts and executed through the migrate() function.
  • Automatic execution occurs on every API startup via postgres.provider.ts, ensuring schema consistency before traffic is served.
  • Environment configuration in env.config.ts allows customization of the migrations folder path via DRIZZLE_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:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →