-
Notifications
You must be signed in to change notification settings - Fork 852
DA-5233 Hono Guide Created #7156
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
+393
−0
Merged
Changes from all commits
Commits
Show all changes
10 commits
Select commit
Hold shift + click to select a range
1b73e42
DA-5233 Hono Guide Created
mhartington d4d2460
Optimised images with calibre/image-actions
github-actions[bot] 4fc3273
Optimised images with calibre/image-actions
github-actions[bot] d51e0d0
Apply suggestions from code review
mhartington 7856781
Apply suggestions from code review
mhartington 7ed5b05
Update content/800-guides/390-hono.mdx
mhartington 095742d
apply updates
mhartington e3d1d79
apply updates
mhartington 9649338
apply feedback
mhartington 2cc25c3
Merge branch 'main' into mhartington/DA-5233-hono-guide
ankur-arch File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Some comments aren't visible on the classic Files Changed page.
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,392 @@ | ||
--- | ||
title: 'How to use Prisma with Hono' | ||
metaTitle: 'How to use Prisma ORM and Prisma Postgres with Hono' | ||
description: 'Learn how to use Prisma ORM in a Hono app' | ||
sidebar_label: 'Hono' | ||
image: '/img/guides/prisma-hono-cover.png' | ||
completion_time: '15 min' | ||
community_section: true | ||
--- | ||
|
||
## Introduction | ||
|
||
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. | ||
|
||
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/hono). | ||
|
||
## Prerequisites | ||
- [Node.js 20+](https://nodejs.org) | ||
|
||
## 1. Set up your project | ||
|
||
Create a new Hono project: | ||
|
||
```terminal | ||
npm create hono@latest | ||
``` | ||
|
||
:::info | ||
- *Target directory?* `my-app` | ||
- *Which template do you want to use?* `nodejs` | ||
- *Install dependencies? (recommended)* `Yes` | ||
- *Which package manager do you want to use?* `npm` | ||
::: | ||
|
||
## 2. Install and configure Prisma | ||
|
||
### 2.1. Install dependencies | ||
|
||
To get started with Prisma, you'll need to install a few dependencies: | ||
|
||
<TabbedContent code> | ||
<TabItem value="Prisma Postgres (recommended)"> | ||
```terminal | ||
npm install prisma --save-dev | ||
npm install @prisma/extension-accelerate @prisma/client dotenv | ||
``` | ||
</TabItem> | ||
<TabItem value="Other databases"> | ||
```terminal | ||
npm install prisma --save-dev | ||
npm install @prisma/client dotenv | ||
``` | ||
</TabItem> | ||
</TabbedContent> | ||
|
||
Once installed, initialize Prisma in your project: | ||
|
||
```terminal | ||
npx prisma init --db --output ../src/generated/prisma | ||
```` | ||
|
||
:::info | ||
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" | ||
::: | ||
This will create: | ||
|
||
- A `prisma/` directory with a `schema.prisma` file | ||
- A `.env` file with a `DATABASE_URL` already set | ||
|
||
### 2.2. Define your Prisma Schema | ||
|
||
In the `prisma/schema.prisma` file, add the following models and change the generator to use the `prisma-client` provider: | ||
|
||
```prisma file=prisma/schema.prisma | ||
generator client { | ||
//edit-next-line | ||
provider = "prisma-client" | ||
engineType = "client" | ||
output = "../src/generated/prisma" | ||
} | ||
mhartington marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
datasource db { | ||
provider = "postgresql" | ||
url = env("DATABASE_URL") | ||
} | ||
|
||
//add-start | ||
model User { | ||
id Int @id @default(autoincrement()) | ||
email String @unique | ||
name String? | ||
posts Post[] | ||
} | ||
|
||
model Post { | ||
id Int @id @default(autoincrement()) | ||
title String | ||
content String? | ||
published Boolean @default(false) | ||
authorId Int | ||
author User @relation(fields: [authorId], references: [id]) | ||
} | ||
//add-end | ||
``` | ||
|
||
This creates two models: `User` and `Post`, with a one-to-many relationship between them. | ||
|
||
### 2.3. Configure the Prisma Client generator | ||
|
||
Now, run the following command to create the database tables and generate the Prisma Client: | ||
|
||
```terminal | ||
npx prisma migrate dev --name init | ||
``` | ||
### 2.4. Seed the database | ||
|
||
Let's add some seed data to populate the database with sample users and posts. | ||
|
||
Create a new file called `seed.ts` in the `prisma/` directory: | ||
|
||
```typescript file=prisma/seed.ts | ||
import { PrismaClient, Prisma } from "../src/generated/prisma/client.js"; | ||
|
||
const prisma = new PrismaClient(); | ||
|
||
const userData: Prisma.UserCreateInput[] = [ | ||
{ | ||
name: "Alice", | ||
email: "alice@prisma.io", | ||
posts: { | ||
create: [ | ||
{ | ||
title: "Join the Prisma Discord", | ||
content: "https://pris.ly/discord", | ||
published: true, | ||
}, | ||
{ | ||
title: "Prisma on YouTube", | ||
content: "https://pris.ly/youtube", | ||
}, | ||
], | ||
}, | ||
}, | ||
{ | ||
name: "Bob", | ||
email: "bob@prisma.io", | ||
posts: { | ||
create: [ | ||
{ | ||
title: "Follow Prisma on Twitter", | ||
content: "https://www.twitter.com/prisma", | ||
published: true, | ||
}, | ||
], | ||
}, | ||
}, | ||
]; | ||
|
||
export async function main() { | ||
for (const u of userData) { | ||
await prisma.user.create({ data: u }); | ||
} | ||
} | ||
|
||
main() | ||
.catch((e) => { | ||
console.error(e); | ||
process.exit(1); | ||
}) | ||
.finally(async () => { | ||
await prisma.$disconnect(); | ||
}); | ||
``` | ||
|
||
Now, tell Prisma how to run this script by updating your `package.json`: | ||
|
||
```json file=package.json | ||
{ | ||
"name": "my-app", | ||
"type": "module", | ||
"scripts": { | ||
"dev": "tsx watch src/index.ts", | ||
"build": "tsc", | ||
"start": "node dist/index.js" | ||
}, | ||
//add-start | ||
"prisma": { | ||
"seed": "tsx prisma/seed.ts" | ||
}, | ||
//add-end | ||
"dependencies": { | ||
"@hono/node-server": "^1.19.5", | ||
"@prisma/client": "^6.16.3", | ||
"@prisma/extension-accelerate": "^2.0.2", | ||
"dotenv": "^17.2.3", | ||
"hono": "^4.9.9" | ||
}, | ||
"devDependencies": { | ||
"@types/node": "^20.11.17", | ||
"prisma": "^6.16.3", | ||
"tsx": "^4.20.6", | ||
"typescript": "^5.8.3" | ||
} | ||
} | ||
``` | ||
|
||
Run the seed script: | ||
|
||
```terminal | ||
npx prisma db seed | ||
``` | ||
|
||
And open Prisma Studio to inspect your data: | ||
|
||
```terminal | ||
npx prisma studio | ||
``` | ||
|
||
## 3. Integrate Prisma into Hono | ||
|
||
### 3.1. Create a Prisma middleware | ||
|
||
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: | ||
|
||
<TabbedContent code> | ||
<TabItem value="Prisma Postgres (recommended)"> | ||
|
||
```tsx file=src/lib/prisma.ts | ||
import type { Context, Next } from 'hono'; | ||
import { PrismaClient } from '../generated/prisma/client.js'; | ||
import { withAccelerate } from '@prisma/extension-accelerate'; | ||
|
||
function withPrisma(c: Context, next: Next) { | ||
if (!c.get('prisma')) { | ||
const databaseUrl = process.env.DATABASE_URL; | ||
mhartington marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
if (!databaseUrl) { | ||
throw new Error('DATABASE_URL is not set'); | ||
} | ||
const prisma = new PrismaClient({ datasourceUrl: databaseUrl }) | ||
.$extends(withAccelerate()); | ||
|
||
c.set('prisma', prisma); | ||
} | ||
return next(); | ||
} | ||
export default withPrisma; | ||
``` | ||
|
||
</TabItem> | ||
|
||
<TabItem value="Other databases"> | ||
|
||
```tsx file=src/lib/prisma.ts | ||
import type { Context, Next } from 'hono'; | ||
import { PrismaClient } from '../generated/prisma/client.js'; | ||
|
||
const databaseUrl = process.env.DATABASE_URL; | ||
if (!databaseUrl) { | ||
throw new Error('DATABASE_URL is not set'); | ||
} | ||
const prisma = new PrismaClient({ datasourceUrl: databaseUrl }); | ||
|
||
function withPrisma(c: Context, next: Next) { | ||
if (!c.get('prisma')) { | ||
c.set('prisma', prisma); | ||
} | ||
return next(); | ||
} | ||
|
||
export default withPrisma; | ||
``` | ||
</TabItem> | ||
</TabbedContent> | ||
|
||
:::warning | ||
We recommend using a connection pooler (like [Prisma Accelerate](https://www.prisma.io/accelerate)) to manage database connections efficiently. | ||
mhartington marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
If you choose not to use one, in long-lived environments (for example, a Node.js server) instantiate a single `PrismaClient` and reuse it across requests to avoid exhausting database connections. In serverless environments or when using a pooler (for example, Accelerate), creating a client per request is acceptable. | ||
::: | ||
|
||
### 3.2 Environment Variables & Types | ||
|
||
By default, Hono does not load any environment variables from a `.env`. `dotenv` handles this and will be read that file and expose them via `process.env`. | ||
|
||
Edit the `src/index.ts` to import `dotenv` and call the `config` method on it. | ||
|
||
```ts file=src/index.ts | ||
import { Hono } from 'hono'; | ||
import { serve } from '@hono/node-server'; | ||
|
||
// Read .env and set variables to process.env | ||
import * as dotenv from 'dotenv'; | ||
dotenv.config(); | ||
``` | ||
|
||
Next, Hono needs additional types to to know that the `withPrisma` middleware will set a `prisma` | ||
key on the Hono Context | ||
|
||
```ts file=src/index.ts | ||
import { Hono } from "hono"; | ||
import { serve } from "@hono/node-server"; | ||
// add-next-line | ||
import type { PrismaClient } from "./generated/prisma/client.js"; | ||
|
||
import * as dotenv from "dotenv"; | ||
dotenv.config(); | ||
|
||
// add-start | ||
type ContextWithPrisma = { | ||
Variables: { | ||
prisma: PrismaClient; | ||
}; | ||
}; | ||
// add-end | ||
|
||
// edit-next-line | ||
const app = new Hono<ContextWithPrisma>(); | ||
|
||
app.get("/", (c) => { | ||
return c.text("Hello Hono!"); | ||
}); | ||
|
||
serve( | ||
{ | ||
fetch: app.fetch, | ||
port: 3000, | ||
}, | ||
(info) => { | ||
console.log(`Server is running on http://localhost:${info.port}`); | ||
} | ||
); | ||
``` | ||
|
||
If using Cloudflare Workers, the environment variables will automatically be set to Hono's contenxt, | ||
so `dotenv` can be skipped. | ||
|
||
|
||
### 3.3. Create A GET Route | ||
|
||
Fetch data from the database using Hono's `app.get` function. This will perform any database queries | ||
and return the data as JSON. | ||
|
||
Create a new route inside of `src/index.ts`: | ||
|
||
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: | ||
|
||
```ts file=src/index.ts | ||
import withPrisma from './lib/prisma.js'; | ||
|
||
app.get('/users', withPrisma, async (c) => { | ||
const prisma = c.get('prisma'); | ||
const users = await prisma.user.findMany({ | ||
include: { posts: true }, | ||
}); | ||
return c.json({ users }); | ||
}); | ||
``` | ||
mhartington marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
|
||
### 3.4. Display The Data | ||
|
||
Start the Hono app by call the `dev` script in the `package.json` | ||
|
||
```terminal | ||
npm run dev | ||
``` | ||
|
||
There should be a "Server is running on http://localhost:3000" log printed out. From here, the data | ||
can be viewed by visting `http://localhost:3000/users` or by running `curl` from the command line | ||
|
||
```terminal | ||
curl http://localhost:3000/users | jq | ||
``` | ||
|
||
You're done! You've created a Hono app with Prisma that's connected to a Prisma Postgres database. | ||
For next steps there are some resources below for you to explore as well as next steps for expanding | ||
your project. | ||
|
||
## Next Steps | ||
|
||
Now that you have a working Hono app connected to a Prisma Postgres database, you can: | ||
|
||
- Extend your Prisma schema with more models and relationships | ||
- Add create/update/delete routes and forms | ||
- Explore authentication and validation | ||
- Enable query caching with [Prisma Postgres](/postgres/database/caching) for better performance | ||
|
||
### More Info | ||
|
||
- [Prisma Documentation](/orm/overview/introduction) | ||
- [Hono Documentation](https://hono.dev/docs/) |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.