Skip to main content

How to use Prisma ORM with TanStack Start

10 min

Introduction

Prisma ORM simplifies database interactions, and TanStack Start offers a robust framework for building modern React applications. Together with Prisma Postgres, they provide a seamless full-stack development experience with type-safe queries and efficient data management.

This guide will walk you through integrating Prisma ORM with a Prisma Postgres database in a TanStack Start project from scratch.

Prerequisites

Before starting this guide, ensure you have:

  • Node.js 18+ installed
  • A Prisma Postgres database (or any PostgreSQL database)

Step 1: Initialize Your TanStack Start Project

To begin, create a new TanStack Start project. In the directory where you'd like to create your project, run the following commands:

mkdir prisma-tanstack-start-demo
cd prisma-tanstack-start-demo
npm init -y

This will create a new folder called prisma-tanstack-start-demo, navigate into it, and initialize a new Node.js project.

Open the directory in your IDE and create a tsconfig.json file with the following configuration:

tsconfig.json
{
"compilerOptions": {
"jsx": "react-jsx",
"moduleResolution": "Bundler",
"module": "ESNext",
"target": "ES2022",
"skipLibCheck": true,
"strictNullChecks": true
}
}

We also need a .gitignore file, so let's set that up now:

.gitignore
node_modules
.env

Next, install TanStack Router and Vinxi, as TanStack Start currently requires them:

npm install @tanstack/react-start @tanstack/react-router vinxi

We also need React, the Vite React plugin, and TypeScript:

npm install react react-dom
npm install --save-dev @vitejs/plugin-react vite-tsconfig-paths
npm install --save-dev typescript @types/react @types/react-dom

Update your package.json to use Vinxi's CLI. Add "type": "module" and modify the scripts to use Vinxi's CLI:

package.json
{
"type": "module",
"scripts": {
"dev": "vinxi dev",
"build": "vinxi build",
"start": "vinxi start"
}
}

Then, create and configure TanStack Start's app.config.ts file:

app.config.ts
import { defineConfig } from '@tanstack/react-start/config'
import tsConfigPaths from 'vite-tsconfig-paths'

export default defineConfig({
vite: {
plugins: [
tsConfigPaths({
projects: ['./tsconfig.json'],
}),
],
},
})

For TanStack Start to function, we need four files in ~/app/:

  • router.tsx (The router configuration)
  • ssr.tsx (The server entry point)
  • client.tsx (The client entry point)
  • routes/__root.tsx (The root of the app)

router.tsx configures the application's main router with route definitions and settings:

app/router.tsx
import { createRouter as createTanStackRouter } from '@tanstack/react-router'
import { routeTree } from './routeTree.gen'

export function createRouter() {
const router = createTanStackRouter({
routeTree,
scrollRestoration: true,
})

return router
}

declare module '@tanstack/react-router' {
interface Register {
router: ReturnType<typeof createRouter>
}
}
note

You should be seeing an error about routeTree.gen.ts not existing. This is expected. It will be generated when you run TanStack Start for the first time.

ssr.tsx allows us to know what routes and loaders we need to execute when the user hits a given route:

app/ssr.tsx
import {
createStartHandler,
defaultStreamHandler,
} from '@tanstack/react-start/server'
import { getRouterManifest } from '@tanstack/react-start/router-manifest'

import { createRouter } from './router'

export default createStartHandler({
createRouter,
getRouterManifest,
})(defaultStreamHandler)

client.tsx initializes the client-side logic to handle routes in the browser:

app/client.tsx
import { hydrateRoot } from "react-dom/client";
import { StartClient } from "@tanstack/react-start/client";
import { createRouter } from "./router";

const router = createRouter();

hydrateRoot(document, <StartClient router={router} />);

routes/__root.tsx defines the root route and global HTML layout for the entire application:

app/routes/__root.tsx
import type { ReactNode } from "react";
import {
Outlet,
createRootRoute,
HeadContent,
Scripts,
} from "@tanstack/react-router";

export const Route = createRootRoute({
head: () => ({
meta: [
{
charSet: "utf-8",
},
{
name: "viewport",
content: "width=device-width, initial-scale=1",
},
{
title: "Prisma TanStack Start Demo",
},
],
}),
component: RootComponent,
});

