This content is not yet available in 🇺🇸 English. Showing the 🇹🇷 Türkçe version.
Next.js Server Actions: Form, Mutation ve Güvenli Veri Yazımı
Bu rehberde ne öğreneceksiniz?
Bu yazı bir haber özeti değil; adım adım uygulayabileceğiniz bir öğretici makale (tutorial) formatındadır. Her bölümün sonunda pratik çıkarımlar ve üretim ortamında karşılaşacağınız senaryolar yer alır.
- Server Action ile tip güvenli mutation yazmak
- useActionState / useFormStatus ile form UX kurmak
- CSRF ve yetkilendirme kontrollerini action içine almak
- revalidatePath ve cache invalidation stratejisi seçmek
Ön koşullar
Rehberi verimli takip etmek için aşağıdaki bilgilere aşina olmanız önerilir. Eksik hissettiğiniz konularda ilgili bölümde ek kaynak ipuçları bulacaksınız.
- Server vs Client Component ayrımı
- HTTP POST ve HTML form temelleri
- Zod ile validation
Güncellik ve teknoloji yığını
Makale 2026 itibarıyla güncellenmiştir. Örnekler ve API referansları şu yığınla uyumludur: Next.js 16 App Router, React 19, Zod, Prisma 7. Eski sürüm dokümantasyonu ile karıştırmamak için major versiyon farklarını özellikle belirttik.
Framework sürümleri hızla değişir; kalıcı olan prensipler (güvenlik, katman ayrımı, ölçüm) bu rehberin omurgasını oluşturur.
Mental model: Action bir API endpoint gibidir
Her "use server" fonksiyonu ağa açık bir yüzeydir. Client Component'ten çağrılsa bile sunucuda çalışır; bu yüzden session kontrolü ve input validation zorunludur.
Action'lar RSC payload içinde serialize edilir; public action'larda hassas bilgi döndürmeyin. Hata mesajlarını kullanıcı dostu, log'ları ise ayrıntılı tutun.
Birden fazla mutation için tek dev action yerine küçük, isimlendirilmiş action'lar (createComment, deleteComment) tercih edin — audit ve test kolaylaşır.
"use server";
import { revalidatePath } from "next/cache";
import { auth } from "@/auth";
import { commentSchema } from "@/lib/schemas/comment";
export async function createComment(formData: FormData) {
const session = await auth();
if (!session?.user?.id) {
return { ok: false as const, error: "Unauthorized" };
}
const parsed = commentSchema.safeParse({
blogId: formData.get("blogId"),
body: formData.get("body"),
});
if (!parsed.success) {
return { ok: false as const, error: "Invalid input", issues: parsed.error.flatten() };
}
await prisma.comment.create({
data: { ...parsed.data, authorId: session.user.id },
});
revalidatePath(`/blog/${parsed.data.blogId}`);
return { ok: true as const };
}
Form entegrasyonu ve progressive enhancement
JavaScript kapalı olsa bile form gönderimi çalışmalıdır. Server Action'ı doğrudan action prop'una bağlamak bu prensibi destekler.
useActionState ile önceki state (hata, başarı) form altında gösterilir. Loading için useFormStatus nested button gerektirir.
Form entegrasyonu ve progressive enhancement — Uygulama adımları
Aşağıdaki adımları sırayla uygulayın. Her adım tamamlandığında bir sonrakine geçin; özellikle güvenlik ve veri bütünlüğü adımlarını atlamayın.
Adım adım uygulama
Aşağıdaki sırayı takip edin. Her adımı tamamlamadan bir sonrakine geçmeyin; özellikle güvenlik ve veri katmanı adımları atlanmamalıdır.
- Server Component sayfada formu render edin; action import edin.
- Client wrapper yalnızca pending UI için kullanın.
- Başarılı submit sonrası focus yönetimi ve live region ile screen reader bilgilendirin.
// CommentForm.tsx — "use client"
"use client";
import { useActionState } from "react";
import { createComment } from "./actions";
export function CommentForm({ blogId }: { blogId: string }) {
const [state, action, pending] = useActionState(createComment, null);
return (
<form action={action}>
<input type="hidden" name="blogId" value={blogId} />
<textarea name="body" required minLength={3} />
<button disabled={pending}>{pending ? "Gönderiliyor…" : "Yorum ekle"}</button>
{state?.ok === false && <p role="alert">{state.error}</p>}
</form>
);
}
Yetkilendirme ve idempotency
Aynı form iki kez gönderildiğinde çift kayıt oluşmaması için strateji seçin.
Kritik işlemlerde (ödeme, yayınlama) idempotency key veya DB unique constraint kullanın.
Action içinde resource ownership kontrolü yapın: kullanıcı yalnızca kendi yorumunu silebilmeli.
Dikkat: Action'da yalnızca cookie session'a güvenmeyin; blogId için varlık ve yetki kontrolü ekleyin.
Cache ve revalidation
Mutation sonrası hangi path'lerin invalidate edileceği performansı doğrudan etkiler.
Production ortamında Server Actions ile ilgili en sık görülen sorun, geliştirme ortamındaki varsayımların (küçük veri seti, tek kullanıcı, sıcak cache) canlı trafikte çökmemesidir. Bu yüzden her değişiklikten önce yük testi veya en azından p95 latency ölçümü yapın.
Structured logging (request id, route, süre, kullanıcı id’si — PII olmadan) ve hata oranı alarmları, sorunları kullanıcı şikayetinden önce yakalamanızı sağlar. Log’da stack trace tutun; kullanıcıya generic mesaj gösterin.
Dokümantasyonu kod ile birlikte güncelleyin: README, ADR (Architecture Decision Record) veya ekip wiki’sinde “neden bu kararı aldık?” sorusunun cevabı gelecekteki sizin en büyük yardımcınızdır.
- revalidatePath — belirli route
- revalidateTag — etiketli fetch cache
- Gereksiz global revalidate'dan kaçının
Derinlemesine: Senaryo çalışması
Gerçek bir ekip senaryosu: Cuma akşamı deploy sonrası hata oranı yükseldi. Aşağıdaki kontrol listesi ile kök nedeni daraltın.
Son deploy diff'ine bakın: şema migration, env değişikliği, feature flag açılışı.
Trace id ile tek bir başarısız isteği uçtan uca izleyin (edge → server → DB).
Gerekirse kill switch veya önceki imaja rollback; veri migration geri alınamazsa kod rollback yeterli olmayabilir.
Adım adım uygulama
Aşağıdaki sırayı takip edin. Her adımı tamamlamadan bir sonrakine geçmeyin; özellikle güvenlik ve veri katmanı adımları atlanmamalıdır.
- Metrik panosunda hata oranı ve p95 latency
- Log'da son 15 dakika exception grupları
- Son başarılı deploy tag'ine dönüş kararı
Production checklist
Canlıya çıkmadan önce bu maddeleri review edin.
Production ortamında üretim ortamı ile ilgili en sık görülen sorun, geliştirme ortamındaki varsayımların (küçük veri seti, tek kullanıcı, sıcak cache) canlı trafikte çökmemesidir. Bu yüzden her değişiklikten önce yük testi veya en azından p95 latency ölçümü yapın.
Structured logging (request id, route, süre, kullanıcı id’si — PII olmadan) ve hata oranı alarmları, sorunları kullanıcı şikayetinden önce yakalamanızı sağlar. Log’da stack trace tutun; kullanıcıya generic mesaj gösterin.
Dokümantasyonu kod ile birlikte güncelleyin: README, ADR (Architecture Decision Record) veya ekip wiki’sinde “neden bu kararı aldık?” sorusunun cevabı gelecekteki sizin en büyük yardımcınızdır.
- Rate limit ve timeout tanımlı
- Secret'lar secret manager'da
- Health check ve readiness probe çalışıyor
- Alarm eşikleri tanımlı (5xx, latency)
Sık yapılan hatalar
Aşağıdaki tuzaklar eğitim ortamlarında nadiren, production'da ise pahalıya mal olur. Code review checklist'inize eklemenizi öneririz.
- Validation'ı atlayıp FormData'yı doğrudan Prisma'ya vermek
- Hassas stack trace'i client'a döndürmek
- Her action'da tüm siteyi revalidate etmek
Pratik alıştırmalar
Okumak yeterli değildir; öğrenmeyi pekiştirmek için küçük bir side-project veya mevcut kod tabanınızda şu görevleri uygulayın:
- Mevcut bir forma Server Action ekleyin ve Zod ile doğrulayın
- Yetkisiz kullanıcı ile delete action'ını test edin
- pending state için erişilebilir loading metni ekleyin
Özet ve sonraki adımlar
Bu rehberdeki prensipleri tek seferde tüm projeye uygulamaya çalışmayın. Önce tek bir route veya modül seçin, ölçün, sonra yaygınlaştırın.
- next-intl ile çok dilli form hata mesajları
- Rate limit middleware ile action koruması