Skip to main content
skill CX Codex

bun-drizzle-integration — Claude Code skill: Drizzle ORM on Bun SQLite

A skill that walks your agent through wiring Drizzle ORM to the bun:sqlite driver: schema, migrations, CRUD and transactions.

Install into Claude Code · Skills CLI (Vercel) All methods and platforms ↓
npx skills add secondsky/claude-skills --skill bun-drizzle-integration -a claude-code
Open on GitHub

What bun-drizzle-integration does

The skill kicks in when you build typed database access with Drizzle ORM on top of Bun's SQLite driver. It carries ready patterns: table definitions with sqliteTable, a drizzle.config.ts setup, and migration generation and application through drizzle-kit. Your agent pulls insert, select, update and delete examples from it, including onConflictDoNothing and upsert.

Relations get their own section, so relations, nested with queries, transactions with tx.rollback() and prepared statements are all covered. There is also a table of common failures: SQLITE_CONSTRAINT, no such column, Cannot find module. That last one points at the import path — pull the driver from anywhere but drizzle-orm/bun-sqlite and the types stop lining up.

Two packages come first: bun add drizzle-orm and bun add -D drizzle-kit. The skill references references/migrations.md and references/performance.md, worth loading for tricky migrations and performance work.

What it helps with

  • define tables in schema.ts with types and foreign keys
  • generate and apply migrations with drizzle-kit
  • write an upsert that updates the conflicting row
  • wrap several inserts in a transaction that can roll back
  • fetch records together with their related rows in one query

Example prompts for the agent

  • Define users and posts tables in src/db/schema.ts with sqliteTable and link them through relations
  • Set up drizzle.config.ts for SQLite and generate a migration with bun drizzle-kit generate
  • Insert a user with onConflictDoUpdate on email and return the row via .returning()

How to install bun-drizzle-integration

1Skills CLI (Vercel)

npx skills add secondsky/claude-skills --skill bun-drizzle-integration -a claude-code

2Manually: put the files in place

~/.claude/skills/bun-drizzle-integration/SKILL.md

Copy the whole skill folder; for one project use .claude/skills/bun-drizzle-integration/

Step by step, with commands for each platform: How to install skills in Claude Code: five ways

Questions about bun-drizzle-integration

How do I install bun-drizzle-integration in Claude?

Run npx skills add secondsky/claude-skills --skill bun-drizzle-integration -a claude-code. The skill then lives at ~/.claude/skills/bun-drizzle-integration/SKILL.md.

What does bun-drizzle-integration do?

It gives your agent patterns for Drizzle ORM on the bun:sqlite driver: schema, config, migrations, CRUD, relations, transactions and prepared statements.

Which packages does the skill need?

drizzle-orm as a dependency and drizzle-kit as a dev dependency: bun add drizzle-orm and bun add -D drizzle-kit.

Source text

SKILL.md · MIT
---
name: bun-drizzle-integration
description: Use when integrating Drizzle ORM with Bun's SQLite driver for type-safe schema definitions and migrations.
metadata:
  version: "1.0.0"
license: MIT
---

# Bun Drizzle Integration

Drizzle ORM provides type-safe database access with Bun's SQLite driver.

## Quick Start

```bash
bun add drizzle-orm
bun add -D drizzle-kit
```

## Schema Definition

```typescript
// src/db/schema.ts
import { sqliteTable, text, integer } from "drizzle-orm/sqlite-core";

export const users = sqliteTable("users", {
  id: integer("id").primaryKey({ autoIncrement: true }),
  name: text("name").notNull(),
  email: text("email").notNull().unique(),
  createdAt: integer("created_at", { mode: "timestamp" })
    .notNull()
    .default(sql`(unixepoch())`),
});

export const posts = sqliteTable("posts", {
  id: integer("id").primaryKey({ autoIncrement: true }),
  title: text("title").notNull(),
  content: text("content"),
  authorId: integer("author_id")
    .notNull()
    .references(() => users.id),
});
```

## Database Setup

