Giriş: Neden Server Actions?
Next.js’in son sürümleriyle birlikte uygulama mimarisi “daha az kablo, daha çok iş” anlayışına yaklaştı. Bunların başında da Server Actions geliyor. Klasik yaklaşımda bir form gönderimini işlemek için API route yazmak, doğrulama yapmak, CSRF önlemleri düşünmek, sonra istemci tarafında fetch ile bağlanmak gerekiyordu. Server Actions, özellikle App Router kullanan projelerde, bu akışı sadeleştirerek form verisini doğrudan sunucu tarafında çalışan bir fonksiyona teslim etmenizi sağlıyor.
Bu yazıda, Next.js 15 (App Router) üzerinde Server Actions ile API yazmadan form işleme akışını kuracağız. Örnek senaryomuz basit bir “Bültene kayıt” formu olacak: e-posta doğrulama, rate limit mantığına uygun küçük bir kontrol ve sonuç mesajını kullanıcıya gösterme. Kod örnekleri TypeScript odaklıdır, fakat aynı mantık JavaScript ile de birebir uygulanır.
Ön Koşullar
Devam etmeden önce projede App Router kullanıyor olmanız ve Node.js sürümünüzün güncel olması gerekir. Ayrıca örnekte veri saklama katmanını basit tutacağız; dilerseniz Prisma, Drizzle veya doğrudan PostgreSQL ile genişletebilirsiniz. Ama amaç, Server Actions’ın form + doğrulama + sunucu tarafı işlem üçlüsünde neleri kolaylaştırdığını net görmek.
1) Server Action Fonksiyonunu Tanımlama
Server Actions’ın temel fikri, bir fonksiyonun sunucuda çalışacağını açıkça belirtmektir. Bu sayede fonksiyonunuz istemci paketine taşınmaz ve güvenli tarafta kalır. Genellikle app altında bir dosyada, örneğin app/actions/newsletter.ts gibi konumlandırılır.
app/actions/newsletter.ts:
Not: Aşağıdaki kod bloğunu Blogger HTML’inde göstermek için düz metin olarak paylaşıyorum.
Kod:
"use server";
type ActionState = { ok: boolean; message: string };
function isValidEmail(email: string) {
return /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email);
}
export async function subscribeNewsletter(prevState: ActionState, formData: FormData): Promise<ActionState> {
const email = String(formData.get("email") ?? "").trim().toLowerCase();
if (!email) return { ok: false, message: "E-posta alanı boş olamaz." };
if (!isValidEmail(email)) return { ok: false, message: "Geçerli bir e-posta girin." };
// Basit bir “oran sınırlama” fikri: aynı e-postayı kısa sürede tekrar alma
// Gerçek projede Upstash/Redis veya benzeri bir katman önerilir.
await new Promise((r) => setTimeout(r, 300)); // örnek gecikme
// Burada DB’ye yazma veya üçüncü parti servise iletme yapılır
return { ok: true, message: "Kaydınız alındı. Teşekkürler!" };
}
2) Formu Server Action’a Bağlama
Şimdi bu action’ı bir formun action özelliğine bağlayacağız. Next.js tarafında bu, “form submit” ile birlikte verinin otomatik olarak sunucu fonksiyonuna gitmesi demek. Eğer kullanıcıya durum mesajı göstermek istiyorsanız useActionState (veya proje yapılandırmanıza göre benzer state kancaları) oldukça pratik.
app/newsletter/page.tsx örneği:
Kod:
"use client";
import { useActionState } from "react";
import { subscribeNewsletter } from "../actions/newsletter";
const initialState = { ok: false, message: "" };
export default function NewsletterPage() {
const [state, formAction, pending] = useActionState(subscribeNewsletter, initialState);
return (
<div>
<h2>Bültene Katıl</h2>
<form action={formAction}>
<label>E-posta</label>
<input name="email" type="email" placeholder="[email protected]" required />
<button type="submit" disabled={pending}>
{pending ? "Gönderiliyor..." : "Kaydol"}
</button>
</form>
{state.message ? (
<p><b>{state.ok ? "Başarılı:" : "Hata:"}</b> {state.message}</p>
) : null}
</div>
);
}
3) Güvenlik ve Üretim İpuçları
Server Actions API route ihtiyacını azaltır, ama güvenlik sorumluluğunu ortadan kaldırmaz. Öncelikle, sunucu tarafında çalışan fonksiyonlarınızda her zaman doğrulama yapın; istemci tarafındaki required gibi kontroller sadece kullanıcı deneyimidir, güvenlik değildir. İkinci olarak, bülten gibi uç noktalarda bot trafiği yoğun olur; bu yüzden gerçek projede rate limit’i Redis/Upstash gibi bir katmanla uygulamak mantıklıdır. Üçüncü olarak, e-posta kaydını bir veritabanına yazıyorsanız tekrarlı kayıtları engellemek için benzersiz indeks kullanın.
Performans tarafında da avantajlar var: fetch katmanı, ayrı endpoint, ekstra JSON serileştirme gibi adımlar azaldığı için akış sadeleşir. Ayrıca action’ın sunucu tarafında kalması, anahtar ve gizli bilgilerin istemciye sızma riskini ciddi biçimde düşürür. Buna rağmen üçüncü parti servis çağrıları yapıyorsanız (Mailchimp, Brevo, vb.), hata yönetimini iyi kurgulayın ve kullanıcıya ham hata mesajı döndürmeyin.
4) Sık Yapılan Hatalar
En sık görülen hata, action dosyasına "use server" eklemeyi unutmak veya action’ı istemci bileşeninde yanlış şekilde çağırmaktır. İkinci hata, form alan adlarının (örneğin name="email") action içinde okunan anahtarlarla uyuşmaması. Üçüncü hata ise, action içinde doğrulama yokken yalnızca istemci doğrulamasına güvenmek. Bu üç noktayı kontrol ettiğinizde, Server Actions akışı genellikle sorunsuz çalışır.
Sonuç
Next.js 15’te Server Actions, özellikle form temelli işlemlerde “API route yaz, fetch bağla, JSON dön” rutinini büyük ölçüde azaltıyor. Bu yaklaşım, hem kod tabanını sadeleştiriyor hem de hassas işlemleri doğal şekilde sunucu tarafında tutuyor. Buradaki bülten örneği küçük görünse de aynı mimariyi parola sıfırlama, ödeme sonrası kayıt, yönetim paneli formları ve veri güncelleme ekranları gibi daha kritik alanlara ölçekleyebilirsiniz.