The easiest way to work with a database in Next.js

Build high-performance and type-safe Next.js apps with Prisma's developer-friendly database tools: The world's most popular TypeScript ORM and the first serverless database without cold starts.

Why Next.js and Prisma

Built for high-performance web apps

Built on unikernels, Prisma Postgres runs on bare metal servers for peak performance and infinite scalability.

Serverless, without cold starts

The first serverless database with pay-as-you-go pricing, no infrastructure management, and zero cold starts.

Flexible data fetching & rendering

Display your data using client-side rendering, server-side rendering and static site generation.

Built-in global caching

Add a cache strategy to any database query and its results will be cached close to your users for peak performance and UX.

End-to-end type safety

Pairing Prisma with Next.js ensures your app is coherently typed, from the database to your React components.

Helpful communities

Both Next.js and Prisma have vibrant communities where you find support, fun events and amazing developers.

How Prisma and Next.js fit together

Prisma's database tools are the perfect fit for building Next.js applications. They serve as the data access layer for Server Components (both static and dynamic), Server Actions, Route Handlers, and standalone services.

Static Site Generation with Prisma

Next.js 13+ introduced a fundamental shift in how we handle data fetching. Server Components, which are the default in the App Router, allow you to fetch data directly in your components without extra wrappers or special functions. This means you can use Prisma directly in your components and automatically get static generation when possible.

Here's how to implement a blog page that's statically generated at build time. The data fetching happens server-side, and the HTML is generated once during build.

// app/blog/[slug]/page.tsx

import { prisma } from '@/lib/prisma'

export async function generateStaticParams() {
  const posts = await prisma.post.findMany()
  return posts.map((post) => ({ slug: post.slug }))
}

export default async function Page({ params }: { params: Promise<{ slug: string }> }) {
  const { slug } = await params
  const post = await prisma.post.findUnique({
    where: { slug },
  })
  return (
    <div>
      <h1 className="text-4xl sm:text-5xl md:text-6xl stretch-display mb-0 text-center mt-0 font-sans-display text-foreground-neutral max-w-224 mx-auto">{post?.title || 'Post not found'}</h1>
      <p>{post?.content || 'No content available'}</p>
    </div>
  )
}

Dynamic Server-Side Data Fetching with Prisma

For dynamic data that needs to be fresh on every request, like a user's dashboard or authenticated content, Server Components can be used. They automatically execute on the server for each request, making them perfect for displaying real-time or user-specific data. The following example shows how to implement a dashboard that displays user-specific content.

// app/dashboard/page.tsx

import { auth } from '@/lib/auth'
import { prisma } from '@/lib/prisma'

export default async function DashboardPage() {
  const session = await auth()

  if (!session) {
    redirect('/login')
  }

  const posts = await prisma.post.findMany({
    where: { authorId: session.user.id }
  })

  return (
    <ul>
      {posts.map(post => (
        <li key={post.id}>{post.title}</li>
      ))}
    </ul>
  )
}

Server Actions with Prisma

Server Actions can be used in place of API routes for many cases. They allow you to define server-side functions that can be called directly from your components, making them perfect for database mutations. They're also progressive enhancement-friendly, working even without JavaScript enabled.

You can then use the createPost server action in your component:

// app/actions.ts
'use server'

import { prisma } from '@/lib/prisma'
import { revalidatePath } from 'next/cache'

export async function createPost(formData: FormData) {
  const title = formData.get('title') as string
  const content = formData.get('content') as string

  await prisma.post.create({ data: { title, content } })
  revalidatePath('/blog')
}

API Routes with Route Handlers

While Server Actions cover many use cases, sometimes you still need traditional API endpoints, like for webhook handlers or public APIs. Next.js 13+ introduces Route Handlers as a replacement for API routes. These handlers are more powerful and flexible than the old API routes, supporting modern Web API standards.

// app/api/posts/route.ts

import { prisma } from '@/lib/prisma'
import { NextResponse } from 'next/server'

export async function GET() {
  const posts = await prisma.post.findMany()
  return NextResponse.json(posts)
}

export async function POST(request: Request) {
  const json = await request.json()
  const post = await prisma.post.create({ data: json })
  return NextResponse.json(post)
}

Client Components with Server Data

Sometimes you need to combine server-side data fetching with client-side interactivity. Next.js makes this easy by allowing you to pass server-fetched data to Client Components. This pattern is perfect for cases where you want the initial data to be server-rendered but need client-side interactivity after the initial load.

// app/components/PostList.tsx
'use client'

import { useState } from 'react'
import { Post } from '../generated/client'

export default function PostList({ initialPosts }: { initialPosts: Post[] }) {
  const [posts, setPosts] = useState(initialPosts)
  return (
    <ul>
      {posts.map(post => (
        <li key={post.id}>{post.title}</li>
      ))}
    </ul>
  )
}

// app/blog/page.tsx
import { prisma } from '@/lib/prisma'
import PostList from '../components/PostList'

export default async function BlogPage() {
  const posts = await prisma.post.findMany()
  return <PostList initialPosts={posts} />
}

Next.js and Prisma is the ultimate combo if you need a database in React apps!

Guillermo Rauch
Guillermo Rauch
CEO & Founder
Vercel

Featured Prisma & Next.js community examples

Modern Saas Starter Kit: next-forge

A starter template for modern SaaS apps! next-forge comes with Next.js 15, auth, DB & ORM, payments, docs, blog, o11y, analytics, emails, and a lot more, to save you the initial boilerplate for your next Next.js SaaS app.

Prisma in Next.js - My fav Way to Work with Databases

Learn best practices for using Prisma with Next.js App Router! Explore server components, server actions, and edge middleware, plus efficient querying, handling migrations, and deploying to Vercel.

t3 Stack

t3 is a web development stack focused on simplicity, modularity, and full-stack type safety. It includes Next.js, tRPC, Tailwind, TypeScript, Prisma and NextAuth.

Blitz.js

Blitz.js is an application framework built on top of Next.js and Prisma. It brings back the simplicity and conventions of server-rendered frameworks like Ruby on Rails while preserving everything developers love about React.

Fullstack Form Builder

This comprehensive 4-hour tutorial teaches you how to build a fullstack form application with drag & drop functionality, layout fields (titles, subtitles, paragraphs), and field types (text, number, dropdowns, dates, checkbox, text areas).