Guides/ TypeScript

Hono with tRPC and Drizzle

Create a TypeScript fullstack app with Hono, tRPC, Drizzle, PostgreSQL, TanStack Router, Tailwind CSS, and Better Auth.

Updated 2026-05-12

honotrpcdrizzletanstack-router

Use this stack when you want a fast TypeScript API server and a separate React frontend with typed client-server calls.

npm create better-fullstack@latest my-hono-app -- \
  --ecosystem typescript \
  --frontend tanstack-router \
  --backend hono \
  --runtime bun \
  --database postgres \
  --orm drizzle \
  --auth better-auth \
  --api trpc \
  --css-framework tailwind \
  --ui-library shadcn-ui \
  --package-manager bun

What this creates

  • A TanStack Router frontend.
  • A Hono backend running on Bun.
  • PostgreSQL and Drizzle.
  • Better Auth.
  • tRPC between the web app and API.
  • A monorepo structure for frontend and server packages.

Generated shape

This command creates a split app shape: the frontend and backend are separate packages, but they are generated together and share the same stack configuration. That makes the API boundary explicit without giving up TypeScript inference.

Representative shape:

my-hono-app/
  bts.jsonc
  apps/
    web/
    server/
  packages/
    shared/

The exact workspace names may differ, but the architectural point is the same: TanStack Router owns the browser app, Hono owns HTTP, Drizzle owns database access, and tRPC is the typed contract between them.

Example Hono route

Hono is useful when request handling should stay explicit and lightweight:

import { Hono } from "hono";

const app = new Hono();

app.get("/health", (c) => {
  return c.json({ ok: true });
});

export default app;

Keep framework-level middleware, auth context, and request logging in the server package. Avoid leaking Hono request objects into shared business logic.

Example tRPC procedure shape

tRPC procedures should be small, validated entry points around server operations:

import { z } from "zod";

const createTaskInput = z.object({
  title: z.string().min(1),
});

export const taskProcedures = {
  create: async (rawInput: unknown, userId: string) => {
    const input = createTaskInput.parse(rawInput);

    return {
      id: crypto.randomUUID(),
      title: input.title,
      ownerId: userId,
    };
  },
};

For larger apps, put validation schemas in a shared module only when both client and server need them. Database writes should stay server-only.

When to choose it

Choose Hono when the backend should stay small, fast, and explicit. This setup works well for API-first products, dashboards, internal tools, and services that may later split frontend and backend deployment.

Compatibility notes

  • --frontend tanstack-router plus --backend hono gives a separate React web app and API server.
  • --runtime bun selects Bun for the Hono service in this guide.
  • --api trpc is appropriate here because the frontend is React-based. For SvelteKit, Nuxt, or SolidStart guides, Better Fullstack uses oRPC instead.
  • PostgreSQL and Drizzle are a production-oriented pair for this split service shape.

Deployment notes

Plan for two deployable targets if your host treats the frontend and Hono server separately. Configure CORS, auth cookie domains, and public API URLs deliberately; split services make those details visible.

The API server needs the PostgreSQL connection string and auth secrets. The web app needs the API origin and any public app URL values. Keep secrets out of frontend build-time public variables.

Troubleshooting

  • If browser requests fail before reaching Hono, inspect CORS and the configured API base URL.
  • If auth cookies are missing across domains, check same-site settings, secure cookies, and whether web/API domains match your intended deployment.
  • If tRPC calls compile but fail at runtime, verify the Hono tRPC adapter is mounted at the same path used by the client.
  • If generated apps cannot connect to PostgreSQL locally, confirm the database is running and the connection string matches the selected database.

Tradeoffs

If you want a single framework to own the whole app, use TanStack Start or Next.js. If you want a separate API boundary, Hono is the cleaner default.

Compared with a self-backend fullstack framework, this stack has more moving parts. The payoff is a cleaner service boundary, easier API-focused testing, and a backend that can later serve multiple clients.

Next steps