TanStack Start

Learn how to use Prisma ORM in a TanStack Start app

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

1. Set up your project

To begin, create a new TanStack Start project.

npm create @tanstack/start@latest
  • What would you like to name your project? tanstack-start-prisma
  • Would you like to use Tailwind CSS? No
  • Select Toolchain None
  • Select deployment adapter Nitro
  • What add-ons would you like for your project? Prisma
  • Would you like any examples? No
  • Prisma: Database Provider Prisma PostgresSQL

This will create a new folder called tanstack-start-prisma and create a new Prisma Postgres Database for you. The final database connection string will be printed out.

  Database Connection

    Connection String:

    postgresql://b4889.....

Copy this connection string and set the DATABASE_URL variable in .env.local:

# Database URL for PostgreSQL
DATABASE_URL="postgresql://b4889....."

2. Configure Prisma

2.1. Define your Prisma Schema

In schema.prisma, the model for our todos is defined below the generator and datasource blocks:

prisma/schema.prisma
generator client {
  provider = "prisma-client"
  output   = "../app/generated/prisma"
}

datasource db {
  provider = "postgresql"
}

model Todo {
  id        Int      @id @default(autoincrement())
  title     String
  createdAt DateTime @default(now())
}

This creates a Todo model that will be pushed to the database

2.2. Configure the Prisma Client generator

Now, run the following command to create the database tables:

npm run db:seed -- --name init

2.3. Seed the database

Generate the Prisma Client needed for the project;

npm run db:generate

Then seed the project with the seed.ts file in the prisma/ directory:

npm run db:seed

And open Prisma Studio to inspect your data:

npm run db:studio

3. Integrate Prisma into TanStack Start

3.1 The Prisma Client

Instead of creating a new Prisma Client instance in each file, TanStack Start has a db.ts that creates a single instance that can be shared globally

src/db.ts
import { PrismaClient } from "./generated/prisma/client.js";

import { PrismaPg } from "@prisma/adapter-pg";

const adapter = new PrismaPg({
  connectionString: process.env.DATABASE_URL!,
});

declare global {
  var __prisma: PrismaClient | undefined;
}

export const prisma = globalThis.__prisma || new PrismaClient({ adapter });

if (process.env.NODE_ENV !== "production") {
  globalThis.__prisma = prisma;
}

3.2 Fetch data on load

First, import the necessary modules. Then, create a server function using the createServerFn function. This function will fetch the data from the database using the .findMany() method

src/routes/index.tsx
import { createFileRoute } from "@tanstack/react-router";
import { createServerFn } from "@tanstack/react-start"; 
import { prisma } from '../db'; 

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

const getTodos = createServerFn({ method: "GET" }).handler(async () => { 
  return prisma.todo.findMany(); 
}); 

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

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

app/routes/index.tsx
import { createFileRoute } from '@tanstack/react-router';
import { createServerFn } from '@tanstack/react-start';
import { prisma } from '../db';

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

const getTodos = createServerFn({ method: "GET" }).handler(async () => {
  return prisma.todo.findMany();
});

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

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

app/routes/index.tsx
import { createServerFn } from "@tanstack/react-start";
import { createFileRoute } from "@tanstack/react-router";
import { prisma } from '../db';

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

const getTodos = createServerFn({ method: "GET" }).handler(async () => {
  return prisma.todo.findMany();
});

function Home() {
  const todos = Route.useLoaderData(); 

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

3.3 Display the todos

Next, you'll update the home page to display the data retrieved from your database.

Map over the todos and display them in a list:

app/routes/index.tsx
import { createFileRoute } from '@tanstack/react-router';
import { createServerFn } from '@tanstack/react-start';
import { prisma } from '../db';

export const Route = createFileRoute('/')({
  component: App,
  loader: () => getTodos(),
});

const getTodos = createServerFn({ method: 'GET' }).handler(async () => {
  return prisma.todo.findMany();
});

function App() {
  const todos = Route.useLoaderData();

  return (
    <div>
      <ul>
        {todos.map(todo => (
          <li key={todo.id}>{todo.title}</li>
        ))}
      </ul>
    </div>
  );
}

This setup will display the todos 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

On this page