Building a Todo API with HonoJS, Drizzle ORM & Neon — A Beginner-Friendly Guide
Source: Dev.to
🚀 Getting Started with HonoJS — Routing + Drizzle + Neon Todo API
HonoJS is an ultrafast, lightweight web framework designed for building APIs across Node.js, Bun, Deno, and edge runtimes like Cloudflare Workers and Vercel Edge Functions.
In this tutorial you will:
- Learn simple routing in Hono
- Build a Todo API using Drizzle ORM + Neon PostgreSQL
- Discuss why this stack is great for modern backends
- See two real‑world apps built with Hono
Why HonoJS?
- Extremely fast & lightweight
- Multi‑runtime compatible
- TypeScript‑first
- Middleware‑friendly
It offers power similar to Express but is optimized for edge and serverless environments.
npm create hono@latest
# or
pnpm create hono@latest
yarn create hono@latest
Basic Example (index.ts)
import { Hono } from 'hono';
const app = new Hono();
app.get('/', (c) => c.text('👋 Hello from Hono!'));
app.get('/api/hello', (c) => {
return c.json({ message: 'This is a JSON response!' });
});
export default app;
npm run dev
You now have a fully working API with clean, type‑safe routing.
Todo API with Hono + Drizzle + Neon
We’ll combine:
- Hono → API router
- Neon → Serverless PostgreSQL
- Drizzle ORM → Type‑safe database layer
🧠 Step 1 — Set up Neon & Environment
-
Create a Neon database and copy the connection string:
DATABASE_URL="postgres://your-connection-string" -
Install dependencies:
npm install hono @neondatabase/serverless drizzle-orm drizzle-kit
Define the schema (src/db/schema.ts)
import { pgTable, serial, text, boolean, timestamp } from 'drizzle-orm/pg-core';
export const todos = pgTable('todos', {
id: serial('id').primaryKey(),
content: text('content').notNull(),
completed: boolean('completed').default(false).notNull(),
createdAt: timestamp('created_at').defaultNow().notNull(),
});
Initialise Drizzle (src/db/index.ts)
import { drizzle } from 'drizzle-orm/neon-http';
import { neon } from '@neondatabase/serverless';
import * as schema from './schema';
const sql = neon(process.env.DATABASE_URL!);
export const db = drizzle(sql, { schema });
Build the API (src/app.ts)
import { Hono } from 'hono';
import { db } from './db';
import { todos } from './db/schema';
const app = new Hono();
// Get all todos
app.get('/todos', async (c) => {
const all = await db.select().from(todos);
return c.json(all);
});
// Create a todo
app.post('/todos', async (c) => {
const { content } = await c.req.json();
const newTodo = await db.insert(todos).values({ content }).returning();
return c.json(newTodo);
});
// Mark a todo as completed
app.patch('/todos/:id', async (c) => {
const id = Number(c.req.param('id'));
const updated = await db
.update(todos)
.set({ completed: true })
.where(todos.id.eq(id))
.returning();
return c.json(updated);
});
// Delete a todo
app.delete('/todos/:id', async (c) => {
const id = Number(c.req.param('id'));
await db.delete(todos).where(todos.id.eq(id));
return c.text('Deleted');
});
export default app;
You now have a complete REST API:
GET /todosPOST /todosPATCH /todos/:idDELETE /todos/:id
🧩 Stack Summary
- Hono – fast & edge‑ready
- Drizzle – type‑safe SQL
- Neon – scalable serverless Postgres
Perfect for microservices and APIs.
🙌 Real‑World Projects Using Hono
- MoneySense.ai – smart financial insights
- MenuGo.live – modern digital restaurant platform
Both rely on Hono‑powered backends for reliability and performance.
Extending the Todo API
Consider adding:
- Authentication (JWT, Clerk, Lucia)
- Request validation with Zod
- Analytics & logging
- A frontend UI for the Todo API
Conclusion
HonoJS provides edge‑ready performance, clean routing, strong TypeScript support, and easy integration with serverless tools like Neon. Whether you’re prototyping or scaling production systems, it’s a powerful, modern backend choice.