How to use Prisma ORM with SolidStart
Introduction
Prisma ORM streamlines database access with type-safe queries and a smooth developer experience. SolidStart, a modern framework for building reactive web apps with SolidJS, pairs well with Prisma and Postgres to create a clean and scalable full-stack architecture.
In this guide, you'll learn how to integrate Prisma ORM with a Prisma Postgres database in a SolidStart project from scratch. You can find a complete example of this guide on GitHub.
Prerequisites
Before getting started, make sure you have the following installed:
- Node.js 18+ installed
Step 1: Set Up a SolidStart Project
Begin by creating a new SolidStart app. In your terminal, run:
npm init solid@latest
Use the following options when prompted:
- Project name:
my-solid-prisma-app
(or any name you prefer) - Is this a SolidStart project:
yes
- Template:
bare
- Use TypeScript:
yes
Next, navigate into your new project, install dependencies, and start the development server:
cd my-solid-prisma-app
npm install
npm run dev
Once the dev server is running, open http://localhost:3000
in your browser. You should see the SolidStart welcome screen.
Let's clean up the default UI by editing the app.tsx
file and replacing the header:
import { createSignal } from "solid-js";
import "./app.css";
export default function App() {
const [count, setCount] = createSignal(0);
return (
<main>
<h1>SolidStart + Prisma</h1>
<h1>Hello world!</h1>
<button class="increment" onClick={() => setCount(count() + 1)} type="button">
Clicks: {count()}
</button>
<p>
Visit{" "}
<a href="https://start.solidjs.com" target="_blank">
start.solidjs.com
</a>{" "}
to learn how to build SolidStart apps.
</p>
</main>
);
}
Your app.tsx
file should now look like this:
import "./app.css";
export default function App() {
return (
<main>
<h1>SolidStart + Prisma</h1>
</main>
);
}
Step 2: Install and Initialize Prisma
To get started with Prisma, you'll need to install a few dependencies:
npm install prisma --save-dev
npm install tsx --save-dev
npm install @prisma/extension-accelerate
If you're not using a Prisma Postgres database, you can skip @prisma/extension-accelerate
.
Once installed, initialize Prisma in your project:
npx prisma init --db
This will create:
- A
prisma/
directory with aschema.prisma
file - A
.env
file with aDATABASE_URL
already set
Step 2.1: Define Your Prisma Schema
Open the prisma/schema.prisma
file and add the following models:
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.
Now, run the following command to create the database tables and generate the Prisma Client:
npx prisma migrate dev --name init
Step 2.2: 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 "@prisma/client";
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();
Now, tell Prisma how to run this script by updating your package.json
:
"prisma": {
"seed": "tsx prisma/seed.ts"
}
Run the seed script:
npx prisma db seed
And open Prisma Studio to inspect your data:
npx prisma studio
Step 3: Use Prisma Client in Your Application
Step 3.1: Create a Prisma Client
At the root of your project, create a new lib
folder and a prisma.ts
file inside it:
mkdir -p lib && touch lib/prisma.ts
Add the following code to create a Prisma Client instance:
import { PrismaClient } from "@prisma/client";
import { withAccelerate } from "@prisma/extension-accelerate";
const prisma = new PrismaClient().$extends(withAccelerate());
export default prisma;
If you're not using Prisma Postgres, remove .$extends(withAccelerate())
.
Step 3.2: Create an API Route
Now, let's fetch data from the database using an API route.
Create a new file at src/routes/api/users.ts
:
import prisma from "../../lib/prisma";
export async function GET() {
const users = await prisma.user.findMany({
include: {
posts: true,
},
});
return new Response(JSON.stringify(users), {
headers: { "Content-Type": "application/json" },
});
}
Step 4: Fetch Data in Your Component
In your app.tsx
file, use createResource
to fetch data from your new API route:
import "./app.css";
import { createResource } from "solid-js";
import { User, Post } from "@prisma/client";
type UserWithPosts = User & {
posts: Post[];
};
const fetchUsers = async () => {
const res = await fetch("http://localhost:3000/api/users");
return res.json();
};
export default function App() {
const [users, { mutate, refetch }] = createResource<UserWithPosts[]>(fetchUsers);
return (
<main>
<h1>SolidStart + Prisma</h1>
</main>
);
}
createResource
is a SolidJS hook for managing async data. It tracks loading and error states automatically. Learn more.
Step 5: Display the Data
To show the users and their posts, use SolidJS's <For>
component:
import "./app.css";
import { createResource, For } from "solid-js";
import { User, Post } from "@prisma/client";
type UserWithPosts = User & {
posts: Post[];
};
const fetchUsers = async () => {
const res = await fetch("http://localhost:3000/api/users");
return res.json();
};
export default function App() {
const [users, { mutate, refetch }] =
createResource<UserWithPosts[]>(fetchUsers);
return (
<main>
<h1>SolidJS + Prisma</h1>
<For each={users() ?? []}>
{(user) => (
<div>
<h3>{user.name}</h3>
<For each={user.posts}>{(post) => <p>{post.title}</p>}</For>
</div>
)}
</For>
</main>
);
}
<For>
loops through an array reactively. Think of it like .map()
in React. Learn more
Step 6: Add Loading and Error States
Use SolidJS's <Show>
component to handle loading and error conditions:
import "./app.css";
import { createResource, For, Show } from "solid-js";
import { User, Post } from "@prisma/client";
type UserWithPosts = User & {
posts: Post[];
};
const fetchUsers = async () => {
const res = await fetch("http://localhost:3000/api/users");
return res.json();
};
export default function App() {
const [users, { mutate, refetch }] =
createResource<UserWithPosts[]>(fetchUsers);
return (
<main>
<h1>SolidJS + Prisma</h1>
<Show when={!users.loading} fallback={<p>Loading...</p>}>
<Show when={!users.error} fallback={<p>Error loading data</p>}>
<For each={users()}>
{(user) => (
<div>
<h3>{user.name}</h3>
<For each={user.posts}>{(post) => <p>{post.title}</p>}</For>
</div>
)}
</For>
</Show>
</Show>
</main>
);
}
<Show>
conditionally renders content. It's similar to an if
statement. Learn more
Next Steps
Now that you have a working SolidStart 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, validation, and optimistic updates
More Info
Stay connected with Prisma
Continue your Prisma journey by connecting with our active community. Stay informed, get involved, and collaborate with other developers:
- Follow us on X for announcements, live events and useful tips.
- Join our Discord to ask questions, talk to the community, and get active support through conversations.
- Subscribe on YouTube for tutorials, demos, and streams.
- Engage on GitHub by starring the repository, reporting issues, or contributing to an issue.