function RootComponent() {
return (
<RootDocument>
<Outlet />
</RootDocument>
);
}

function RootDocument({ children }: Readonly<{ children: ReactNode }>) {
return (
<html>
<head>
<HeadContent />
</head>
<body>
{children}
<Scripts />
</body>
</html>
);
}

Create one more file called index.tsx in app/routes/:

app/routes/index.tsx
import { createFileRoute } from "@tanstack/react-router";

export const Route = createFileRoute("/")({
component: Home,
});

function Home() {
return (
<div>
<h1>Posts</h1>
</div>
);
}

Now, run:

npm run dev

This will generate the routeTree.gen.ts file and resolve any routing errors.

Your file tree should look like this:

.
├── app/
│ ├── routes/
│ │ ├── __root.tsx
│ │ └── index.tsx
│ ├── client.tsx
│ ├── router.tsx
│ ├── routeTree.gen.ts
│ └── ssr.tsx
├── .gitignore
├── app.config.ts
├── package-lock.json
├── package.json
└── tsconfig.json

Step 2: Install and Configure Prisma ORM

Next, we need to install and set up Prisma ORM in our project. Let's start by installing the Prisma CLI.

2.1 Install Prisma ORM and Define Your Model

To start, install the necessary dependencies. At the root of your project, run:

npm install prisma --save-dev

The Prisma CLI is now installed.

Now, run the following command and follow the prompts to set up Prisma:

npx prisma init --db --output ../app/generated/prisma

This command does the following:

  • Creates a prisma directory with a schema.prisma file.
  • Creates a Prisma Postgres database.
  • Creates a .env file containing the DATABASE_URL at the project root.
  • Outputs the generated Prisma Client into the app/generated/prisma directory.

In schema.prisma, create a model for our Posts:

prisma/schema.prisma
model Post {
id Int @id @default(autoincrement())
title String
content String?
}

To migrate your database, run:

npx prisma migrate dev --name init

This does three things:

  • Creates a new SQL migration file in the prisma/migrations directory.
  • Executes the SQL migration file against the database.
  • Runs prisma generate under the hood, which installs the @prisma/client package and generates a tailored Prisma Client API based on your models.

To view your database, run:

npx prisma studio

Select the Post table and add a record.

info

Instead of using Prisma Studio, you can seed your database with data using the following command. See Prisma Seed for more information.

We can't see the post in our app yet, so let's fix that.

2.2 Fetch and Display Data in index.tsx

Let's set up index.tsx to fetch the post we added to the database. First, import the necessary modules:

app/routes/index.tsx
import { PrismaClient } from "@prisma/client";
import { createServerFn } from "@tanstack/react-start";

Create an instance of the Prisma Client:

app/routes/index.tsx
const prisma = new PrismaClient();

Create a server function using TanStack Start's createServerFn to fetch the posts from the database using .findMany():

app/routes/index.tsx
const getPosts = createServerFn({ method: "GET" }).handler(async () => {
return prisma.post.findMany();
});

TanStack Start allows functions to run on load with loader functions in the createFileRoute function. Fetch the posts on load with this code:

app/routes/index.tsx
export const Route = createFileRoute("/")({
component: Home,
loader: () => {
return getPosts();
},
});

Store the response from the loader in the main component using Route.useLoaderData():

app/routes/index.tsx
function Home() {
const posts = Route.useLoaderData();

return (
<div>
<h1>Posts</h1>
</div>
);
}

Map over the posts and display them in a list:

app/routes/index.tsx
function Home() {
const posts = Route.useLoaderData();

return (
<div>
<h1>Posts</h1>
<ul>
{posts.map((post) => (
<li key={post.id}>
<h3>{post.title}</h3>
<p>{post.content}</p>
</li>
))}
</ul>
</div>
);
}

This setup will display the posts on your page, fetched directly from your database.

Next Steps

You've successfully integrated Prisma ORM with TanStack Start, creating a seamless full-stack application. Here are a few suggestions for what you can do next:

  • Expand your Prisma models to handle more complex data relationships.
  • Implement additional CRUD operations to enhance your application's functionality.
  • Explore more features of Prisma and TanStack Start to deepen your understanding.
  • Check out Prisma Postgres to see how you can scale your application.

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:

We genuinely value your involvement and look forward to having you as part of our community!