Next.js 16 Server Actions 2026: Mutation, Revalidation ve Mülakat Soruları
Next.js 16 Server Actions'ın mutation, revalidation, bekleme durumu, optimistic UI ve güvenliği nasıl ele aldığı ve her kavramı sınayan mülakat soruları.

Next.js Server Actions, sıradan bir async fonksiyonu; API rotası, istemci tarafı fetch çağrısı veya manuel JSON serileştirmesi olmadan bir formun doğrudan çağırabileceği bir sunucu tarafı mutation uç noktasına dönüştürür. Next.js 16'da veri mutation'ları yazmanın varsayılan yolu bunlardır ve 2026'da neredeyse her senior React mülakatında karşımıza çıkarlar. Bu derinlemesine inceleme; bunların nasıl çalıştığını, revalidation'ın taze veriyi arayüze nasıl aktardığını, bekleme (pending) ve hata durumlarının nasıl modelleneceğini ve çoğu geliştiricinin takıldığı güvenlik kurallarını adım adım ele alıyor.
Server Action, "use server" ile işaretlenen ve yalnızca sunucuda çalışan; bir istemci bileşeninden veya formdan sanki yerel bir fonksiyonmuş gibi çağrılabilen async bir fonksiyondur; bu sırada Next.js ağ isteğini, argüman serileştirmesini ve CSRF korumasını otomatik olarak üstlenir.
Server Action'lar Perde Arkasında Nasıl Çalışır
Server Action, derleyicinin ürettiği bir uç nokta üzerinden ağ aracılığıyla çağrılan, yalnızca sunucuda çalışan bir fonksiyondur. Bir fonksiyon "use server" yönergesini taşıdığında, Next.js derleyicisi fonksiyonun gövdesini tarayıcıya asla göndermez. Bunun yerine fonksiyonun yerine hafif bir referans koyar: üretilen bir POST rotasına eşlenmiş, hash'lenmiş bir action kimliği. Action istemciden çağrıldığında bu rotaya bir istek gönderilir, gerçek fonksiyon sunucuda çalışır ve serileştirilmiş sonuç çağırana geri akıtılır.
Bu tasarımın hem üretim kodu hem de mülakatlar açısından akılda tutulması gereken üç sonucu vardır. Birincisi, argümanlar ve dönüş değerleri serileştirilebilir olmalıdır; çünkü ağ üzerinden kodlanmış yükler (payload) olarak geçerler. İkincisi, sırlar sunucuda kalır; çünkü fonksiyon gövdesi hiçbir zaman istemci için paketlenmez. Üçüncüsü, bir <form> öğesine bağlanan action'lar hydration'dan önce bile çalışır; progressive enhancement'ın (aşamalı geliştirme) temel bir satış noktası olmasının nedeni budur. Resmi Next.js veri güncelleme kılavuzu tam çalışma modelini belgeler.
Her Server Action, "use server" ile işaretlenmiş bir dosyada veya blokta yer alır. Tek bir mutation şuna benzer:
"use server"
import { revalidatePath } from "next/cache"
import { redirect } from "next/navigation"
import { PostService } from "@/lib/services/post-service"
export async function createPost(formData: FormData) {
// FormData values arrive as strings; cast explicitly
const title = formData.get("title") as string
const body = formData.get("body") as string
// Run business logic through the service layer, never the ORM directly
const post = await PostService.create({ title, body })
// Purge the cached list so the next request refetches it
revalidatePath("/posts")
// Send the user to the freshly created resource
redirect(`/posts/${post.id}`)
}Fonksiyon, gönderilen FormData'yı okur, bir servis katmanı üzerinden kalıcı hale getirir, önbelleğe alınmış listeyi geçersiz kılar ve yönlendirme yapar. Bunların hiçbiri için istemci tarafı JavaScript gerekmez.
Server Action'ı İstemci JavaScript'i Olmadan Bir Forma Bağlamak
Action'ı bir formun action prop'una geçirmek en basit entegrasyondur. Next.js, gönderimi FormData'ya serileştirir ve fonksiyonu sunucuda çağırır. Bu yaklaşım yerel form gönderim mekanizmasını kullandığı için JavaScript devre dışı bırakıldığında da çalışır ve sayfa hydrate olur olmaz sorunsuzca gelişir.
import { createPost } from "./actions"
export default function NewPostForm() {
return (
<form action={createPost}>
<input name="title" required />
<textarea name="body" required />
<button type="submit">Publish</button>
</form>
)
}Her alandaki name özniteliği, formData.get() tarafından okunan anahtar haline gelir. MDN FormData referansı tarayıcının bu nesneyi formdan nasıl oluşturduğunu açıklar. Daha zengin bir kontrol için next/form, aynı action tabanlı sözleşmeyi korurken yerel öğeyi istemci tarafı gezinme ve önyüklemeyle (prefetching) genişletir.
useActionState ile Bekleme ve Hata Durumunu Yönetmek
Gerçek formların doğrulama geri bildirimine ve bir yükleme göstergesine ihtiyacı vardır. React 19 hook'u useActionState, bir Server Action'ı sarmalar, her gönderim boyunca bir durum değerini taşır ve bir isPending bayrağı sunar. Eski useFormState adlandırmasının yerini alır ve geçerli durum, sarmalanmış bir action ve bekleme boolean değerinden oluşan bir tuple döndürür.
"use client"
import { useActionState } from "react"
import { createPost } from "./actions"
const initialState = { error: "" }
export default function NewPostForm() {
// state carries the last return value; isPending tracks the in-flight request
const [state, formAction, isPending] = useActionState(createPost, initialState)
return (
<form action={formAction}>
<input name="title" required />
<textarea name="body" required />
{state.error ? <p role="alert">{state.error}</p> : null}
<button type="submit" disabled={isPending}>
{isPending ? "Publishing..." : "Publish"}
</button>
</form>
)
}Bir hook action'ı yönettiğinde, fonksiyon imzası FormData'dan önce bir prevState ilk parametresi kazanır. Hata fırlatmak yerine bir nesne döndürmek, bileşenin bir error boundary olmadan satır içi doğrulama göstermesine olanak tanır:
"use server"
import { revalidateTag } from "next/cache"
import { PostService } from "@/lib/services/post-service"
type FormState = { error: string }
export async function createPost(
prevState: FormState,
formData: FormData,
): Promise<FormState> {
const title = formData.get("title") as string
// Validate on the server; client validation is never trustworthy alone
if (!title || title.length < 3) {
return { error: "Title must be at least 3 characters." }
}
await PostService.create({ title })
// Invalidate by tag rather than path for finer-grained control
revalidateTag("posts")
return { error: "" }
}react.dev'deki useActionState referansı, hydration öncesi gönderimler için permalink desteği gibi ileri düzey kalıpları kapsar. Yapılandırılmış durum döndürmek, başarı yolunu ve hata yolunu tek ve öngörülebilir bir yerde tutar.
revalidatePath ile revalidateTag: Doğru Geçersiz Kılma Yöntemini Seçmek
Bir mutation işin yalnızca yarısıdır; arayüzün de bunu yansıtması gerekir. Next.js, next/cache içinden iki geçersiz kılma fonksiyonu sunar ve doğru olanı seçmek mülakatlarda sık karşılaşılan bir ayırt edici sorudur.
| Fonksiyon | Neyi geçersiz kılar | En uygun olduğu durum |
|----------|-------------|-----------|
| revalidatePath("/posts") | Bir rotaya ait önbelleğe alınmış her girdiyi | Mutation, tek ve net bir sayfayı ya da layout'u etkilediğinde |
| revalidateTag("posts") | O etiketle işaretlenmiş her önbelleğe alınmış fetch'i | Aynı veri birden fazla rotada göründüğünde |
revalidatePath kaba ve rota merkezlidir: bir URL'nin ve onun layout ağacının önbelleğini temizler. revalidateTag ise ince taneli ve veri merkezlidir: o dizeyle etiketlenmiş herhangi bir fetch veya önbelleğe alınmış fonksiyon, nerede bulunursa bulunsun geçersiz kılınır. Büyük uygulamalarda etiketler daha iyi ölçeklenir; çünkü tek bir mutation, bir kenar çubuğunu, bir listeyi ve bir detay sayfasını tek bir çağrıda yenileyebilir. Her iki fonksiyon da veriyi hemen yeniden çekmek yerine bayat (stale) olarak işaretler; bu nedenle içeriği bir sonraki istek yeniden üretir.
Next.js 16 Cache Components ile etiketleme, cacheTag aracılığıyla "use cache" yönergesiyle bütünleşir; bu da önbelleklemenin uygulama genelinde nasıl ele alınacağını değiştirir. Bu etkileşim, SharpSkill'deki Next.js 16 Cache Components kılavuzunda ayrıntılı olarak inceleniyor.
React / Next.js mülakatlarında başarılı olmaya hazır mısın?
İnteraktif simülatörler, flashcards ve teknik testlerle pratik yap.
useOptimistic ile İyimser (Optimistic) Arayüz Güncellemeleri
Ağ gidiş-dönüşleri fark edilir bir gecikme ekler. useOptimistic hook'u beklenen sonucu anında render eder, ardından action tamamlandığında sunucu yanıtıyla uzlaştırır. Geçerli durumu ve iyimser sürümü üreten bir reducer alır.
"use client"
import { useOptimistic } from "react"
import { likePost } from "./actions"
export function LikeButton({ postId, likes }: { postId: string; likes: number }) {
// optimisticLikes updates before the server confirms
const [optimisticLikes, addOptimisticLike] = useOptimistic(
likes,
(current) => current + 1,
)
async function handleLike() {
addOptimisticLike(null) // update the UI immediately
await likePost(postId) // then run the real mutation
}
return (
<form action={handleLike}>
<button type="submit">Like ({optimisticLikes})</button>
</form>
)
}Action başarısız olursa React, iyimser değeri otomatik olarak onaylanmış sunucu durumuna geri döndürür; bu sayede manuel bir geri alma işlemine gerek kalmaz. react.dev'deki useOptimistic referansı, uzlaşma döngüsünün geçişlerle (transition) nasıl etkileşime girdiğini ayrıntılı olarak anlatır. Bu kalıp, Server Action formlarını tamamen istemcide render edilen bir SPA kadar tepkisel hissettiren şeydir.
Argümanları Bağlamak ve Action'ları Olay İşleyicilerinden Çağırmak
Her mutation bir form gönderiminden kaynaklanmaz. Bir satırı silmek, bir ayarı açıp kapatmak veya bir listeyi yeniden sıralamak çoğunlukla bir düğme tıklamasından ya da başka bir olaydan tetiklenir. Server Action, istemcide sıradan bir fonksiyon referansıdır; bu nedenle, çağrının arayüzü tepkisel tutmak için bir transition içinde çalışması koşuluyla herhangi bir işleyiciden çağrılabilir.
Form alanı olmayan ek argümanlar bind ile eklenir; bu da söz konusu değerleri başa ekleyen yeni bir action üretir. Gönderilen FormData ile birlikte bir kimlik (ID) geçirmenin yerleşik yolu budur.
"use client"
import { useTransition } from "react"
import { deletePost, updatePost } from "./actions"
export function PostActions({ postId }: { postId: string }) {
const [isPending, startTransition] = useTransition()
// Bind the id so the action receives it before FormData
const updateWithId = updatePost.bind(null, postId)
return (
<div>
<form action={updateWithId}>
<input name="title" />
<button type="submit">Save</button>
</form>
{/* Event-handler invocation wrapped in a transition */}
<button
onClick={() => startTransition(() => deletePost(postId))}
disabled={isPending}
>
{isPending ? "Deleting..." : "Delete"}
</button>
</div>
)
}Bağlanan argümanlar, kapanışta yakalanan (closed-over) diğer değerler gibi şifrelenir; böylece postId aktarım sırasında kurcalanmaz. Yine de action, çağıranın o kayıt üzerinde işlem yapma yetkisi olduğunu doğrulamak zorundadır. Doğrudan çağrıyı startTransition içine sarmalamak, React'in arayüzü etkileşimli tutmasını sağlar ve bekleme durumunu bir form sarmalayıcısı olmadan gösterir.
Server Action Güvenliği: Her Action'ı Herkese Açık Bir API Gibi Ele Alın
En tehlikeli yanılgı, bir Server Action'ın sunucu kodunun yanında yazıldığı için özel (private) olduğunu sanmaktır. Gerçekte, bir action kullanıldığında Next.js, herkesin özel olarak hazırlanmış bir istekle çağırabileceği herkese açık bir POST uç noktası üretir. Framework, güvenli action kimlikleri sağlar ve next build sırasında kullanılmayan action'ları ortadan kaldırır; ancak çağıranı yetkilendirmez.
Server Action'lar erişilebilir HTTP uç noktalarıdır. Bir layout'taki veya middleware'deki oturum kontrolleri onları korumaz; çünkü bir saldırgan doğrudan action'a POST isteği gönderebilir. Herhangi bir veriye dokunmadan önce oturumu ve çağıranın izinlerini action gövdesinin içinde doğrulayın.
"use server"
import { auth } from "@/lib/auth"
import { headers } from "next/headers"
import { UserService } from "@/lib/services/user-service"
export async function deleteUser(userId: string) {
// Authenticate on every invocation, not in a wrapper component
const session = await auth.api.getSession({ headers: await headers() })
if (!session || session.user.role !== "admin") {
throw new Error("Unauthorized")
}
await UserService.delete(userId)
}İki kural daha önemlidir. Satır içi bir action tarafından yakalanan kapanış (closed-over) değerleri, istemciye gönderilmeden önce şifrelenir ve sunucuda çözülür; böylece yakalanan bir token düz metin olarak sızmaz, ancak buna güvenmek kırılgandır: sırları kapanışların tamamen dışında tutun. Ayrıca istemciden gelen her argüman, tıpkı bir REST gövdesi gibi doğrulanması gereken güvenilmez bir girdidir. Next.js veri güvenliği kılavuzu, bu garantilerin arkasındaki taint (kirlilik) modelini biçimsel olarak tanımlar. Bu ödünleşimler üzerinde yapılandırılmış pratik için SharpSkill'deki Next.js Server Actions mülakat modülü, işe alım panellerinin tam olarak sorduğu soruları çalıştırır.
Next.js 16 Server Actions Mülakat Soruları
Bu sorular, 2026 senior React ve full-stack mülakat turlarında tekrar tekrar karşımıza çıkar.
Bir Server Action neden yalnızca serileştirilebilir değerler kabul edip döndürebilir? Çünkü argümanlar ve sonuçlar, istemci ile sunucu arasındaki ağ sınırını kodlanmış yükler olarak geçer. Fonksiyonlar, sınıf örnekleri ve DOM düğümleri serileştirilemez; bu nedenle bunları geçirmek hata fırlatır. FormData, düz nesneler, diziler ve ilkel (primitive) değerler güvenlidir.
Server Action'larla progressive enhancement nasıl çalışır? Bir action doğrudan bir formun action prop'una geçirildiğinde, tarayıcı formu React hydrate olmadan önce bile bir POST isteğiyle yerel olarak gönderir. Next.js bu isteği yakalar ve action'ı sunucu tarafında çalıştırır; böylece form istemci JavaScript'i olmadan işlevseldir ve hydration'dan sonra istemci odaklı bir deneyime yükselir.
Bir action'da hata fırlatmak ile hata döndürmek arasındaki fark nedir? Hata fırlatmak, en yakın error boundary'ye yayılır ve beklenmeyen başarısızlıklar için doğru seçenektir. useActionState aracılığıyla yapılandırılmış bir durum nesnesi döndürmek ise, formu DOM'dan kaldırmadan satır içi gösterilmesi gereken beklenen doğrulama hataları için doğru seçenektir.
revalidatePath çağrısı veriyi hemen yeniden çeker mi? Hayır. Önbelleğe alınmış girdileri bayat (stale) olarak işaretler; böylece bir sonraki istek bunları yeniden üretir. Geçerli yanıt etkilenmez; bir mutation'dan sonraki yönlendirmenin taze render edilmiş içeriğe ulaşmasının nedeni budur.
Bu mutation'ların içinde çalıştığı daha geniş render bağlamı için, Üretimde React 19 Server Components incelemesi, Server Actions bilgisiyle doğal olarak birlikte gider.
React / Next.js mülakatlarında başarılı olmaya hazır mısın?
İnteraktif simülatörler, flashcards ve teknik testlerle pratik yap.
Sonuç
Next.js 16 Server Actions; mutation'ları, revalidation'ı ve progressive enhancement'ı tek ve sunucu öncelikli bir yapıda birleştirir. Öne çıkan noktalar:
- Ağ yönetimini ve progressive enhancement'ı bedava elde etmek için mutation'ları
"use server"ile işaretleyin ve bir formunactionprop'una geçirin. - Bekleme ve doğrulama durumunu
useActionStateile yönetin; beklenen hatalar için hata fırlatmak yerine yapılandırılmış bir nesne döndürün. - Tek bir rota değiştiğinde
revalidatePath'e, aynı veri birden fazla rotaya yayıldığındarevalidateTag'e başvurun. - Beklenen sonucu anında render etmek ve React'in otomatik olarak uzlaştırmasına ya da geri almasına izin vermek için
useOptimistickullanın. - Her action gövdesinin içinde yetkilendirme ve doğrulama yapın; çünkü kullanılan her action, yalnızca middleware'in korumadığı herkese açık bir HTTP uç noktasıdır.
Pratik yapmaya başla!
Mülakat simülatörleri ve teknik testlerle bilgini test et.
Etiketler
Paylaş
İlgili makaleler

Next.js 16'da Cache Components: use cache, PPR ve 2026 Mülakat Soruları
Next.js 16 Cache Components rehberi: use cache yönergesi, Partial Pre-Rendering, cacheLife, cacheTag, use cache private ile güvenlik ve kıdemli geliştirici mülakat soruları.

2026'da React Compiler: Otomatik Memoizasyon ve Teknik Mülakat Soruları
React Compiler hakkında kapsamlı rehber — otomatik memoizasyon, derleme hattı, React kuralları, ESLint entegrasyonu ve 2026 yılı React teknik mülakat soruları.

React 19 useEffectEvent ve Activity: Yeni API'ler ve 2026 Mulakat Sorulari
React 19.2 useEffectEvent ve Activity API detayli incelemesi. Stale closure cozumleri, arka plan on-render, kod ornekleri ve 2026 mulakat sorulari.