Rendering & DataPro· 50 min read

Connecting a Real Database

Swap the pretend in-memory data for a real database — using Prisma to define a schema and query it straight from a Server Component.

What you will learn

  • Explain what an ORM like Prisma does
  • Define a model in the Prisma schema
  • Query the database directly inside a Server Component

From pretend data to a real database

So far our examples held posts in a plain JavaScript array. That data vanishes when the server restarts and cannot be shared between users. Real apps store data in a database — a program built to save, find and update large amounts of data safely and permanently. A very common choice is PostgreSQL (Postgres), a free, powerful relational database.

What an ORM (Prisma) does for you

Talking to a database normally means writing SQL (Structured Query Language, the language databases speak). An ORM (Object-Relational Mapper) lets you skip raw SQL and work with normal JavaScript objects and methods instead — it translates your JavaScript calls into SQL for you. Prisma is the most popular ORM in the Next.js world.

Without an ORMWith Prisma (an ORM)
Write raw SQL strings by handCall methods like prisma.post.findMany()
Easy to make typos in SQLAutocomplete and type-checking help you
You map rows to objects yourselfYou get JavaScript objects back directly

Step 1 — describe your data in the schema

Prisma keeps one file, schema.prisma, that describes your tables as models. A model is a blueprint for one kind of record — here, a blog Post with an id, a title and a body.

A Prisma schema describing a Post table
// prisma/schema.prisma
datasource db {
  provider = "postgresql"
  url      = env("DATABASE_URL")
}

generator client {
  provider = "prisma-client-js"
}

model Post {
  id    Int    @id @default(autoincrement())
  title String
  body  String
}

Note: Output (after running the setup command): The Post model becomes a real "Post" table in your Postgres database, with an auto-incrementing id, a title column and a body column. Prisma also builds a typed client so your editor knows about Post.

Step 2 — create the table and the client

Two terminal commands turn that schema into a real table and into JavaScript you can call. migrate creates/updates the database table to match your schema; generate builds the typed Prisma client your code imports.

Terminal: build the database table and the Prisma client
# create the table from the schema
npx prisma migrate dev --name init

# (re)build the typed client your code imports
npx prisma generate

Note: Output: Applying migration "init" Your database is now in sync with your schema. ✔ Generated Prisma Client The Post table now exists in Postgres, and "@prisma/client" is ready to import in your code.

Step 3 — query the database in a Server Component

This is where Next.js shines. Because Server Components run on the server, you can talk to the database directly inside one — no API route in the middle. The component is async, so you await the query.

A Server Component reads posts straight from the database with Prisma
// app/blog/page.js  (a Server Component)
import { PrismaClient } from '@prisma/client';
const prisma = new PrismaClient();

export default async function BlogPage() {
  const posts = await prisma.post.findMany();   // SELECT * FROM Post
  return (
    <ul>
      {posts.map((p) => (
        <li key={p.id}>{p.title}</li>
      ))}
    </ul>
  );
}

Note: Output (assuming two posts are stored): Hello Next.js Why I love React No API route, no fetch — the page queried the database directly on the server. prisma.post.findMany() ran the SQL, and the titles are in the HTML before it reaches the browser.

The full path of one request, step by step

Here is exactly what happens when a visitor opens /blog with this setup:

  1. The visitor opens /blog. The browser asks your Next.js server for the page.
  2. On the server, the async BlogPage component runs. It calls prisma.post.findMany().
  3. Prisma turns that JavaScript call into the SQL SELECT * FROM "Post" and sends it to Postgres.
  4. Postgres returns the rows. Prisma hands them back to you as a plain array of JavaScript objects.
  5. The component builds the <ul> of titles — the page is rendered with the real data already inside it.
  6. The finished HTML is sent to the browser. The visitor (and search engines) see the real, stored posts immediately.

Inserting and updating data

The same prisma object creates and changes records. You would call these inside a Server Action (after a form submit), then revalidate so the list refreshes.

Creating a new row is one method call
await prisma.post.create({
  data: { title: 'New post', body: 'Hello world' },
});

Note: Output (behaviour): A new row is inserted into the Post table with the given title and body and a fresh auto-incremented id. Pair this with revalidatePath("/blog") in a Server Action and the new post appears on the list immediately.

Tip: Keep your database connection string out of your code. Put it in a .env file as DATABASE_URL and Prisma reads it automatically — the next lesson on environment variables covers exactly why secrets belong there.

Watch out: Never create a PrismaClient inside a Client Component or ship it to the browser — it holds your database credentials. Database work belongs in Server Components, Route Handlers and Server Actions, which never leave the server.

Q. In the Next.js App Router, where can you safely run a Prisma database query like prisma.post.findMany()?

Answer: Database queries (and the credentials they need) must stay on the server. Server Components, Route Handlers and Server Actions all run on the server, so they can query Prisma directly; Client Components cannot.

✍️ Practice

  1. Add an author field (a String) to the Post model and run prisma migrate dev again.
  2. Query and display posts from the database in a Server Component, showing the title and author.

🏠 Homework

  1. Replace the in-memory posts array in your blog project with a real Prisma + Postgres model, and read the posts directly in the blog list Server Component.
Want to learn this with a mentor?

CodingClave runs guided, project-based training (28-day, 45-day & 6-month batches).

Explore Training →