Strona główna / Artykuły

Server Actions w Next.js z Prismą i PostgreSQLiem

Next.js Server Actions komunikuje się bezpośrednio z wspólnym klientem Prisma oraz bazą PostgreSQL, dzięki czemu operacje CRUD nad zadaniami działają bez konieczności użycia tras API ani żadnych żądań fetch po stronie klienta.

Wydawca: REACTAPP.TOP4 min czytania917 słów

Źródła: Next.js Server Actions + Prisma + PostgreSQL: The Integration Pattern You Actually Need

Podręczniki często omawiają Next.js, Prisma i PostgreSQL jako odrębne komponenty do instalacji: tworzenie szkieletu aplikacji, generowanie klienta, skierowanie połączenia do bazy danych oraz wykonywanie migracji. Brakuje jednak wyjaśnienia, jak te trzy warstwy łączą się w jeden wzorzec integracji – oraz dlaczego taki wzorzec eliminuje tak wiele typowych procedur związanych z pełnym stackiem.

Rozdział obowiązków jest jasny. Server Actions przenoszą zadania za granicę serwera. Prisma generuje zapytania bezpieczne pod względem typów. PostgreSQL przechowuje dane. Każda warstwa zajmuje się jedną konkretną funkcją. Razem eliminują one całą środkową warstwę: nie ma specjalnie zaprojektowanych tras API, nie ma ręcznie pisanych pętli fetch, a także nie ma dodatkowych procedur serializacji pomiędzy komponentem React a bazą danych.

Dostateczny jest nawet mały menedżer zadań, aby pokazać ten wzorzec od początku do końca – od schematu aż po działającą interfejs użytkownika – bez konieczności wprowadzania specjalnych obsługowników tras do operacji CRUD.

Dlaczego właśnie ten stack

Akcje serwera, Prisma i PostgreSQL wzmacniają się nawzajem na każdym poziomie aplikacji full-stack w Next.js.

Akcje są wykonywane na serwerze, dzięki czemu można bezpośrednio importować klienta Prisma, nie ujawniając danych dostępu do bazy danych przeglądarce. Prisma zapewnia typizowane interfejsy zapytań, więc wartości zapisywane w PostgreSQL i odczytywane później pozostają spójne w całym grafie TypeScript. PostgreSQL jest niezawodny, powszechnie wspierany i dobrze integruje się z procesem migracji w Prismie.

Korzyścią jest krótka ścieżka od kliknięcia przycisku do zapisania rekordu – zazwyczaj przy mniejszej ilości kodu łączącego w porównaniu z innymi podejściami w ekosystemie Next.js.

Ustawienie projektu

Zacznij od nowej aplikacji Next.js i dodaj Prismę:

npx create-next-app@latest my-app --typescript
cd my-app
npm install prisma @prisma/client
npx prisma init

The prisma init command creates a prisma/ folder with a schema.prisma file and a .env file. Open .env and add your PostgreSQL connection string:
```DATABASE_URL="postgresql://USER:PASSWORD@HOST:5432/mydb"

3. Define Your Schema

Open prisma/schema.prisma and define your data model. We will keep it simple — a Task model:
```generator client {
  provider = "prisma-client-js"
}

datasource db {
  provider = "postgresql"
  url      = env("DATABASE_URL")
}

model Task {
  id        String   @id @default(cuid())
  title     String
  completed Boolean  @default(false)
  createdAt DateTime @default(now())
  updatedAt DateTime @updatedAt
}

Run the migration to create the table:
```npx prisma migrate dev --name init

This creates the table and generates the Prisma Client. You are ready to query.

Wzorzec integracji

To jest istota koncepcji. Server Action importuje klienta Prisma i komunikuje się bezpośrednio z bazą danych – bez ścieżki API, bez wywołania fetch na stronie klienta oraz bez dodatkowej warstwy serializacji pomiędzy interfejsem a przechowywaniem danych. Najpierw należy eksportować wspólną instancję Prisma, która przetrwa aktualizację w trakcie rozwoju:

// lib/prisma.ts
import { PrismaClient } from '@prisma/client';

const globalForPrisma = globalThis as unknown as { prisma: PrismaClient };

export const prisma =
  globalForPrisma.prisma ?? new PrismaClient();

if (process.env.NODE_ENV !== 'production')
  globalForPrisma.prisma = prisma;

Następnie należy zdefiniować moduł Server Actions:

// app/tasks/actions.ts
'use server';
import { revalidatePath } from 'next/cache';
import { prisma } from '@/lib/prisma';

export async function getTasks() {
  return prisma.task.findMany({ orderBy: { createdAt: 'desc' } });
}
5. Wiring It to Your UI

Now use the Server Actions in your page and components:
```// app/tasks/page.tsx
import { getTasks } from './actions';
import { TaskForm } from './TaskForm';
import { TaskList } from './TaskList';

export default async function TasksPage() {
  const tasks = await getTasks();
  return (
    <main>
      <h1>My Tasks</h1>
      <TaskForm />
      <TaskList tasks={tasks} />
    </main>
  );
}
export async function createTask(formData: FormData) {
  const title = formData.get('title') as string;
  if (!title?.trim()) return { error: 'Title is required' };
  await prisma.task.create({ data: { title } });
  revalidatePath('/tasks');
}

export async function toggleTask(id: string, completed: boolean) {
  await prisma.task.update({ where: { id }, data: { completed: !completed } });
  revalidatePath('/tasks');
}

export async function deleteTask(id: string) {
  await prisma.task.delete({ where: { id } });
  revalidatePath('/tasks');
}

Podłączenie do interfejsu

Należy wywoływać te funkcje z strony. Komponent serwera może bezpośrednio używać getTasks() – bez useEffect, bez ręcznego flagi ładowania oraz bez wywołań fetch na stronie klienta:

// app/tasks/page.tsx
import { getTasks } from './actions';
import { TaskForm } from './TaskForm';
import { TaskList } from './TaskList';

export default async function TasksPage() {
  const tasks = await getTasks();
  return (
    <main>
      <h1>My Tasks</h1>
      <TaskForm />
      <TaskList tasks={tasks} />
    </main>
  );
}

Podsumowanie

Działania serwera w połączeniu z Prismą i PostgreSQLiem umożliwiają stworzenie pełnego stacku do obsługi danych przy niemal zerowym nakładzie pracy nad kodem szablonowym. Komponent wywołuje funkcję, która poprzez Prismę zapisuje lub odczytuje dane; PostgreSQL przechowuje te dane, a revalidatePath odświeża interfejs użytkownika — zazwyczaj w kilkudziesięciu liniach kodu, zamiast wymagać osobnej warstwy API.