Skip to content

Commit 3e2f7bd

Browse files
committed
DA-5233 Hono Guide Created
1 parent 09ceaf5 commit 3e2f7bd

File tree

2 files changed

+364
-0
lines changed

2 files changed

+364
-0
lines changed

content/800-guides/390-hono.mdx

Lines changed: 363 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,363 @@
1+
---
2+
title: 'How to use Prisma ORM with Hono'
3+
metaTitle: 'How to use Prisma ORM and Prisma Postgres with Hono'
4+
description: 'Learn how to use Prisma ORM in a Hono app'
5+
sidebar_label: 'Hono'
6+
image: '/img/guides/prisma-astro-cover.png'
7+
completion_time: '15 min'
8+
community_section: true
9+
---
10+
11+
## Introduction
12+
13+
Prisma ORM offers type-safe database access, and [Hono](https://hono.dev/) is built for fast, lightweight web apps. Together with [Prisma Postgres](https://www.prisma.io/postgres), you get a fast, lightweight backend, that can be deployed through Node.js, Cloudflare, or many other runtimes.
14+
15+
In this guide, you'll learn to integrate Prisma ORM with a Prisma Postgres database in a Hono backend application. You can find a complete example of this guide on [GitHub](https://github.com/prisma/prisma-examples/tree/latest/orm/node).
16+
17+
## Prerequisites
18+
- [Node.js 20+](https://nodejs.org)
19+
20+
## 1. Set up your project
21+
22+
Create a new Hono project:
23+
24+
```terminal
25+
npm create hono@latest
26+
```
27+
28+
:::info
29+
- *Target directory?* `my-app`
30+
- *Which template do you want to use?* `nodejs`
31+
- *Install dependencies? (recommended)* `Yes`
32+
- *Do you want to install project dependencies?* `Yes`
33+
- *Which package manager do you want to use?* `npm`
34+
:::
35+
36+
## 2. Install and Configure Prisma
37+
38+
### 2.1. Install dependencies
39+
40+
To get started with Prisma, you'll need to install a few dependencies:
41+
42+
<TabbedContent code>
43+
<TabItem value="Prisma Postgres (recommended)">
44+
```terminal
45+
npm install prisma dotenv --save-dev
46+
npm install @prisma/extension-accelerate @prisma/client
47+
```
48+
</TabItem>
49+
<TabItem value="Other databases">
50+
```terminal
51+
npm install prisma dotenv --save-dev
52+
npm install @prisma/client
53+
```
54+
</TabItem>
55+
</TabbedContent>
56+
57+
Once installed, initialize Prisma in your project:
58+
59+
```terminal
60+
npx prisma init --db --output ../src/generated/prisma
61+
```
62+
:::info
63+
You'll need to answer a few questions while setting up your Prisma Postgres database. Select the region closest to your location and a memorable name for your database like "My Hono Project"
64+
:::
65+
This will create:
66+
67+
- A `prisma/` directory with a `schema.prisma` file
68+
- A `.env` file with a `DATABASE_URL` already set
69+
70+
### 2.2. Define your Prisma Schema
71+
72+
In the `prisma/schema.prisma` file, add the following models and change the generator to use the `prisma-client` provider:
73+
74+
```prisma file=prisma/schema.prisma
75+
generator client {
76+
//edit-next-line
77+
provider = "prisma-client"
78+
output = "../src/generated/prisma"
79+
}
80+
81+
datasource db {
82+
provider = "postgresql"
83+
url = env("DATABASE_URL")
84+
}
85+
86+
//add-start
87+
model User {
88+
id Int @id @default(autoincrement())
89+
email String @unique
90+
name String?
91+
posts Post[]
92+
}
93+
94+
model Post {
95+
id Int @id @default(autoincrement())
96+
title String
97+
content String?
98+
published Boolean @default(false)
99+
authorId Int
100+
author User @relation(fields: [authorId], references: [id])
101+
}
102+
//add-end
103+
```
104+
105+
This creates two models: `User` and `Post`, with a one-to-many relationship between them.
106+
107+
### 2.3. Configure the Prisma Client generator
108+
109+
Now, run the following command to create the database tables and generate the Prisma Client:
110+
111+
```terminal
112+
npx prisma migrate dev --name init
113+
```
114+
### 2.4. Seed the database
115+
116+
Let's add some seed data to populate the database with sample users and posts.
117+
118+
Create a new file called `seed.ts` in the `prisma/` directory:
119+
120+
```typescript file=prisma/seed.ts
121+
import { PrismaClient, Prisma } from "../src/generated/prisma/client.js";
122+
123+
const prisma = new PrismaClient();
124+
125+
const userData: Prisma.UserCreateInput[] = [
126+
{
127+
name: "Alice",
128+
129+
posts: {
130+
create: [
131+
{
132+
title: "Join the Prisma Discord",
133+
content: "https://pris.ly/discord",
134+
published: true,
135+
},
136+
{
137+
title: "Prisma on YouTube",
138+
content: "https://pris.ly/youtube",
139+
},
140+
],
141+
},
142+
},
143+
{
144+
name: "Bob",
145+
146+
posts: {
147+
create: [
148+
{
149+
title: "Follow Prisma on Twitter",
150+
content: "https://www.twitter.com/prisma",
151+
published: true,
152+
},
153+
],
154+
},
155+
},
156+
];
157+
158+
export async function main() {
159+
for (const u of userData) {
160+
await prisma.user.create({ data: u });
161+
}
162+
}
163+
164+
main()
165+
.catch((e) => {
166+
console.error(e);
167+
process.exit(1);
168+
})
169+
.finally(async () => {
170+
await prisma.$disconnect();
171+
});
172+
```
173+
174+
Now, tell Prisma how to run this script by updating your `package.json`:
175+
176+
```json file=package.json
177+
{
178+
"name": "my-app",
179+
"type": "module",
180+
"scripts": {
181+
"dev": "tsx watch src/index.ts",
182+
"build": "tsc",
183+
"start": "node dist/index.js"
184+
},
185+
//add-start
186+
"prisma": {
187+
"seed": "tsx prisma/seed.ts"
188+
},
189+
//add-end
190+
"dependencies": {
191+
"@hono/node-server": "^1.19.5",
192+
"@prisma/client": "^6.16.3",
193+
"@prisma/extension-accelerate": "^2.0.2",
194+
"dotenv": "^17.2.3",
195+
"hono": "^4.9.9"
196+
},
197+
"devDependencies": {
198+
"@types/node": "^20.11.17",
199+
"prisma": "^6.16.3",
200+
"tsx": "^4.20.6",
201+
"typescript": "^5.8.3"
202+
}
203+
}
204+
```
205+
206+
Run the seed script:
207+
208+
```terminal
209+
npx prisma db seed
210+
```
211+
212+
And open Prisma Studio to inspect your data:
213+
214+
```terminal
215+
npx prisma studio
216+
```
217+
218+
## 3. Integrate Prisma Into Hono
219+
220+
### 3.1. Create a Prisma Middleware
221+
222+
Inside of `/src`, create a `lib` directory and a `prisma.ts` file inside it. This file will be used to create and export your Prisma Client instance. Set up the Prisma client like this:
223+
224+
<TabbedContent code>
225+
<TabItem value="Prisma Postgres (recommended)">
226+
```tsx file=src/lib/prisma.ts
227+
import type { Context, Next } from 'hono';
228+
import { PrismaClient } from '../generated/prisma/client.js';
229+
import { withAccelerate } from '@prisma/extension-accelerate';
230+
231+
function withPrisma(c: Context, next: Next) {
232+
if (!c.get('prisma')) {
233+
const databaseUrl = process.env.DATABASE_URL;
234+
235+
if (!databaseUrl) {
236+
throw new Error('DATABASE_URL is not set');
237+
}
238+
const prisma = new PrismaClient({ datasourceUrl: databaseUrl })
239+
.$extends(withAccelerate());
240+
241+
c.set('prisma', prisma);
242+
}
243+
return next();
244+
}
245+
export default withPrisma;
246+
```
247+
</TabItem>
248+
249+
<TabItem value="Other databases">
250+
```tsx file=src/lib/prisma.ts
251+
import type { Context, Next } from 'hono';
252+
import { PrismaClient } from '../generated/prisma/client.js';
253+
254+
function withPrisma(c: Context, next: Next) {
255+
if (!c.get('prisma')) {
256+
const databaseUrl = process.env.DATABASE_URL;
257+
258+
if (!databaseUrl) {
259+
throw new Error('DATABASE_URL is not set');
260+
}
261+
const prisma = new PrismaClient({ datasourceUrl: databaseUrl })
262+
263+
c.set('prisma', prisma);
264+
}
265+
return next();
266+
}
267+
export default withPrisma;
268+
```
269+
</TabItem>
270+
</TabbedContent>
271+
272+
:::warning
273+
We recommend using a connection pooler (like [Prisma Accelerate](https://www.prisma.io/accelerate)) to manage database connections efficiently.
274+
275+
If you choose not to use one, **avoid** instantiating `PrismaClient` globally in long-lived environments. Instead, create and dispose of the client per request to prevent exhausting your database connections.
276+
:::
277+
278+
### 3.2 Environment Variables & Types
279+
280+
By default, Hono does not load any environment variables from a `.env`. `dotenv` handles this and
281+
will be read that file and expose them via `process.env`.
282+
283+
Edit the `src/index.ts` to import `dotenv` and call the `config` method on it.
284+
285+
```ts file=src/index.ts
286+
import { Hono } from 'hono';
287+
import { serve } from '@hono/node-server';
288+
289+
// Read .env and set variables to process.env
290+
import * as dotenv from 'dotenv';
291+
dotenv.config();
292+
```
293+
294+
Next, Hono needs additional types to to know that the `withPrisma` middleware will set a `prsima`
295+
key on the Hono Context
296+
297+
```ts file=src/index.ts
298+
import type { PrismaClient } from './generated/prisma/client.js';
299+
300+
type ContextWithPrisma = {
301+
Variables: {
302+
prisma: PrismaClient;
303+
};
304+
};
305+
306+
const app = new Hono<ContextWithPrisma>();
307+
```
308+
309+
310+
### 3.3. Create A GET Route
311+
312+
Fetch data from the database using Hono's `app.get` function. This will perform any database queries
313+
and return the data as JSON.
314+
315+
Create a new route inside of `src/index.ts`:
316+
317+
Now, create a GET route that fetches the `Users` data from your database, making sure to include each user's `Posts` by adding them to the `include` field:
318+
319+
```ts file=src/index.ts
320+
import withPrisma from './lib/prisma.js';
321+
322+
app.get('/users', withPrisma, async (c) => {
323+
const prisma = c.get('prisma');
324+
const users = await prisma.user.findMany({
325+
include: { posts: true },
326+
});
327+
return c.json({ users });
328+
});
329+
```
330+
331+
332+
### 3.4. Display The Data
333+
334+
Start the Hono app by call the `dev` script in the `package.json`
335+
336+
```terminal
337+
npm run dev
338+
```
339+
340+
There should be a "Server is running on http://localhost:3000" log printed out. From here, the data
341+
can be viewed by visting `http://localhost:3000/users` or by running `curl` from the command line
342+
343+
```terminal
344+
curl http://localhost:3000/users | jq
345+
```
346+
347+
You're done! You've created a Hono app with Prisma that's connected to a Prisma Postgres database.
348+
For next steps there are some resources below for you to explore as well as next steps for expanding
349+
your project.
350+
351+
## Next Steps
352+
353+
Now that you have a working Hono app connected to a Prisma Postgres database, you can:
354+
355+
- Extend your Prisma schema with more models and relationships
356+
- Add create/update/delete routes and forms
357+
- Explore authentication and validation
358+
- Enable query caching with [Prisma Postgres](/postgres/database/caching) for better performance
359+
360+
### More Info
361+
362+
- [Prisma Documentation](/orm/overview/introduction)
363+
- [Hono Documentation](https://hono.dev/docs/)

sidebars.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -418,6 +418,7 @@ const sidebars: SidebarsConfig = {
418418
"guides/nuxt",
419419
"guides/sveltekit",
420420
"guides/astro",
421+
"guides/hono",
421422
"guides/solid-start",
422423
"guides/react-router-7",
423424
"guides/tanstack-start",

0 commit comments

Comments
 (0)