```typescript
// src/db/index.ts
import { drizzle } from "drizzle-orm/bun-sqlite";
import { Database } from "bun:sqlite";
import * as schema from "./schema";

const sqlite = new Database("app.db");
export const db = drizzle(sqlite, { schema });
```

## Configuration

```typescript
// drizzle.config.ts
import type { Config } from "drizzle-kit";

export default {
  schema: "./src/db/schema.ts",
  out: "./drizzle",
  dialect: "sqlite",
  dbCredentials: {
    url: "./app.db",
  },
} satisfies Config;
```

## Migrations

```bash
# Generate migration
bun drizzle-kit generate

# Apply migrations
bun drizzle-kit migrate

# Push schema directly (dev only)
bun drizzle-kit push

# Open Drizzle Studio
bun drizzle-kit studio
```

## CRUD Operations

### Insert

```typescript
import { db } from "./db";
import { users, posts } from "./db/schema";

// Single insert
const user = await db.insert(users).values({
  name: "Alice",
  email: "[email protected]",
}).returning();

// Multiple insert
await db.insert(users).values([
  { name: "Bob", email: "[email protected]" },
  { name: "Charlie", email: "[email protected]" },
]);

// Insert or ignore
await db.insert(users)
  .values({ name: "Alice", email: "[email protected]" })
  .onConflictDoNothing();

// Upsert
await db.insert(users)
  .values({ name: "Alice", email: "[email protected]" })
  .onConflictDoUpdate({
    target: users.email,
    set: { name: "Alice Updated" },
  });
```

### Select

```typescript
import { eq, gt, like, and, or, desc, asc } from "drizzle-orm";

// All rows
const allUsers = await db.select().from(users);

// With conditions
const activeUsers = await db
  .select()
  .from(users)
  .where(eq(users.status, "active"));

// Multiple conditions
const filtered = await db
  .select()
  .from(users)
  .where(and(
    gt(users.age, 18),
    like(users.name, "%Alice%")
  ));

// Specific columns
const names = await db
  .select({ name: users.name, email: users.email })
  .from(users);

// Order and limit
const topUsers = await db
  .select()
  .from(users)
  .orderBy(desc(users.createdAt))
  .limit(10);

// First result
const first = await db.query.users.findFirst({
  where: eq(users.id, 1),
});
```

### Update

```typescript
// Update with condition
await db
  .update(users)
  .set({ name: "Alice Updated" })
  .where(eq(users.id, 1));

// Update multiple fields
await db
  .update(users)
  .set({
    name: "New Name",
    updatedAt: new Date(),
  })
  .where(eq(users.email, "[email protected]"));
```

### Delete

```typescript
// Delete with condition
await db.delete(users).where(eq(users.id, 1));

// Delete multiple
await db.delete(users).where(gt(users.createdAt, cutoffDate));
```

## Relations

```typescript
// schema.ts
import { relations } from "drizzle-orm";

export const usersRelations = relations(users, ({ many }) => ({
  posts: many(posts),
}));

export const postsRelations = relations(posts, ({ one }) => ({
  author: one(users, {
    fields: [posts.authorId],
    references: [users.id],
  }),
}));

// Query with relations
const usersWithPosts = await db.query.users.findMany({
  with: {
    posts: true,
  },
});

// Nested relations
const detailed = await db.query.users.findFirst({
  where: eq(users.id, 1),
  with: {
    posts: {
      with: {
        comments: true,
      },
    },
  },
});
```

## Transactions

```typescript
// Transaction
await db.transaction(async (tx) => {
  const [user] = await tx.insert(users)
    .values({ name: "Alice", email: "[email protected]" })
    .returning();

  await tx.insert(posts).values({
    title: "First Post",
    authorId: user.id,
  });
});

// Rollback on error
await db.transaction(async (tx) => {
  await tx.insert(users).values({ name: "Bob" });

  if (someCondition) {
    tx.rollback(); // Throws to rollback
  }

  await tx.insert(posts).values({ ... });
});
```

