Back to Prisma

SolidStart

apps/docs/content/docs.v6/guides/solid-start.mdx

latest11.2 KB
Original Source

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

1. Set up your project

Begin by creating a new SolidStart app. In your terminal, run:

npm
npm init solid@latest

Use the following options when prompted:

:::info

  • Project name: my-solid-prisma-app
  • Is this a SolidStart project: Yes
  • Template: bare
  • Use TypeScript: Yes

:::

Next, navigate into your new project, install dependencies, and start the development server:

npm
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.

Clean up the default UI by editing the app.tsx file and replacing its content with the following code:

typescript
import "./app.css";

export default function App() {
  return (
    <main>
      <h1>SolidStart + Prisma</h1>
    </main>
  );
}

2. Install and Configure Prisma

2.1. Install dependencies

To get started with Prisma, you'll need to install a few dependencies:

npm
npm install prisma tsx @types/pg --save-dev
npm
npm install @prisma/client @prisma/adapter-pg dotenv pg

:::info

If 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:

npm
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 SolidStart Project" :::

This will create:

  • A prisma directory with a schema.prisma file.
  • A prisma.config.ts file for configuring Prisma
  • A Prisma Postgres database.
  • A .env file containing the DATABASE_URL at the project root.
  • An output directory for the generated Prisma Client as src/generated/prisma.

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
generator client {
  provider = "prisma-client"
  output   = "../src/generated/prisma"
}

datasource db {
  provider = "postgresql"
}

model User { // [!code ++]
  id    Int     @id @default(autoincrement()) // [!code ++]
  email String  @unique // [!code ++]
  name  String? // [!code ++]
  posts Post[] // [!code ++]
} // [!code ++]

model Post { // [!code ++]
  id        Int     @id @default(autoincrement()) // [!code ++]
  title     String // [!code ++]
  content   String? // [!code ++]
  published Boolean @default(false) // [!code ++]
  authorId  Int // [!code ++]
  author    User    @relation(fields: [authorId], references: [id]) // [!code ++]
} // [!code ++]

This creates two models: User and Post, with a one-to-many relationship between them.

2.3 Add dotenv to prisma.config.ts

To get access to the variables in the .env file, they can either be loaded by your runtime, or by using dotenv. Include an import for dotenv at the top of the prisma.config.ts

ts
import "dotenv/config"; // [!code ++]
import { defineConfig, env } from "prisma/config";
export default defineConfig({
  schema: "prisma/schema.prisma",
  migrations: {
    path: "prisma/migrations",
  },
  datasource: {
    url: env("DATABASE_URL"),
  },
});

2.4. Configure the Prisma Client generator

Now, run the following command to create the database tables and generate the Prisma Client:

npm
npx prisma migrate dev --name init
npm
npx prisma generate

2.5. 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
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: "[email protected]",
    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: "[email protected]",
    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 prisma.config.ts:

ts
import "dotenv/config";
import { defineConfig, env } from "prisma/config";
export default defineConfig({
  schema: "prisma/schema.prisma",
  migrations: {
    path: "prisma/migrations",
    seed: `tsx prisma/seed.ts`, // [!code ++]
  },
  datasource: {
    url: env("DATABASE_URL"),
  },
});

Run the seed script:

npm
npx prisma db seed

And open Prisma Studio to inspect your data:

npm
npx prisma studio

3. Integrate Prisma into SolidStart

3.1. Create a Prisma Client

At the root of your project, create a new lib folder and a prisma.ts file inside it:

bash
mkdir -p lib && touch lib/prisma.ts

Add the following code to create a Prisma Client instance:

typescript
import { PrismaClient } 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,
});

export default prisma;

:::warning We recommend using a connection pooler (like Prisma Accelerate) to manage database connections efficiently.

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. :::

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:

typescript
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" },
  });
}

3.3. Fetch Data in Your Component

In your app.tsx file, use createResource to fetch data from your new API route:

typescript
import "./app.css";
import { createResource } from "solid-js"; // [!code ++]
import { User, Post } from "./generated/prisma/client"; // [!code ++]

type UserWithPosts = User & { // [!code ++]
  posts: Post[]; // [!code ++]
}; // [!code ++]

const fetchUsers = async () => { // [!code ++]
  const res = await fetch("http://localhost:3000/api/users"); // [!code ++]
  return res.json(); // [!code ++]
}; // [!code ++]

export default function App() {
  const [users, { mutate, refetch }] = createResource<UserWithPosts[]>(fetchUsers);

  return (
    <main>
      <h1>SolidStart + Prisma</h1>
    </main>
  );
}

:::info createResource is a SolidJS hook for managing async data. It tracks loading and error states automatically. Learn more. :::

3.4. Display the Data

To show the users and their posts, use SolidJS's <For> component:

typescript
import "./app.css";
import { createResource, For } from "solid-js"; // [!code highlight]
import { User, Post } from "./generated/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() ?? []}> // [!code ++]
        {(user) => ( // [!code ++]
          <div> // [!code ++]
            <h3>{user.name}</h3> // [!code ++]
            <For each={user.posts}>{(post) => <p>{post.title}</p>}</For> // [!code ++]
          </div> // [!code ++]
        )} // [!code ++]
      </For> // [!code ++]
    </main>
  );
}

:::info <For> loops through an array reactively. Think of it like .map() in React. Learn more :::

3.5. Add Loading and Error States

Use SolidJS's <Show> component to handle loading and error conditions:

typescript
import "./app.css";
import { createResource, For, Show } from "solid-js"; // [!code highlight]
import { User, Post } from "./generated/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>}> // [!code ++]
        <Show when={!users.error} fallback={<p>Error loading data</p>}> // [!code ++]
          <For each={users()}>
            {(user) => (
              <div>
                <h3>{user.name}</h3>
                <For each={user.posts}>{(post) => <p>{post.title}</p>}</For>
              </div>
            )}
          </For>
        </Show> // [!code ++]
      </Show> // [!code ++]
    </main>
  );
}

:::info <Show> conditionally renders content. It's similar to an if statement. Learn more :::

You're done! You've just created a SolidStart app connected to a Prisma Postgres database.

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
  • Enable query caching with Prisma Postgres for better performance

More Info