Which ORM Does OpenSEO Use for Database Migrations?
OpenSEO uses Drizzle ORM for database migrations, with type-safe schema definitions and dual database support for both Cloudflare D1 (SQLite) and PostgreSQL.
The open-source OpenSEO repository (every-app/open-seo) implements a modern, migration-ready data layer built entirely on Drizzle ORM (drizzle-orm). According to the source code, the project maintains separate Drizzle configurations for SQLite-based D1 and PostgreSQL instances, using Drizzle's built-in migration tooling to apply versioned schema changes across both environments.
Why Drizzle ORM Powers OpenSEO Database Migrations
Drizzle ORM provides OpenSEO with a type-safe, SQL-like DSL for schema definition without sacrificing performance or developer experience. The repository leverages Drizzle's modular architecture, importing database-specific cores from drizzle-orm/sqlite-core and drizzle-orm/pg-core depending on the target environment.
This design choice enables OpenSEO to:
- Deploy to Cloudflare D1 (SQLite) for edge-compatible deployments
- Run PostgreSQL for traditional server-based infrastructure
- Share schema logic while maintaining environment-specific optimizations
How OpenSEO Configures Drizzle ORM for Dual Databases
SQLite/D1 Schema Definition
In src/db/schema.ts, OpenSEO defines tables using Drizzle's SQLite core:
// src/db/schema.ts
import { sqliteTable, text, integer } from "drizzle-orm/sqlite-core";
export const projects = sqliteTable("projects", {
id: text("id").primaryKey(),
name: text("name").notNull(),
createdAt: integer("created_at", { mode: "timestamp" }).notNull(),
});
PostgreSQL Schema Definition
The same table structure is mirrored for PostgreSQL in src/db/pg/schema.ts:
// src/db/pg/schema.ts
import { pgTable, text, timestamp } from "drizzle-orm/pg-core";
export const projects = pgTable("projects", {
id: text("id").primaryKey(),
name: text("name").notNull(),
createdAt: timestamp("created_at", { mode: "date" }).defaultNow(),
});
Both definitions maintain identical column semantics while using Drizzle's database-specific type primitives.
Running Database Migrations in OpenSEO
Creating Drizzle Clients
OpenSEO instantiates separate Drizzle clients for each database backend. The D1 client in src/db/d1/client.ts:
// src/db/d1/client.ts
import { drizzle } from "drizzle-orm/d1";
import { env } from "../env";
export const d1Db = drizzle(env.DB, { schema });
The PostgreSQL client in src/db/pg/client.ts:
// src/db/pg/client.ts
import { drizzle } from "drizzle-orm/postgres-js";
import postgres from "postgres";
import { schema } from "./schema";
export const pgDb = drizzle(postgres(env.PG_CONNECTION_STRING), { schema });
Migration Script Implementation
The repository includes a custom migration script at scripts/migrate-d1-to-postgres.ts that applies Drizzle migrations across both databases:
// scripts/migrate-d1-to-postgres.ts
import { drizzle } from "drizzle-orm/d1";
import { drizzle as pgDrizzle } from "drizzle-orm/postgres-js";
import { schema as d1Schema } from "../src/db/schema";
import { schema as pgSchema } from "../src/db/pg/schema";
const d1 = drizzle(env.DB, { schema: d1Schema });
const pg = pgDrizzle(env.PG_CONNECTION_STRING, { schema: pgSchema });
await d1.migrate(); // applies any pending D1 migrations
await pg.migrate(); // applies matching PostgreSQL migrations
The drizzle.migrate() method invokes Drizzle's migration CLI (drizzle-migrate) under the hood, reading versioned SQL files and applying pending changes transactionally.
Key Configuration Files for OpenSEO ORM Setup
| Purpose | File Path |
|---|---|
| Global Drizzle configuration | drizzle.config.ts |
| SQLite/D1 schema definitions | src/db/schema.ts |
| PostgreSQL schema definitions | src/db/pg/schema.ts |
| D1 client instantiation | src/db/d1/client.ts |
| PostgreSQL client instantiation | src/db/pg/client.ts |
| Cross-database migration script | scripts/migrate-d1-to-postgres.ts |
The drizzle.config.ts file at the repository root centralizes migration settings, output paths, and database connection parameters for the Drizzle CLI.
Summary
- OpenSEO uses Drizzle ORM as its sole database abstraction layer for both schema definition and migrations
- Dual-database architecture supports Cloudflare D1 (SQLite) and PostgreSQL through separate Drizzle core packages
- Type-safe migrations are applied via
drizzle.migrate()or thedrizzle-migrateCLI - Shared schema patterns across database engines minimize code duplication while preserving engine-specific optimizations
Frequently Asked Questions
Does OpenSEO support other ORMs besides Drizzle?
No. As implemented in every-app/open-seo, the entire data layer is built on Drizzle ORM exclusively. No Prisma, TypeORM, or other ORM dependencies exist in the codebase.
How does OpenSEO handle schema changes across D1 and PostgreSQL?
The repository maintains parallel schema files (src/db/schema.ts for D1, src/db/pg/schema.ts for PostgreSQL). The migration script scripts/migrate-d1-to-postgres.ts applies Drizzle migrations to both backends, ensuring schema consistency.
What Drizzle packages does OpenSEO install?
OpenSEO imports drizzle-orm with database-specific subpackages: drizzle-orm/sqlite-core, drizzle-orm/pg-core, drizzle-orm/d1, and drizzle-orm/postgres-js. These provide type-safe clients for each database engine.
Can I use Drizzle migrations with Cloudflare D1 in my own project?
Yes. The OpenSEO source demonstrates production-ready Drizzle ORM usage with D1. The key requirements are: install drizzle-orm/d1, configure a Drizzle client with your D1 binding, and run drizzle.migrate() to apply pending migrations.
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 →