Step-by-step guide to implement a D1 database on top of the Hono Vite React Stack https://github.com/yusukebe/hono-vite-react-stack
Please study the existing codebase carefully and implement a D1 database setup as described in "Database Setup Implementation Plan" below. List out all the individual steps as bullets before starting.
Instead of the chat example described, we want to make a classifieds app where users can submit (without authentication) a listing with a title, description, location and phone number.
Complete the entire flow of implementation, migrations and initial deployment.
/
├── src/
│ ├── server/
│ │ ├── index.tsx # Main worker code with Hono routes
│ │ ├── renderer.tsx # React SSR shell
│ │ └── db.ts # Database operations (to be created)
│ ├── client/
│ │ ├── app.tsx # Client-side React app
│ │ └── index.tsx # Client entry point
│ ├── lib/
│ │ ├── utils.ts # Utility functions
│ │ └── schema.ts # Drizzle schema definitions (to be created)
│ └── style.css # Global styles
├── migrations/ # SQL migration files
├── drizzle/ # Generated Drizzle artifacts
├── drizzle.config.ts # Drizzle configuration (to be created)
├── wrangler.jsonc # Cloudflare configuration
└── vite.config.ts # Vite configuration
import { sql } from 'drizzle-orm';
import { text, integer, sqliteTable } from 'drizzle-orm/sqlite-core';
export const messages = sqliteTable('messages', {
id: integer('id').primaryKey({ autoIncrement: true }),
content: text('content').notNull(),
createdAt: integer('created_at', { mode: 'timestamp' }).notNull().default(sql`CURRENT_TIMESTAMP`),
});
import type { Config } from 'drizzle-kit';
import { defineConfig } from 'drizzle-kit';
export default defineConfig({
schema: './src/lib/schema.ts',
out: './drizzle',
dialect: 'sqlite',
});
When choosing a database name, append a random 6-character string to make it unique.
{
"$schema": "node_modules/wrangler/config-schema.json",
"name": "chat-app",
"compatibility_date": "2025-03-20",
"main": "./src/server/index.tsx",
"assets": {
"directory": "dist"
},
"d1_databases": [
{
"binding": "DB",
"database_name": "chat-db",
"database_id": "<your-database-id>",
"migrations_dir": "drizzle"
}
]
}
import { drizzle } from 'drizzle-orm/d1';
import { messages } from '@/lib/schema';
export interface Env {
DB: D1Database;
}
export const getDb = (env: Env) => drizzle(env.DB);
export async function getMessages(env: Env) {
const db = getDb(env);
return await db.select().from(messages).all();
}
export async function createMessage(env: Env, content: string) {
const db = getDb(env);
return await db.insert(messages).values({ content }).run();
}
wrangler d1 create chat-db
npm install drizzle-orm
npm install -D drizzle-kit
import { Hono } from 'hono'
import { renderer } from './renderer'
import { getMessages, createMessage } from './db'
// Define the environment interface
interface Env {
DB: D1Database;
}
const app = new Hono<{ Bindings: Env }>()
// Add API routes and existing code
// ...
To manage your database schema using drizzle-kit and wrangler:
src/lib/schema.ts
npx drizzle-kit generate
This command will:
migrations
directorynpx wrangler d1 migrations apply chat-db --local
npx wrangler d1 migrations apply chat-db --remote
For development, you can use additional flags with drizzle-kit generate:
npx drizzle-kit generate --verbose # Show detailed output
Update the main worker (src/server/index.tsx) with:
Update the client-side React app (src/client/app.tsx) with:
npm run dev
npm run deploy
Create a Github action to run migrations, based on this code snippet:
- name: Apply D1 Migrations
uses: cloudflare/wrangler-action@v3
with:
apiToken: ${{ secrets.CF_API_TOKEN }}
accountId: ${{ secrets.CF_ACCOUNT_ID }}
command: d1 migrations apply ${{ secrets.CF_DB_NAME }}
Add a "Database" section to the README file, describing how the schema can be updated, how migrations are generated and applied to the local and remote databases.
Keep the changes in the README focused on the database changes we just did and focus on useful information for further development. Don't replicate the schema.
Include a small section on resetting the local DB, which can be done with this command:
rm .wrangler/state/v3/d1/miniflare-D1DatabaseObject/*
Extend package.json with the most important commands that a user might want to run.
Add this context to your project via the
ctxs
command line integration: