This article is published in English.
Next.js, Tailwind, and Prisma with Docker Postgres
Step-by-step: create a Next.js TypeScript app, run Postgres in Docker, configure Prisma migrate and seed, and query users from a server component.
Prerequisites
Install these tools before following the steps:
- Docker (for a local Postgres container)
- Node.js (v16+ recommended)
- npm (ships with Node)
1) Create a Next.js project
Use the official initializer and answer the prompts. Prefer App Router and TypeScript for this walkthrough.
npx create-next-app@latest notes-taking
# choose your options in the interactive prompt (App Router, TypeScript recommended)
cd note-taking
To force TypeScript from the first command:
npx create-next-app@latest note-taking — ts
2) Add Tailwind CSS (Already Come with NextJs)
Recent create-next-app templates already wire Tailwind when you enable it in the interactive options, so no separate Tailwind install is required for a fresh project that selected it.
3) Run Postgres using Docker (locally)
Start Postgres in a container:
docker run — name notes-postgres -e POSTGRES_PASSWORD=password -e POSTGRES_DB=notes_app -p 5432:5432 -d postgres:latest
Flag meanings:
- docker run — create and start a container
- --name notes-postgres — stable name for later commands
- -e POSTGRES_PASSWORD=... / -e POSTGRES_DB=... — bootstrap credentials and database
- -p 5432:5432 — publish the port to the host
- -d postgres:latest — detach and use the Postgres image
Confirm it is running:
docker ps
Filter by image:
docker ps — filter “ancestor=postgres”
List every container, including stopped ones:
docker ps -a
Filter by container name:
docker ps — filter “name=notes-postgres”
4) Install Prisma and related packages
From the Next.js project root:
npm install prisma tsx — save-dev
npm install @prisma/extension-accelerate @prisma/client
Initialize Prisma and emit the client under the app folder so App Router imports stay local:
npx prisma init — db — output ../app/generated/prisma
That creates a prisma/ directory with schema.prisma, a .env containing DATABASE_URL, and (with --output) a generated client under app/generated/prisma.
Prefer the default client location instead? Initialize without a custom output:
npx prisma init — db and remove — output.
5) Configure .env (DATABASE_URL)
Point DATABASE_URL at the Docker Postgres instance:
DATABASE_URL=”postgresql://postgres:password@localhost:5432/notes_app?schema=public”
Swap password and database name if you chose different values.
6) Edit prisma/schema.prisma
Use a User/Post model pair that matches the seed script later:
generator client {
provider = "prisma-client-js"
output = "../app/generated/prisma"
}
datasource db {
provider = "postgresql"
url = env("DATABASE_URL")
}
model User {
id Int @id @default(autoincrement())
name String
email String @unique
posts Post[]
}
model Post {
id Int @id @default(autoincrement())
title String
content String?
published Boolean @default(false)
authorId Int
author User @relation(fields: [authorId], references: [id])
}
Save the file when the models look right.
7) Run migration (create tables)
Apply the first migration to create tables:
npx prisma migrate dev — name init
Prisma writes SQL under prisma/migrations for that change.
8) Seed the database
Seeding inserts sample rows so Prisma Studio and the app have data immediately.
Create prisma/seed.ts (adjust the import if your client output path differs):
// prisma/seed.ts
import { PrismaClient, Prisma } from "../app/generated/prisma";
const prisma = new PrismaClient();
const userData: Prisma.UserCreateInput[] = [
{
name: "Alice",
email: "alice@prisma.io",
posts: {
create: [
{
title: "Join the Prisma Discord",
content: "https://pris.ly/discord",
published: true,
},
{
title: "Prisma on YouTube",
content: "https://pris.ly/youtube",
},
],
},
},
{
name: "Bob",
email: "bob@prisma.io",
posts: {
create: [
{
title: "Follow Prisma on Twitter",
content: "https://www.twitter.com/prisma",
published: true,
},
],
},
},
];
export async function main() {
for (const u of userData) {
await prisma.user.create({ data: u });
}
}
main();ty
Register the seed script in package.json:
"prisma": {
"seed": "tsx prisma/seed.ts"
}
Run it:
npx prisma db seed
That inserts Alice and Bob plus their posts.
9) Open Prisma Studio
Inspect and edit rows visually:
npx prisma studio
A browser UI lists models and records.
10) Create a Prisma client wrapper (lib/prisma.ts)
Avoid spawning many PrismaClient instances in development by using a global singleton and the accelerate extension. Create lib/prisma.ts:
// lib/prisma.ts
import { PrismaClient } from "../app/generated/prisma"; // adjust path if needed
import { withAccelerate } from "@prisma/extension-accelerate";
declare global {
// allow global prisma across module reloads in dev
// eslint-disable-next-line no-var
var prisma: PrismaClient | undefined;
}
const prisma =
global.prisma ?? new PrismaClient().$extends(withAccelerate());
if (process.env.NODE_ENV !== "production") global.prisma = prisma;
export default prisma;
Point the import at your generated client path, or use @prisma/client if you skipped --output.
11) Test DB connection from Next.js (server component)
Example app/page.tsx that loads users on the server:
import prisma from '@/lib/db'
export default async function Home() {
const users = await prisma.user.findMany();
return (
<div className="min-h-screen bg-gray-50 flex flex-col items-center justify-center -mt-16">
<h1 className="text-4xl font-bold mb-8 font-[family-name:var(--font-geist-sans)] text-[#333333]">
Superblog
</h1>
<ol className="list-decimal list-inside font-[family-name:var(--font-geist-sans)]">
{users.map((user) => (
<li key={user.id} className="mb-2">
{user.name}
</li>
))}
</ol>
</div>
);
}
Start the Next.js dev server:
npm run dev
Open http://localhost:3000 and confirm the seeded users render.
Full command checklist
create project
npx create-next-app@latest my-app
cd my-app
postgres docker
docker run — name notes-postgres -e POSTGRES_PASSWORD=password -e POSTGRES_DB=notes_app -p 5432:5432 -d postgres:latest
docker ps
docker exec -it notes-postgres psql -U postgres
prisma
npm install prisma tsx — save-dev
npm install @prisma/extension-accelerate @prisma/client
npx prisma init — db — output ../app/generated/prisma
edit prisma/schema.prisma
npx prisma migrate dev — name init
create prisma/seed.ts
add prisma.seed entry to package.json
npx prisma db seed
npx prisma studio
npm run dev
Troubleshooting & tips
- Cannot connect to Postgres: confirm the container with
docker ps, then verifyDATABASE_URLhost and port. Trypsqlfrom the host or another client against the same URL. - Migration failures: read the SQL Prisma generated under
prisma/migrationsand ensure the database name matches.env. - Wrong client import: regenerate after changing
output, or switch imports to@prisma/clientif you use the default location. - Empty UI: re-run the seed and confirm Prisma Studio shows Alice/Bob before debugging the page component.