|
| 1 | +--- |
| 2 | +title: How to use Prisma Next with Hono |
| 3 | +description: Build a Hono API on Prisma Next with the hono template, then add your own routes. |
| 4 | +url: /guides/next/hono |
| 5 | +metaTitle: How to use Prisma Next with Hono |
| 6 | +metaDescription: Scaffold a Hono API backed by Prisma Next and Prisma Postgres, seed it, serve users over HTTP, and add a POST route, with tested commands and output. |
| 7 | +badge: early-access |
| 8 | +--- |
| 9 | + |
| 10 | +## Introduction |
| 11 | + |
| 12 | +In this guide, you scaffold a Hono API backed by Prisma Next, initialize and seed a PostgreSQL database, serve data over HTTP, and add your own POST route. The `hono` template generates the server for you, so most of the work is understanding the pieces and extending them. |
| 13 | + |
| 14 | +Every command, route, and response below was run end to end against a live Prisma Postgres database. |
| 15 | + |
| 16 | +## Prerequisites |
| 17 | + |
| 18 | +- Node.js 24 or later, or [Bun](https://bun.sh/) (this guide uses Bun for speed; npm works the same) |
| 19 | +- A PostgreSQL connection string, or nothing at all: the scaffold can create a [Prisma Postgres](/postgres) database for you |
| 20 | + |
| 21 | +## 1. Scaffold the project |
| 22 | + |
| 23 | +```bash |
| 24 | +bunx create-prisma@next create my-hono-api --provider postgres --template hono |
| 25 | +``` |
| 26 | + |
| 27 | +Pick your package manager and database at the prompts. The template generates a Hono server in `src/index.ts` with two routes (`GET /` and `GET /users`), the Prisma Next setup in `src/prisma/`, and package scripts for the database steps. |
| 28 | + |
| 29 | +```bash |
| 30 | +cd my-hono-api |
| 31 | +``` |
| 32 | + |
| 33 | +## 2. Update the starter query helpers |
| 34 | + |
| 35 | +Model access is namespace-qualified on PostgreSQL (`db.orm.public.User`), and the current template's helper files still use the older flat form, which fails at runtime. Open `src/prisma/users.ts` and `src/prisma/seed.ts` and change every `db.orm.User` to `db.orm.public.User`: |
| 36 | + |
| 37 | +```ts title="src/prisma/users.ts" |
| 38 | +const users = await db.orm.public.User |
| 39 | + .select("id", "email", "username", "name", "createdAt") |
| 40 | + .take(limit) |
| 41 | + .all(); |
| 42 | +``` |
| 43 | + |
| 44 | +:::note |
| 45 | + |
| 46 | +This is a known template issue and will disappear from this guide once the template is updated. |
| 47 | + |
| 48 | +::: |
| 49 | + |
| 50 | +## 3. Initialize and seed the database |
| 51 | + |
| 52 | +```bash |
| 53 | +bun run db:init |
| 54 | +bun run db:seed |
| 55 | +``` |
| 56 | + |
| 57 | +```text no-copy |
| 58 | +"summary": "Applied 5 operation(s) across 1 space(s), database signed" |
| 59 | +Seeded 3 users. |
| 60 | +``` |
| 61 | + |
| 62 | +## 4. Run the server |
| 63 | + |
| 64 | +```bash |
| 65 | +bun run dev |
| 66 | +``` |
| 67 | + |
| 68 | +The server starts on port 3000 (set `PORT` to change it). Check both routes: |
| 69 | + |
| 70 | +```bash |
| 71 | +curl http://localhost:3000/users |
| 72 | +``` |
| 73 | + |
| 74 | +```json no-copy |
| 75 | +[ |
| 76 | + { "id": "1", "email": "alice@prisma.io", "username": "alice", "name": "Alice", "createdAt": "2026-07-06T23:37:32.440Z" }, |
| 77 | + { "id": "2", "email": "bob@prisma.io", "username": "bob", "name": "Bob", "createdAt": "2026-07-06T23:37:32.474Z" }, |
| 78 | + { "id": "3", "email": "carol@prisma.io", "username": "carol", "name": "Carol", "createdAt": "2026-07-06T23:37:32.507Z" } |
| 79 | +] |
| 80 | +``` |
| 81 | + |
| 82 | +The route handler is ordinary Hono code calling an ordinary Prisma Next query; there is no framework adapter in between. |
| 83 | + |
| 84 | +## 5. Add a POST route |
| 85 | + |
| 86 | +Add a route that creates a user from the request body. Add this to `src/index.ts` above the `serve(...)` call: |
| 87 | + |
| 88 | +```ts title="src/index.ts" |
| 89 | +app.post("/users", async (c) => { |
| 90 | + const body = await c.req.json<{ email: string; name?: string }>(); |
| 91 | + const { db } = await import("./prisma/db"); |
| 92 | + const user = await db.orm.public.User.create({ |
| 93 | + email: body.email, |
| 94 | + name: body.name ?? null, |
| 95 | + }); |
| 96 | + return c.json(user, 201); |
| 97 | +}); |
| 98 | +``` |
| 99 | + |
| 100 | +Restart the server and create a user: |
| 101 | + |
| 102 | +```bash |
| 103 | +curl -X POST http://localhost:3000/users \ |
| 104 | + -H "content-type: application/json" \ |
| 105 | + -d '{"email":"dev@prisma.io","name":"Dev"}' |
| 106 | +``` |
| 107 | + |
| 108 | +```json no-copy |
| 109 | +{ "createdAt": "2026-07-06T23:37:56.184Z", "email": "dev@prisma.io", "id": 4, "name": "Dev", "username": null } |
| 110 | +``` |
| 111 | + |
| 112 | +`.create(...)` returns the full inserted record, database defaults included, so the response needs no second query. |
| 113 | + |
| 114 | +## Common gotchas |
| 115 | + |
| 116 | +:::warning |
| 117 | + |
| 118 | +In a long-running server, don't call `db.close()` in route handlers; the client's connection pool is shared across requests. Close it only on process shutdown. |
| 119 | + |
| 120 | +::: |
| 121 | + |
| 122 | +## Prompt your coding agent |
| 123 | + |
| 124 | +The scaffold installs Prisma Next skills for your coding agent. Prompts that map to this guide: |
| 125 | + |
| 126 | +- "Using the prisma-next-queries skill, add GET /users/:id that returns one user or a 404." |
| 127 | +- "Add a Post model related to User, update the database, and expose GET /users/:id/posts." |
| 128 | +- "Wrap the signup route's writes in a transaction." |
| 129 | + |
| 130 | +## Next steps |
| 131 | + |
| 132 | +- [Read the Prisma Next overview](/orm/next) for the concepts behind contracts and typed queries. |
0 commit comments