Client Area

Modern Node.js APIs with Hono, Bun, and Edge Runtime

ByDomain India Team·DomainIndia Engineering
6 min readPublished 21 Apr 2026Updated 23 Jun 2026210 views

In this article

  • 1The 2026 Node.js landscape
  • 2Why Bun runtime
  • 3Step 1 — Install Bun on DomainIndia VPS
  • 4Step 2 — Scaffold Hono API
  • 5Step 3 — Database with Bun's built-in SQLite or Drizzle

Modern Node.js APIs with Hono, Bun, and Edge Runtime

TL;DR
Node.js APIs in 2026 look different from Express. Hono (lightweight, multi-runtime), Bun (30× faster install, built-in APIs), and edge-compatible code let you run the same app on DomainIndia VPS, Cloudflare Workers, Vercel, or Deno Deploy. This guide shows a unified stack.

The 2026 Node.js landscape

FrameworkYearRuntimePhilosophy
Express2010Node.js onlyMature, minimal, large ecosystem
Fastify2016Node.js2× faster than Express, schema-first
Koa2013Node.jsExpress successor by same team, async-native
Hono2022Node/Deno/Bun/EdgeMulti-runtime, Web-Fetch-API-based
ElysiaJS2023Bun onlyBun-native, type safety

Pick Hono for new greenfield APIs — it runs identically on Node.js (DomainIndia VPS), Bun, Deno, Cloudflare Workers, Vercel Functions, AWS Lambda. Deploy flexibility without code changes.

Why Bun runtime

MetricNode.js 20Bun 1.1Deno 1.46
Install speedBaseline25-30× fasterSimilar to Node
Startup time~200ms~20ms~100ms
Built-in APIsRequires packagesBuilt-in (SQLite, WS, password hashing)Requires packages
Package mgmtnpm/yarn/pnpmbun install (lockfile-compatible)JSR / npm
Production-ready 2026?YesYesYes (for greenfield)

Bun wins for dev experience + install speed. Node.js is still the most proven in production.

Step 1 — Install Bun on DomainIndia VPS

bash
curl -fsSL https://bun.sh/install | bash
source ~/.bashrc
bun --version

Or stick with Node.js 20+:

bash
# AlmaLinux
sudo dnf install -y nodejs npm

# Ubuntu
curl -fsSL https://deb.nodesource.com/setup_20.x | sudo bash -
sudo apt install -y nodejs

Step 2 — Scaffold Hono API

bash
mkdir myapi && cd myapi
bun init  # or: npm init -y
bun add hono
# or: npm install hono

src/index.ts:

typescript
import { Hono } from 'hono';
import { logger } from 'hono/logger';
import { cors } from 'hono/cors';
import { jwt } from 'hono/jwt';
import { zValidator } from '@hono/zod-validator';
import { z } from 'zod';

const app = new Hono();

app.use('*', logger());
app.use('*', cors({ origin: ['https://yourcompany.com'] }));

// Public routes
app.get('/health', (c) => c.json({ status: 'ok', version: '1.0.0' }));

// Protected routes
app.use('/v1/*', jwt({ secret: Bun.env.JWT_SECRET! }));

const userSchema = z.object({
  email: z.string().email(),
  name: z.string().min(1),
});

app.post('/v1/users', zValidator('json', userSchema), async (c) => {
  const { email, name } = c.req.valid('json');
  const user = await createUser(email, name);  // your DB call
  return c.json(user, 201);
});

app.get('/v1/users/:id', async (c) => {
  const user = await getUser(c.req.param('id'));
  if (!user) return c.json({ error: 'Not found' }, 404);
  return c.json(user);
});

// Error handler
app.onError((err, c) => {
  console.error(err);
  return c.json({ error: err.message }, 500);
});

export default {
  port: Number(Bun.env.PORT) || 3000,
  fetch: app.fetch,
};

Run with Bun:

bash
bun run --watch src/index.ts

Or Node.js (via @hono/node-server):

bash
bun add @hono/node-server
# src/server.ts:
# import { serve } from '@hono/node-server';
# serve({ fetch: app.fetch, port: 3000 });
node src/server.ts

Same code. Swap runtime.

Step 3 — Database with Bun's built-in SQLite or Drizzle

SQLite (Bun native, no dep):

typescript
import { Database } from 'bun:sqlite';

const db = new Database('data.db', { create: true });
db.run(`
  CREATE TABLE IF NOT EXISTS users (
    id TEXT PRIMARY KEY,
    email TEXT UNIQUE,
    name TEXT
  )
`);

const insertUser = db.prepare('INSERT INTO users (id, email, name) VALUES (?, ?, ?)');
insertUser.run(crypto.randomUUID(), '[email protected]', 'Rajesh');

