Hono
Learn how to use Prisma ORM in a Hono app
Introduction
Prisma ORM offers type-safe database access, and Hono is built for fast, lightweight web apps. Together with Prisma 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.
Prerequisites
1. Set up your project
Create a new Hono project:
npm create hono@latest- 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:
npm install prisma tsx @types/pg --save-devnpm install @prisma/client @prisma/adapter-pg dotenv pgIf you are using a different database provider (MySQL, SQL Server, SQLite), install the corresponding driver adapter package instead of @prisma/adapter-pg. For more information, see Database drivers.
Once installed, initialize Prisma in your project:
npx prisma init --db --output ../src/generated/prismaYou'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 aschema.prismafile - A
prisma.config.tswith your Prisma configuration - A
.envfile with aDATABASE_URLalready 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:
generator client {
provider = "prisma-client"
output = "../src/generated/prisma"
}
datasource db {
provider = "postgresql"
}
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])
} This creates two models: User and Post, with a one-to-many relationship between them.
In prisma.config.ts, import dotenv at the top of the file
import { defineConfig, env } from "prisma/config";
import "dotenv/config";
export default defineConfig({
schema: "prisma/schema.prisma",
migrations: {
path: "prisma/migrations",
},
datasource: {
url: env("DATABASE_URL"),
},
});2.3. Configure the Prisma Client generator
Now, run the following command to create the database tables and generate the Prisma Client:
npx prisma migrate dev --name initnpx prisma generate2.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:
import { PrismaClient, Prisma } from "../src/generated/prisma/client.js";
import { PrismaPg } from "@prisma/adapter-pg";
const adapter = new PrismaPg({
connectionString: process.env.DATABASE_URL!,
});
const prisma = new PrismaClient({
adapter,
});
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 prisma.config.ts:
import { defineConfig, env } from "prisma/config";
import "dotenv/config";
export default defineConfig({
schema: "prisma/schema.prisma",
migrations: {
path: "prisma/migrations",
seed: "tsx prisma/seed.ts",
},
datasource: {
url: env("DATABASE_URL"),
},
});Run the seed script:
npx prisma db seedAnd open Prisma Studio to inspect your data:
npx prisma studio3. 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:
import type { Context, Next } from "hono";
import { PrismaClient } from "../generated/prisma/client.js";
import { PrismaPg } from "@prisma/adapter-pg";
import "dotenv/config";
const databaseUrl = process.env.DATABASE_URL;
if (!databaseUrl) {
throw new Error("DATABASE_URL is not set");
}
const adapter = new PrismaPg({
connectionString: databaseUrl,
});
const prisma = new PrismaClient({ adapter });
function withPrisma(c: Context, next: Next) {
if (!c.get("prisma")) {
c.set("prisma", prisma);
}
return next();
}
export default withPrisma;We recommend using a connection pooler (like Prisma Accelerate) to manage database connections efficiently.
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. Hono can get additional types to know that the withPrisma middleware will set a prisma
key on the Hono context
import { Hono } from "hono";
import { serve } from "@hono/node-server";
import type { PrismaClient } from "./generated/prisma/client.js";
type ContextWithPrisma = {
Variables: {
prisma: PrismaClient;
};
};
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 context, 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:
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 });
});3.4. Display The Data
Start the Hono app by call the dev script in the package.json
npm run devThere should be a "Server is running on http://localhost:3000" log printed out. From here, the data
can be viewed by visiting http://localhost:3000/users or by running curl from the command line
curl http://localhost:3000/users | jqYou'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 for better performance