async function updateProfile(formData: FormData) {
'use server';
const rawFormData = {
name: formData.get('name'),
bio: formData.get('bio'),
};
// Validare directă cu Zod pe server
const validated = profileSchema.safeParse(rawFormData);
if (!validated.success) return { error: 'Date invalide' };
try {
await db.user.update({ data: validated.data });
revalidatePath('/profile');
return { success: true };
} catch (e) {
return { error: 'Database error' };
}
}După vreo 12 ani de scris cod, am învățat că orice „magie” nouă vine cu un preț pe care îl plătești mai târziu, de obicei la 2 dimineața când crapă producția. Când au apărut Server Actions în Next.js, recunosc că am fost sceptic. Părea că ne întoarcem la PHP, dar după ce le-am folosit la un proiect cu vreo 5.000 de useri activi, m-am prins că sunt exact ce ne trebuia pentru 80% din cazuri.
Nu e o luptă între ele, ci mai degrabă o alegere de instrument. Hai să vedem unde strălucește fiecare, fără vrăjeală de marketing.
Formularele și experiența de dev
Pentru un formular clasic de contact sau de update profil, Server Actions sunt imbatabile. Am reușit să elimin cam 30% din codul de boilerplate la un modul de setări. Nu mai am nevoie de un endpoint separat, nu mai definesc tipuri de date în două locuri și, cel mai important, scap de useEffect sau de stări de loading gestionate manual dacă folosesc useFormStatus sau useOptimistic.
Trade-off-ul? Dacă ai nevoie de logica aia de submit și în afara aplicației tale de Next (de exemplu, dintr-o aplicație mobilă), ești blocat. Server Actions sunt strâns legate de framework. Dacă scrii un formular care trebuie să fie accesibil doar din browser-ul userului, go for it. Dacă vrei să poți da un curl la el mai târziu, fă-ți un API Route.
Problema cu File Upload
Aici e punctul unde mulți se ard. Am încercat să urc imagini de 10-15MB prin Server Actions și m-am lovit de timeout-uri pe Vercel (limita de 15-30 secunde pe hobby/pro plan). Mai mult, body-ul cererii într-o acțiune de server trece prin niște procesări de serializare care pot fi lente pentru fișiere mari.
La un proiect unde trebuia să urcăm PDF-uri grele, am revenit rapid la API Routes. De ce? Pentru că poți folosi edge runtime sau poți face streaming direct către S3/Cloudinary fără să încarci toată memoria serverului. La fișiere mici, gen un avatar de 200KB, Server Actions merg brici, dar pentru orice depășește câțiva mega, API Routes rămân baza.
Webhook-urile și integrarea cu terți
Să fie clar: nu poți folosi Server Actions pentru webhook-uri de la Stripe, Lemon Squeezy sau orice alt serviciu extern. Server Actions sunt gândite pentru interacțiunea utilizator-server, necesitând un context de sesiune și un header specific de Next.js.
Am văzut pe un forum pe cineva care încerca să facă un webhook de plată printr-o acțiune exportată. Nu merge așa. Pentru orice sistem extern care trebuie să-ți „bată la ușă”, API Routes sunt singura variantă. Plus că pe un endpoint de API poți dezactiva ușor body parsing-ul (necesar pentru verificarea semnăturii Stripe), lucru imposibil într-o acțiune de server.
Când aleg ce?
Regula mea e simplă acum. Dacă acțiunea e declanșată de un buton din UI-ul meu, încep cu Server Action. E mult mai rapid de scris, e type-safe din cutie și reduce bundle-ul de JS de pe client pentru că logica de validare (Zod, de exemplu) rămâne doar pe server.
Totuși, păstrez API Routes pentru:
- Aplicații mobile sau clienți externi.
- Upload de fișiere mari sau stream-uri de date.
- Webhook-uri și integrări server-to-server.
La ultimul proiect am ajuns la un mix de 70% Server Actions și 30% API Routes. Voi cum ați împărțit logica în ultimele release-uri de Next?