const users = db.prepare('SELECT * FROM users').all();

PostgreSQL with Drizzle ORM (works everywhere):

bash
bun add drizzle-orm postgres
bun add -D drizzle-kit
typescript
import { drizzle } from 'drizzle-orm/postgres-js';
import postgres from 'postgres';
import { pgTable, text, timestamp } from 'drizzle-orm/pg-core';

const client = postgres(Bun.env.DATABASE_URL!);
export const db = drizzle(client);

export const users = pgTable('users', {
  id: text('id').primaryKey().$defaultFn(() => crypto.randomUUID()),
  email: text('email').unique().notNull(),
  name: text('name').notNull(),
  createdAt: timestamp('created_at').defaultNow(),
});

// Usage:
await db.insert(users).values({ email: '[email protected]', name: 'Rajesh' });
const all = await db.select().from(users);

Drizzle is type-safe, introspectable, and works on Node, Bun, Edge. Unlike Prisma, no code generation step or binary dependency.

Step 4 — Deploy to DomainIndia VPS

systemd service /etc/systemd/system/hono-api.service:

ini
[Unit]
Description=Hono API
After=network.target postgresql.service

[Service]
Type=simple
User=hono
WorkingDirectory=/opt/hono-api
ExecStart=/home/hono/.bun/bin/bun run src/index.ts
Restart=on-failure
RestartSec=3

EnvironmentFile=/opt/hono-api/.env
StandardOutput=journal
StandardError=journal

[Install]
WantedBy=multi-user.target

Front with nginx + SSL (see Go deployment guide for same pattern).

Step 5 — Deploy to Cloudflare Workers (same code!)

The magic of Hono: deploy the same app to Cloudflare Workers:

bash
npm install -g wrangler
wrangler init --yes

wrangler.toml:

toml
name = "hono-api"
main = "src/index.ts"
compatibility_date = "2026-04-01"

src/index.ts (modified for Workers):

typescript
export default {
  async fetch(request: Request, env: Env): Promise<Response> {
    return app.fetch(request, env);
  },
};

Deploy:

bash
wrangler deploy

Same business logic. Now runs at 330+ edge locations. Dev/prod parity with your VPS.

Pattern: Edge + origin

Route some requests to edge (fast, cheap), others to VPS (stateful):

Client ─► Cloudflare Worker
             │
  ├── /api/search   → Worker handles (cached, fast)
  ├── /api/health   → Worker handles
  └── /api/orders   → Forwards to VPS (needs DB)
typescript
app.get('/api/orders/*', async (c) => {
  // Forward to VPS origin
  return fetch(`https://origin.yourcompany.com${c.req.path}`, c.req.raw);
});

Performance — real numbers

On a DomainIndia VPS Starter (2 GB):

StackReq/sec (hello world)Req/sec (DB query)
Express + Node.js 2018,0002,500
Hono + Node.js 2032,0003,000
Hono + Bun55,0003,200
Hono + Cloudflare Workers(global edge)(depends on origin)

Hono + Bun gives you raw throughput. For DB-bound workloads, runtime choice matters less — Postgres is the bottleneck.

Testing

Hono's test utility:

typescript
import { describe, test, expect } from 'bun:test';

describe('Health', () => {
  test('returns ok', async () => {
    const res = await app.request('/health');
    expect(res.status).toBe(200);
    const body = await res.json();
    expect(body.status).toBe('ok');
  });
});

Run: bun test.

Common pitfalls

FAQ

Q Hono, Express, or Fastify for new projects in 2026?

Hono — multi-runtime, future-proof, minimal. Express still fine for pure Node.js simplicity. Fastify if you need schema-first JSON validation and don't care about edge deployment.

Q Bun in production — is it ready?

Yes, for 2026. Major apps (Midjourney, Vercel, Supabase) use it. Node.js is still more battle-tested; go Bun for greenfield, Node for legacy.

Q Drizzle vs Prisma?

Drizzle: TypeScript-first, SQL-like API, no codegen, runs on edge. Prisma: More polished CLI, bigger ecosystem, slower on edge. Both are solid; Drizzle is the modern trend.

Q Can I run Bun on DomainIndia shared hosting?

Shared cPanel "Setup Node.js App" doesn't support Bun runtime. Use VPS, or use Node.js compatibility mode and deploy normally.

Q Hono on Cloudflare Workers — any limits?

Workers Free: 100K req/day, 10ms CPU, 128 MB. Workers Paid: 10M/mo, 50ms CPU. Past that: VPS with Hono + Node/Bun is unlimited (pay per VPS, not per request).

Run modern Node/Bun APIs on a DomainIndia VPS — zero platform tax. Get a VPS

Was this article helpful?

Your feedback helps us improve our documentation

Still need help? Submit a support ticket