Drizzle ORM + drizzle-zod validated inserts on SQLite: working versions (tested 2026-10-15)
Generate Zod insert and select schemas from Drizzle tables with drizzle-zod, refine them, and validate input before inserting into SQLite.
passed2 passed · 0 failed2026-10-15 13:28 UTC- Status
- passed
- Last passed
- 2026-10-15 13:28 UTC
- Tests
- 2 / 2
- Language
- TypeScript
- Runtime
- node v22.23.3
npm install --no-audit --no-fund --ignore-scripts=false npm test
node v22.23.3 linux 6.17.0-1022-azure x64 runner: github-actions 38742087302
The code
Exactly the files that passed. Your agent can pull them with get_recipe("drizzle-zod-insert-schemas") (install), or see them on GitHub.
{
"name": "drizzle-zod-insert-schemas",
"private": true,
"type": "module",
"scripts": {
"test": "node --import tsx --test test/*.test.ts"
},
"dependencies": {
"drizzle-orm": "0.45.4",
"drizzle-zod": "0.8.3",
"zod": "4.6.7",
"better-sqlite3": "12.11.1"
},
"devDependencies": {
"tsx": "4.23.15",
"@types/node": "24.19.2",
"@types/better-sqlite3": "9.6.0"
}
}
import Database from "better-sqlite3";
import { drizzle } from "drizzle-orm/better-sqlite3";
import { sqliteTable, integer, text } from "drizzle-orm/sqlite-core";
import { createInsertSchema, createSelectSchema } from "drizzle-zod";
import { z } from "zod";
export const products = sqliteTable("products", {
id: integer("id").primaryKey({ autoIncrement: true }),
name: text("name").notNull(),
priceCents: integer("price_cents").notNull(),
sku: text("sku").notNull(),
});
// Refine generated schemas instead of hand-writing a second copy of the table.
export const insertProduct = createInsertSchema(products, {
name: (s) => s.min(2).max(100),
priceCents: (s) => s.int().positive(),
sku: (s) => s.regex(/^[A-Z]{3}-\d{4}$/),
}).omit({ id: true });
export const selectProduct = createSelectSchema(products);
export type NewProduct = z.infer<typeof insertProduct>;
export function createDb() {
const sqlite = new Database(":memory:");
sqlite.exec("create table products (id integer primary key autoincrement, name text not null, price_cents integer not null, sku text not null)");
return drizzle(sqlite);
}
export function addProduct(db: ReturnType<typeof createDb>, input: unknown) {
const data = insertProduct.parse(input);
return selectProduct.parse(db.insert(products).values(data).returning().get());
}
import { test } from "node:test";
import assert from "node:assert/strict";
import { ZodError } from "zod";
import { createDb, addProduct } from "../src/db.ts";
test("valid input is inserted", () => {
const p = addProduct(createDb(), { name: "Mug", priceCents: 1299, sku: "MUG-0001" });
assert.deepEqual(p, { id: 1, name: "Mug", priceCents: 1299, sku: "MUG-0001" });
});
test("invalid input never reaches the database", () => {
const db = createDb();
assert.throws(() => addProduct(db, { name: "M", priceCents: -1, sku: "bad" }), ZodError);
assert.throws(() => addProduct(db, { name: "Mug", priceCents: 5 }), ZodError);
});
Connect to ProvenPin
Add the free MCP server so your agent can pull this recipe and others like it. Same setup as the docs.
claude mcp add --transport http provenpin https://mcp.provenpin.com/mcp
{ "mcpServers": { "provenpin": { "url": "https://mcp.provenpin.com/mcp" } } }{ "servers": { "provenpin": { "type": "http", "url": "https://mcp.provenpin.com/mcp" } } }{ "mcpServers": { "provenpin": { "serverUrl": "https://mcp.provenpin.com/mcp" } } }{ "mcpServers": { "provenpin": { "type": "streamableHttp", "url": "https://mcp.provenpin.com/mcp" } } }Any other MCP client: Streamable HTTP at https://mcp.provenpin.com/mcp. No API key, no signup.
Related stacks
Hono + Drizzle ORM + SQLite REST API (Vitest)
CRUD REST API in Hono backed by Drizzle ORM on better-sqlite3, with Zod validation, tested with Vitest and app.request().
better-sqlite3 transactions with Zod-validated inputs
A small ledger on better-sqlite3 using db.transaction for atomic transfers, nested transactions as savepoints for all-or-nothing batches, and Zod 4 to validate inputs and rows, tested on in-memory SQLite.
Drizzle ORM + better-sqlite3 CRUD
Typed schema, migrations-free table creation and CRUD with Drizzle on an in-memory SQLite database.
Anthropic TypeScript SDK tool use loop, tested with a mocked fetch
Run a Claude tool_use loop with the official Anthropic SDK and Zod-validated tool inputs, tested offline with an injected fetch.
All Drizzle ORM recipesAll drizzle-zod recipesAll Zod recipesAll better-sqlite3 recipes