
Next.js : Arrêtez le Spaghetti Code dans vos Server Actions
En 2026, Next.js vous laisse tout faire, y compris n'importe quoi. Vous appelez votre ORM directement dans vos composants UI ? C'est un suicide architectural. J'ai vu trop de projets s'effondrer sous le poids de la "colocation" mal comprise. Voici comment structurer un CRUD qui survit à la hype, aux refontes et à votre future équipe.
Nous sommes en 2026. Le App Router est stable, les Server Actions sont la norme, et pourtant, je vois encore le même code toxique qu'en 2023.
La promesse de Vercel est séduisante : "Écrivez votre SQL à côté de votre bouton". C'est un piège.
Pour un prototype de hackathon ? Allez-y. Pour une app qui doit vivre plus de 6 mois ? C'est criminel. Aujourd'hui, on démonte le mythe de la "simplicité" pour construire quelque chose de solide.
Le Problème : L'Infection de l'UI par la Data
Quand vous importez prisma ou drizzle directement dans page.tsx ou une Server Action inline, vous couplez votre interface à votre infrastructure.
Si demain vous voulez changer d'ORM, exposer une API REST publique ou simplement tester votre logique métier sans lancer un navigateur, vous êtes coincés. Vous devez réécrire l'application.
L'Architecture en Couches (Oui, même en JS)
Oubliez la complexité de Java Spring, mais gardez la discipline. Nous avons besoin de trois niveaux distincts pour un CRUD robuste :
- Interface (UI) : Composants React stupides.
- Infrastructure (Actions) : Validation, Auth check, Parsing.
- Domaine (Services) : La vérité métier, agnostique du framework.

1. La Loi de la Validation (Zod/Valibot)
En 2026, si vous n'avez pas un schéma strict pour chaque entrée, vous codez à l'aveugle. Nous utilisons Zod (ou Valibot pour le tree-shaking) pour définir le contrat.
// src/domain/products/schema.ts
import { z } from 'zod';
export const CreateProductSchema = z.object({
name: z.string().min(3, "Le nom est trop court"),
price: z.number().positive("Le prix doit être positif"),
sku: z.string().regex(/^[A-Z0-9-]+$/, "Format SKU invalide")
});
export type CreateProductInput = z.infer<typeof CreateProductSchema>;
2. Le Service : Le Gardien du Métier
C'est ici que vit votre code. Pas dans Next.js. Ce fichier ne doit rien savoir de FormData ou de revalidatePath.
Il prend des données propres, applique les règles métier, et parle à la DB.
// src/domain/products/service.ts
import { db } from '@/lib/db';
import { CreateProductInput } from './schema';
export const ProductService = {
create: async (data: CreateProductInput) => {
// Règle métier : Pas de doublons de SKU
const existing = await db.product.findUnique({ where: { sku: data.sku } });
if (existing) {
throw new Error("Ce SKU existe déjà");
}
// Création pure
return db.product.create({ data });
}
};
3. La Server Action : Le Passe-Plat
Maintenant, et seulement maintenant, on touche à Next.js. La Server Action est notre couche de transport. Elle attrape la requête, sécurise l'entrée, et délègue.
// src/app/actions/create-product.ts
'use server';
import { redirect } from 'next/navigation';
import { CreateProductSchema } from '@/domain/products/schema';
import { ProductService } from '@/domain/products/service';
import { auth } from '@/lib/auth'; // Votre auth de choix
export async function createProductAction(prevState: any, formData: FormData) {
// 1. Auth Check
const session = await auth();
if (!session) return { error: "Non autorisé" };
// 2. Validation & Parsing
const rawData = Object.fromEntries(formData.entries());
const parsed = CreateProductSchema.safeParse({
...rawData,
price: Number(rawData.price)
});
if (!parsed.success) {
return { errors: parsed.error.flatten().fieldErrors };
}
try {
// 3. Appel au Service
await ProductService.create(parsed.data);
} catch (e) {
// Gestion d'erreur propre
return { error: e instanceof Error ? e.message : "Erreur inconnue" };
}
// 4. Side Effects (Spécifique Next.js)
redirect('/dashboard/products');
}
Pourquoi ça change tout ?
Cette structure vous protège de vous-même.
- Vous voulez passer à une API Route ? Importez
ProductServicedans votre route handlerGET. Zéro duplication. - Vous voulez changer de DB ? Vous ne touchez que
service.ts. - Le Frontend change ? La logique métier reste intacte.
Arrêtez de coder pour la démo de 5 minutes. Codez pour la maintenance de 5 ans.
Un projet en tête ?
Discutons de vos besoins techniques et voyons comment je peux vous aider à concrétiser votre projet.
Me contacter