Building a users table

Building a users table

Use Prisma to fetch data directly inside of a Server Component.

Video resources

Let's turn a static mockup into a React Server Component that fetches data from a database using Prisma and Next.js 13.

Here's what we're starting with:

// app/page.tsx
let users = [
  {
    name: "Kenneth Bell",
    email: "kenneth.bell@example.com",
  },
  {
    name: "Mattie Conway",
    email: "mattie.conway@example.com",
  },
  {
    name: "Lola B. Graham",
    email: "lolab.graham@example.com",
  },
  {
    name: "Cara Fuentes",
    email: "cara.fuentes@example.com",
  },
];

export default function Users() {
  return (
    <ul>
      {users.map((user) => (
        <li key={user.email}>{user.email}</li>
      ))}
    </ul>
  );
}

In Next.js 13, all pages are React Server Components by default. Server Components are a new React primitive that execute directly on the server – and only on the server – at the time of a request.

This is distinct from the concept of server-side rendering (SSR) which applies to the typical React components you're probably familiar with. These Client Components are often pre-rendered on the server using SSR (for example when using a framework like Next.js), but they eventually hydrate and execute on the client, adding interactivity to your page via client-side features like useState and useEffect.

Server Components, in contrast, never execute on the client. They only execute on the server at the time of the request, and then send their output (called the RSC Payload) up to the browser to be rendered by your app.

Because Server Components only ever run on the server, we can use server-side-only libraries like Prisma directly inside the body of our components.

Let's replace our static list of users with a dynamic Prisma query1:

// app/page.tsx
import { prisma } from "@/lib/prisma";

export default async function Page() {
  const users = await prisma.user.findMany();

  return (
    <ul>
      {users.map((user) => (
        <li key={user.id}>{user.email}</li>
      ))}
    </ul>
  );
}

The prisma.user.findMany() function returns all the users from our database. It returns a promise, so notice that we also turned our Server Component into an asynchronous function via the async keyword.

This is the first time we've been able to do anything like this in React, and it simply feels magical.

Let's discuss the three most exciting concepts from our first Server Component.

Async/await

First, Server Components can be async functions that use the await keyword. This allows them to directly use libraries that use promises for async work (like Prisma), without any additional wrapping code.

It's worth noting that while our Server Component is awaiting a response from Prisma, our page is blocked from rendering. This means that the UI will only render once the users have been fetched from the database, which frees us from having to worry about loading states inside of our component.

This approach to data fetching is how traditional server-side applications work, and is fast enough for many applications. In a future lesson you'll learn how Server Components can render loading UI to provide feedback while their data is being fetched.

Server-side code execution

Second, Server Components only ever run on the server. In our component, we're importing and using Prisma. Prisma is a Node.js package that would fail if we attempted to run it in the browser, but because Server Components never execute in the browser, we can safely use it directly inside the body of our component.

Because Server Components are guaranteed to only ever run on the server, they allow us to write React components that directly access secure data from databases and services that would otherwise be tucked away behind firewalls and private API keys.

Once a Server Component runs, its output is sent to the browser in a format called an RSC payload. That output is then rendered by your app. The payload only contains the output, so the browser never needs to execute or even see the code inside your Server Component.

We'll dive deeper into this rendering process in a future lesson.

Type safety

Finally, Server Components fully support TypeScript. Since Server Components execute in a single environment, they're able to automatically take advantage of any TypeScript features that your code (or any of your code's dependencies) may be using.

This is in contrast to Client Components. When fetching data over the network with a Client Component, you must take extra steps to type the result of your request – even if you're using a tool like Prisma on the backend – to get type saftey while rendering your data.

With React Server Components, the data fetching happens in the same context as the render, so there's no extra setup needed for TypeScript to analyze the component.

Why this matters

Server Components give React a seat at that table alongside traditional server-rendered architectures. Developers now can access databases, use battle-tested ORMs, avoid remote API servers, and easily use TypeScript thanks to the Server Component architecture.

Links

Footnotes

  1. The code inside the src/lib/prisma.ts module comes from the following Prisma guide: Best practice for instantiating PrismaClient with Next.js application. It prevents new database connections from being created every time a file is saved due to hot module reloading.

Buy Data fetching with React Server Components

Buy the course

$149one-time payment

Get everything in Data fetching with React Server Components.

  • 1+ hour of video
  • 9 lessons
  • Private Discord
  • Summaries with code
  • Unlimited access to course materials

Lifetime membership

$199
access all coursesone-time payment

Lifetime access to all current and future premium Build UI courses, forever.

  • Access to all five Build UI courses
  • New videos added regularly
  • Refactoring videos on React
  • Private Discord
  • Summaries with code
  • Full access to all future Build UI courses

What's included

Stream or download every video

Watch every lesson directly on Build UI, or download them to watch offline at any time.

Live code demos

Access to a live demo of each lesson that runs directly in your browser.

Private Discord

Chat with Sam, Ryan and other Build UI members about the lessons – or anything else you're working on – in our private server.

Video summaries with code snippets

Quickly reference a lesson's material with text summaries and copyable code snippets.

Source code

Each lesson comes with a GitHub repo that includes a diff of the source code.

Invoices and receipts

Get reimbursed from your employer for becoming a better coder!