## Prepared Statements

```typescript
// Create prepared statement
const getUserById = db
  .select()
  .from(users)
  .where(eq(users.id, sql.placeholder("id")))
  .prepare();

// Execute with parameter
const user = await getUserById.execute({ id: 1 });

// Reuse for performance
for (const id of userIds) {
  const user = await getUserById.execute({ id });
  processUser(user);
}
```

## Raw SQL

```typescript
import { sql } from "drizzle-orm";

// Raw query
const result = await db.run(sql`
  UPDATE users SET last_login = ${new Date()} WHERE id = ${userId}
`);

// In select
const users = await db.select({
  name: users.name,
  upperName: sql<string>`UPPER(${users.name})`,
}).from(users);

// Raw expressions in where
await db.select().from(users).where(
  sql`${users.age} > 18 AND ${users.status} = 'active'`
);
```

## Column Types Reference

```typescript
import {
  sqliteTable,
  text,
  integer,
  real,
  blob,
  numeric,
} from "drizzle-orm/sqlite-core";

const example = sqliteTable("example", {
  // Integer
  id: integer("id").primaryKey(),
  age: integer("age"),

  // Text
  name: text("name"),
  status: text("status", { enum: ["active", "inactive"] }),

  // Real (float)
  price: real("price"),

  // Blob
  data: blob("data", { mode: "buffer" }),

  // Boolean (stored as integer)
  active: integer("active", { mode: "boolean" }),

  // Timestamp (stored as integer)
  createdAt: integer("created_at", { mode: "timestamp" }),
  updatedMs: integer("updated_ms", { mode: "timestamp_ms" }),

  // JSON (stored as text)
  metadata: text("metadata", { mode: "json" }),
});
```

## Common Errors

| Error | Cause | Fix |
|-------|-------|-----|
| `SQLITE_CONSTRAINT` | FK/unique violation | Check constraints |
| `no such column` | Schema mismatch | Run migrations |
| `Cannot find module` | Missing driver | Use `drizzle-orm/bun-sqlite` |
| Type mismatch | Wrong column type | Check schema definition |

## When to Load References

Load `references/migrations.md` when:
- Complex migration scenarios
- Migration squashing
- Database seeding

Load `references/performance.md` when:
- Query optimization
- Indexing strategies
- Connection pooling

© secondsky · MIT · secondsky/claude-skills

Similar skills

All skills for Data and databases →

From the same set89

root-cause-tracing Walks an agent backward through the call stack until it finds the original trigger. Useful when an error surfaces deep in execution, not at the entry point. CX Codex +1 426installs recommendation-engine A skill for building recommendation systems: collaborative filtering, matrix factorization, hybrid approaches. Useful for product recommendations and personalization. CX Codex +1 423installs api-response-optimization A coding-agent skill that walks through payload trimming, HTTP caching and compression for API endpoints. Useful when responses feel slow. CX Codex +1 422installs api-filtering-sorting A skill that walks your coding agent through building API filtering and sorting: query parsing, validation, and injection safety. CX Codex +1 418installs drizzle-orm-d1 A skill that gives your agent working knowledge of Drizzle ORM on Cloudflare D1: schemas, typed queries, Drizzle Kit migrations and the usual D1 errors. CX Codex +1 416installs push-notification-setup A skill that walks your agent through push notification setup with Firebase Cloud Messaging and native services. Useful when you add notifications to an app or debug background messages. CX Codex +1 418installs bun-runtime A skill that teaches your agent the Bun runtime: running files, watch and hot modes, env vars, CLI flags and module resolution. CX Codex +1 414installs defense-in-depth-validation A skill that pushes your agent to validate data at every layer it passes through, so the bug becomes structurally impossible. Useful when bad data fails deep in execution. CX Codex +1 413installs

Project sponsors

Companies that keep this analytics open
Gold sponsor

Impressions, clicks and code copies — open statistics. We keep the numbers public for the same reason NeBlask itself is public. Become a sponsor