Skip to content

Multi-Database

CruzJS supports connecting to multiple databases within a single application. This is useful for multi-tenant isolation, read replicas, or separating analytics data from transactional data.

Register the MultiDatabaseModule in your application:

import { MultiDatabaseModule } from '@cruzjs/core/multi-database';
export default createCruzApp({
modules: [MultiDatabaseModule],
});
ScenarioExample
Tenant isolationSeparate D1 database per tenant for data isolation
Read replicaRoute reads to a replica, writes to primary
Analytics DBSeparate database for analytics queries to avoid impacting production
Legacy migrationAccess both old and new databases during migration

Bind multiple D1 databases in wrangler.toml:

[[d1_databases]]
binding = "DB"
database_name = "main"
database_id = "xxx"
[[d1_databases]]
binding = "DB_ANALYTICS"
database_name = "analytics"
database_id = "yyy"
[[d1_databases]]
binding = "DB_TENANT_A"
database_name = "tenant-a"
database_id = "zzz"

Set environment variables for each database:

Terminal window
DATABASE_URL=postgresql://localhost:5432/main
DATABASE_ANALYTICS_URL=postgresql://localhost:5432/analytics
DATABASE_TENANT_A_URL=postgresql://localhost:5432/tenant_a

The MultiDatabaseService provides access to named database connections:

import { Injectable, Inject } from '@cruzjs/core/di';
import { MultiDatabaseService } from '@cruzjs/core/multi-database';
@Injectable()
export class AnalyticsService {
constructor(
@Inject(MultiDatabaseService) private readonly multiDb: MultiDatabaseService,
) {}
async getPageViews(startDate: string) {
const analyticsDb = this.multiDb.getDatabase('analytics');
return analyticsDb
.select()
.from(pageViews)
.where(gte(pageViews.createdAt, startDate));
}
}
MethodReturnsDescription
getDatabase(name)DrizzleDatabaseGet a Drizzle instance for the named database
listDatabases()string[]List all available database names
ProcedureTypeAuthDescription
multiDatabase.listqueryAdminList all configured database connections
multiDatabase.querymutationAdminExecute a read query against a named database
@Injectable()
export class TenantService {
constructor(
@Inject(MultiDatabaseService) private readonly multiDb: MultiDatabaseService,
) {}
async getTenantData(tenantId: string) {
const tenantDb = this.multiDb.getDatabase(`tenant-${tenantId}`);
return tenantDb.select().from(tenantRecords);
}
}
@Injectable()
export class ProductService {
constructor(
@Inject(MultiDatabaseService) private readonly multiDb: MultiDatabaseService,
@Inject(DRIZZLE) private readonly primaryDb: DrizzleDatabase,
) {}
async getProduct(id: string) {
// Read from replica
const replicaDb = this.multiDb.getDatabase('replica');
return replicaDb.select().from(products).where(eq(products.id, id));
}
async updateProduct(id: string, input: UpdateProductInput) {
// Write to primary
return this.primaryDb
.update(products)
.set(input)
.where(eq(products.id, id))
.returning();
}
}