Use this skill whenever the user wants to design, set up, or refactor Cloudflare D1 database usage in a Hono + TypeScript app running on Cloudflare Workers/Pages, including schema management, bindings, query patterns, and data-access structure.
Scanned 9/8/2026
Install to Claude Code
npx -y skills add AgentiveCity/SkillFactory --skill hono-d1-integration --agent claude-codeInstalls into .claude/skills of the current project.
Are you the author of Hono D1 Integration?
Add the live security badge to your README — it updates automatically with every re-scan.
[](https://www.skillsdirectory.com/skills/agentivecity-hono-d1-integration)More formats (shields.io, HTML) on the badges page.
---
name: "hono-d1-integration"
description: "Use this skill whenever the user wants to design, set up, or refactor Cloudflare D1 database usage in a Hono + TypeScript app running on Cloudflare Workers/Pages, including schema management, bindings, query patterns, and data-access structure."
---
# Hono + Cloudflare D1 Integration Skill
## Purpose
You are a specialized assistant for using **Cloudflare D1** as the database layer in
a **Hono + TypeScript** app running on **Cloudflare Workers / Pages**.
Use this skill to:
- Wire **D1 bindings** into a Hono app (`c.env.DB`)
- Design **schema and migrations** for D1 (via Wrangler)
- Implement **query helpers** and data-access patterns
- Structure **repositories/services** on top of D1
- Use **prepared statements**, parameters, and minimal ORM-style helpers
- Handle **migrations and seeding** for local/dev/test
- Keep D1 usage **runtime-safe** and **type-friendly**
Do **not** use this skill for:
- Hono app scaffolding → use `hono-app-scaffold`
- Non-D1 databases (Postgres/MySQL/etc.) → use TypeORM/other DB skills
- R2 or KV storage → use dedicated storage skills (e.g. `hono-r2-integration`)
If `CLAUDE.md` exists, obey its rules for D1 usage, directories, naming and migration strategy.
---
## When To Apply This Skill
Trigger this skill when the user asks for things like:
- “Use D1 as DB for this Hono API on Cloudflare.”
- “Wire up Hono routes to Cloudflare D1.”
- “Design tables and queries for D1 in this Worker.”
- “Refactor my raw D1 queries into a cleaner structure.”
- “Add migrations/seeding for D1 in this Hono app.”
Avoid this skill when:
- The Hono app is *not* running on Cloudflare Workers / Pages.
- The project has chosen a different DB for this service (e.g. PlanetScale, Supabase).
---
## Runtime & Binding Assumptions
This skill assumes:
- The app runs on **Cloudflare Workers** or **Pages Functions**.
- D1 is configured as a binding in `wrangler.toml`, e.g.:
```toml
[[d1_databases]]
binding = "DB"
database_name = "my_db"
database_id = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
```
- In code, D1 is available as `c.env.DB`.
We will type the Env binding and keep DB access **explicit and centralized**.
---
## Project Structure
This skill works best with a structure like:
```text
src/
app.ts
index.ts
routes/
v1/
users.routes.ts
posts.routes.ts
db/
schema.sql
migrations/
0001_init.sql
0002_add_posts.sql
d1.ts # D1 helpers and typed Env
services/
user.service.ts
post.service.ts
types/
env.d.ts # Env interface with DB binding
```
Adjust paths to match the project, but keep D1-related files under a `db/` or `infrastructure/` style folder.
---
## Typing Env and D1 Binding
Create a shared Env type for Workers:
```ts
// src/types/env.d.ts
export interface Env {
DB: D1Database;
// other bindings e.g. R2, KV, etc.
}
```
Then in routes/services:
```ts
import type { Env } from "../types/env";
export type AppContext = {
Bindings: Env;
};
```
Usage with Hono:
```ts
import { Hono } from "hono";
import type { AppContext } from "./types";
export const app = new Hono<AppContext>();
```
This ensures `c.env.DB` is correctly typed.
---
## D1 Helper Module
Create a small helper for D1 access and typed operations:
```ts
// src/db/d1.ts
import type { Env } from "../types/env";
export type D1 = D1Database;
export function getDb(env: Env): D1 {
return env.DB;
}
export async function runQuery<T = unknown>(
db: D1,
sql: string,
params: unknown[] = [],
): Promise<T[]> {
const stmt = db.prepare(sql);
const result = await stmt.bind(...params).all<T>();
return result.results ?? [];
}
```
For single-row helpers:
```ts
export async function runOne<T = unknown>(
db: D1,
sql: string,
params: unknown[] = [],
): Promise<T | null> {
const rows = await runQuery<T>(db, sql, params);
return rows[0] ?? null;
}
```
This skill should:
- Encourage **parameterized queries** via `.bind(...)`
- Avoid string interpolation that can cause SQL injection
---
## Schema & Migrations
D1 uses `schema.sql` and migrations managed via Wrangler.
### Basic Schema Layout
```sql
-- src/db/schema.sql
CREATE TABLE IF NOT EXISTS users (
id TEXT PRIMARY KEY,
email TEXT NOT NULL UNIQUE,
password_hash TEXT NOT NULL,
created_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ', 'now')),
updated_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ', 'now'))
);
CREATE TABLE IF NOT EXISTS posts (
id TEXT PRIMARY KEY,
user_id TEXT NOT NULL,
title TEXT NOT NULL,
body TEXT NOT NULL,
created_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ', 'now')),
FOREIGN KEY (user_id) REFERENCES users(id)
);
```
Migrations are usually created & applied using commands like:
- `wrangler d1 execute <db_name> --file=src/db/schema.sql --local`
- `wrangler d1 migrations create <db_name> <name>`
- `wrangler d1 migrations apply <db_name> --local`
This skill should:
- Suggest migration commands but **not** assume CLI access inside code.
- Encourage keeping schema & migration SQL in version control.
---
## Service-Level Access Pattern
Design small services using `getDb` & query helpers.
Example `user.service.ts`:
```ts
// src/services/user.service.ts
import type { Env } from "../types/env";
import { getDb, runOne, runQuery } from "../db/d1";
import { nanoid } from "nanoid"; // if project uses this for IDs
export type User = {
id: string;
email: string;
password_hash: string;
created_at: string;
};
export class UserService {
constructor(private env: Env) {}
private db() {
return getDb(this.env);
}
async createUser(email: string, passwordHash: string): Promise<User> {
const id = nanoid();
const db = this.db();
await db
.prepare("INSERT INTO users (id, email, password_hash) VALUES (?, ?, ?)")
.bind(id, email, passwordHash)
.run();
const user = await runOne<User>(db, "SELECT * FROM users WHERE id = ?", [id]);
if (!user) throw new Error("Failed to load just-created user");
return user;
}
async findByEmail(email: string): Promise<User | null> {
const db = this.db();
return runOne<User>(db, "SELECT * FROM users WHERE email = ?", [email]);
}
async listUsers(): Promise<User[]> {
const db = this.db();
return runQuery<User>(db, "SELECT * FROM users ORDER BY created_at DESC");
}
}
```
This skill should:
- Keep SQL in **small, readable strings**.
- Encapsulate DB access in services or repositories, not directly in route handlers (unless trivial).
---
## Using D1 in Hono Routes
Example: a simple users route using `UserService`:
```ts
// src/routes/v1/users.routes.ts
import { Hono } from "hono";
import type { AppContext } from "../../types";
import { UserService } from "../../services/user.service";
export function usersRoutes() {
const app = new Hono<AppContext>();
app.get("/", async (c) => {
const service = new UserService(c.env);
const users = await service.listUsers();
return c.json(users);
});
app.post("/", async (c) => {
const body = await c.req.json<{ email: string; password: string }>();
// Validate body with a validation skill if present
const service = new UserService(c.env);
// Password hashing is done via auth skill (bcrypt/argon2) – here we assume `passwordHash`
const passwordHash = "TODO"; // placeholder
const user = await service.createUser(body.email, passwordHash);
return c.json(user, 201);
});
return app;
}
```
This skill should:
- Encourage injecting `env` into services (no global state).
- Allow composition with `hono-authentication` (e.g., using D1 to fetch user in login).
---
## Transactions and Limits
D1 has more limited transaction semantics than full-blown SQL servers.
This skill should:
- Prefer simple, single-statement operations where possible.
- For multi-step operations, suggest careful ordering and error handling.
- Explicitly avoid patterns that rely on long-lived transactions or complex isolation.
---
## Type Safety Strategies
D1 returns rows as plain JS objects. This skill should:
- Define TypeScript types (`User`, `Post`, etc.) that match the schema.
- Use generic helpers (`runQuery<T>`) to type results.
- Optionally validate results in service logic (e.g., Zod) if project wants stronger runtime guarantees.
---
## Local Development & Testing
This skill can suggest:
- Using `wrangler d1` with `--local` for dev.
- Seeding data via SQL files or small scripts.
- For unit tests, mocking D1 methods instead of hitting real DB:
```ts
const mockDb: Partial<D1Database> = {
prepare: jest.fn().mockReturnValue({
bind: jest.fn().mockReturnThis(),
all: jest.fn().mockResolvedValue({ results: [] }),
run: jest.fn().mockResolvedValue({}),
}),
};
```
- For integration tests in Workers env, tests can use `wrangler d1` to prepare DB before running.
When combined with a Hono testing skill, this gives end-to-end coverage.
---
## Error Handling
This skill must:
- Wrap database errors with useful messages when needed.
- Let general error-handling middleware (from `hono-app-scaffold`) convert them into HTTP responses.
- Avoid leaking sensitive data (SQL text, connection details) in responses.
Example pattern:
```ts
try {
// D1 call
} catch (err) {
console.error("D1 query failed:", err);
throw new Error("Database error");
}
```
The error-handler middleware can then map `Error("Database error")` to a 500 JSON payload.
---
## Example Prompts That Should Use This Skill
- “Use Cloudflare D1 for persistence in this Hono API.”
- “Create D1 schema and wire up user routes in Hono.”
- “Refactor my raw D1 queries into a service layer.”
- “Help me design D1 tables + queries for this feature.”
- “Make D1 usage type-safe and structured in this Worker.”
For these tasks, rely on this skill to produce a **clean, Hono-friendly D1 integration** that is
typed, bound via the Env, and ready for production on Cloudflare Workers/Pages.
Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.
No comments yet. Be the first to comment!