Schema modeling strategy
Model existing tables exactly first. Do not rename columns or
normalize JSON fields as part of the first Drizzle pass. Examples:
import { sqliteTable, text, integer, uniqueIndex } from "drizzle-orm/sqlite-core";
export const ordersOfService = sqliteTable(
"orders_of_service",
{
id: text("id").primaryKey(),
title: text("title").notNull(),
serviceTypeId: text("service_type_id").notNull(),
serviceDate: text("service_date").notNull(),
status: text("status").notNull().default("Planning"),
templateId: text("template_id"),
orderJson: text("order_json").notNull(),
pdfObjectKey: text("pdf_object_key"),
publishedAt: text("published_at"),
createdAt: text("created_at").notNull().default("CURRENT_TIMESTAMP"),
updatedAt: text("updated_at").notNull().default("CURRENT_TIMESTAMP"),
},
(table) => [
uniqueIndex("orders_of_service_service_date_unique_idx").on(table.serviceDate),
]
);
The snippet is illustrative; defaults and foreign keys should be
validated against Drizzle's current SQLite/D1 APIs before use.
Coexistence pattern during migration
Use a shared request-scoped database factory, but let each module
choose whether it still needs direct D1 or Drizzle.
export const createDb = (env: Env) => drizzle(env.DB, { schema });
export const getD1 = (env: Env) => env.DB;
This keeps the boundary explicit and makes feature-by-feature
migration possible without an all-at-once rewrite.