📋 Table of Contents
Was wir bauen
Eine Full-Stack-Aufgabenverwaltungs-App: Next.js 15 App Router, PostgreSQL über Neon (serverlos), Prisma ORM, Serveraktionen (keine separaten API-Routen für Mutationen), Auth.js v5 GitHub OAuth, bereitgestellt auf Vercel.
Projekt-Setup
npx create-next-app@latest taskapp \
--typescript --tailwind --eslint --app --src-dir --import-alias "@/*"
cd taskapp
Datenbank: PostgreSQL mit Neon + Prisma
Erstellen Sie eine kostenlose Datenbank unterneon.tech. Dann:
npm install prisma @prisma/client
npx prisma init
Im.env.local:
DATABASE_URL="postgresql://user:pass@ep-xxx.us-east-2.aws.neon.tech/neondb?sslmode=require"
NEXTAUTH_SECRET="your-random-secret-here"
GITHUB_CLIENT_ID="your-github-oauth-app-id"
GITHUB_CLIENT_SECRET="your-github-oauth-app-secret"
Datenmodelle
// prisma/schema.prisma
model User {
id String @id @default(cuid())
email String @unique
name String?
createdAt DateTime @default(now())
tasks Task[]
}
model Task {
id String @id @default(cuid())
title String
status TaskStatus @default(PENDING)
priority Priority @default(MEDIUM)
userId String
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
@@index([userId])
}
enum TaskStatus { PENDING IN_PROGRESS COMPLETED CANCELLED }
enum Priority { LOW MEDIUM HIGH URGENT }
npx prisma migrate dev --name init
npx prisma generate
// src/lib/db.ts
import { PrismaClient } from '@prisma/client';
const globalForPrisma = globalThis as unknown as { prisma: PrismaClient };
export const db = globalForPrisma.prisma ?? new PrismaClient();
if (process.env.NODE_ENV !== 'production') globalForPrisma.prisma = db;
Serverkomponenten und Datenabruf
App Router-Komponenten sind standardmäßig Serverkomponenten – sie werden auf dem Server ausgeführt und können die Datenbank direkt abfragen:
// src/app/dashboard/page.tsx (Server Component)
import { db } from '@/lib/db';
import { auth } from '@/lib/auth';
import { redirect } from 'next/navigation';
export default async function DashboardPage() {
const session = await auth();
if (!session?.user) redirect('/');
const tasks = await db.task.findMany({
where: { userId: session.user.id, status: { not: 'CANCELLED' } },
orderBy: [{ priority: 'desc' }, { createdAt: 'desc' }],
take: 50,
});
return (
<main className="container mx-auto p-6">
<h1>My Tasks</h1>
{tasks.map(task => <TaskCard key={task.id} task={task} />)}
</main>
);
}
Keine API-Route erforderlich. Kein useEffect. Kein Ladestatus-Boilerplate. Die Komponente wird auf einmal abgerufen und gerendert.
Serveraktionen für Mutationen
Serveraktionen ersetzen API-Routen für Formularübermittlungen und -mutationen:
// src/actions/tasks.ts
'use server';
import { db } from '@/lib/db';
import { auth } from '@/lib/auth';
import { revalidatePath } from 'next/cache';
import { z } from 'zod';
const Schema = z.object({
title: z.string().min(1).max(200),
priority: z.enum(['LOW','MEDIUM','HIGH','URGENT']).default('MEDIUM'),
});
export async function createTask(formData: FormData) {
const session = await auth();
if (!session?.user?.id) throw new Error('Unauthorized');
const parsed = Schema.safeParse({
title: formData.get('title'),
priority: formData.get('priority') || 'MEDIUM',
});
if (!parsed.success) return { error: parsed.error.flatten().fieldErrors };
await db.task.create({ data: { ...parsed.data, userId: session.user.id } });
revalidatePath('/dashboard');
return { success: true };
}
DasrevalidatePathDer Aufruf macht den Next.js-Cache für diese Route ungültig und löst ein neues Server-Rendering mit neuen Daten aus.
Authentifizierung mit Auth.js v5
npm install next-auth@beta @auth/prisma-adapter
// src/lib/auth.ts
import NextAuth from 'next-auth';
import GitHub from 'next-auth/providers/github';
import { PrismaAdapter } from '@auth/prisma-adapter';
import { db } from './db';
export const { auth, handlers, signIn, signOut } = NextAuth({
adapter: PrismaAdapter(db),
providers: [GitHub({ clientId: process.env.GITHUB_CLIENT_ID!, clientSecret: process.env.GITHUB_CLIENT_SECRET! })],
session: { strategy: 'database' },
callbacks: { session: ({ session, user }) => ({ ...session, user: { ...session.user, id: user.id } }) }
});
Fügen Sie den Routenhandler hinzu:src/app/api/auth/[...nextauth]/route.ts→ exportierenhandlers as GET, handlers as POST.
Bereitstellung auf Vercel
# Install Vercel CLI and deploy
npm install -g vercel
vercel
# Set environment variables
vercel env add DATABASE_URL
vercel env add NEXTAUTH_SECRET
vercel env add GITHUB_CLIENT_ID
vercel env add GITHUB_CLIENT_SECRET
vercel --prod
Nach der Bereitstellung: Aktualisieren Sie die GitHub-OAuth-Callback-URL aufhttps://your-app.vercel.app/api/auth/callback/github, dann führenpx prisma migrate deployaus .
Produktionscheckliste
- Ratenbegrenzung— Upstash-Ratelimit für Serveraktionen und API-Routen
- Fehlergrenzen–
error.tsxhinzufügen Dateien für elegante Fallbacks - Ladezustände–
loading.tsxhinzufügen für Suspense-Skelette - Eingabevalidierung– Verwenden Sie immer Zod für Serveraktionen
- Verbindungspooling–
?pgbouncer=true&connection_limit=1hinzufügen zur Neon-URL - Sicherheitsheader– über
next.config.tshinzufügen headers()
🔧 Bereit zum Versand?
Next.js 15 + PostgreSQL ist der dominierende Full-Stack-Stack im Jahr 2026. Entdecken Siewarum TypeScript unerlässlich istfür größere Next.js-Apps und MasterAsynchrone/Wartemusterfür Serverkomponenten und Aktionen.
Häufig gestellte Fragen
Was ist Next.js 15?
Neueste Next.js: stabiles Turbopack (5-mal schneller), React 19 erforderlich, asynchrone Anforderungs-APIs, verbesserte Serveraktionen. App Router ist der zukünftige Standard.
App Router oder Pages Router im Jahr 2026?
App Router für alle neuen Projekte. Pages Router funktioniert, erhält aber keine neuen Funktionen.
Welche Datenbank soll mit Next.js verwendet werden?
PostgreSQL über Neon (serverlos) + Prisma oder Drizzle ORM. Supabase, wenn Sie integrierte Authentifizierung und Echtzeit benötigen.
Was sind Serveraktionen?
Asynchrone Serverfunktionen (gekennzeichnet mit „Server verwenden“), die von React aufgerufen werden. Ersetzen Sie API-Routen für Mutationen. Typsicher, unterstützt optimistische Updates.
Wie wird bereitgestellt?
Vercel (keine Konfiguration, erstellt vom Next.js-Team). Selbsthost: nächster Build + nächster Start hinter Nginx oder Docker.
🔗 Share this article
✍️ Leave a Comment