# Next.js 16 Server Actions en 2026 : mutations, revalidation et questions d'entretien
> Comment les Server Actions de Next.js 16 gèrent les mutations, la revalidation, l'état pending, l'UI optimiste et la sécurité, avec les questions d'entretien qui testent chaque concept.
- Published: 2026-06-24
- Updated: 2026-07-06
- Author: SharpSkill
- Tags: next.js, server-actions, react, mutations, revalidation, interview
- Reading time: 11 min
---
Les Server Actions de Next.js transforment une simple fonction asynchrone en un endpoint de mutation côté serveur qu'un formulaire peut appeler directement, sans route API, sans `fetch` client et sans sérialisation JSON manuelle. Dans Next.js 16, elles constituent la manière par défaut d'écrire des mutations de données, et elles reviennent dans presque chaque entretien React senior en 2026. Cette analyse détaillée décortique leur exécution, la façon dont la revalidation propage des données fraîches vers l'interface, la modélisation des états pending et d'erreur, ainsi que les règles de sécurité qui piègent la plupart des développeurs.
> **Définition en une phrase**
>
> Une Server Action est une fonction asynchrone marquée par `"use server"` qui s'exécute uniquement sur le serveur et peut être appelée depuis un composant client ou un formulaire comme si elle était locale, tandis que Next.js gère automatiquement la requête réseau, la sérialisation des arguments et la protection CSRF.
## Comment les Server Actions s'exécutent en coulisses
Une Server Action est une fonction exclusivement serveur invoquée sur le réseau via un endpoint généré par le compilateur. Lorsqu'une fonction porte la directive `"use server"`, le compilateur de Next.js n'envoie jamais son corps au navigateur. Il remplace la fonction par une référence légère : un identifiant d'action haché associé à une route POST générée. Appeler l'action depuis le client envoie une requête vers cette route, la vraie fonction s'exécute sur le serveur, et le résultat sérialisé est renvoyé en streaming à l'appelant.
Cette conception entraîne trois conséquences à retenir, autant pour le code de production que pour les entretiens. D'abord, les arguments et les valeurs de retour doivent être sérialisables, car ils traversent le réseau sous forme de payloads encodés. Ensuite, les secrets restent sur le serveur, puisque le corps de la fonction n'est jamais inclus dans le bundle client. Enfin, les actions rattachées à un `
)
}
```
L'attribut `name` de chaque champ devient la clé lue par `formData.get()`. La [référence FormData de MDN](https://developer.mozilla.org/en-US/docs/Web/API/FormData) explique comment le navigateur assemble cet objet à partir du formulaire. Pour un contrôle plus fin, `next/form` étend l'élément natif avec la navigation côté client et le préchargement, tout en conservant le même contrat fondé sur les actions.
## Gérer les états pending et d'erreur avec useActionState
Les formulaires réels ont besoin d'un retour de validation et d'un indicateur de chargement. Le hook `useActionState` de React 19 enveloppe une Server Action, fait circuler une valeur d'état à travers chaque soumission et expose un indicateur `isPending`. Il remplace l'ancienne dénomination `useFormState` et retourne un tuple composé de l'état courant, d'une action encapsulée et du booléen pending.
```tsx
// app/posts/new-post-form.tsx
"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 (
)
}
```
Lorsqu'un hook pilote l'action, la signature de la fonction gagne un premier paramètre `prevState` avant `FormData`. Retourner un objet plutôt que lever une exception permet au composant d'afficher la validation en ligne sans error boundary :
```typescript
// app/posts/actions.ts
"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 {
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: "" }
}
```
La [référence useActionState sur react.dev](https://react.dev/reference/react/useActionState) couvre des patterns avancés, comme la prise en charge des permaliens pour les soumissions avant hydratation. Retourner un état structuré maintient le chemin nominal et le chemin d'erreur dans un même endroit prévisible.
## revalidatePath vs revalidateTag : choisir la bonne invalidation
Une mutation ne représente que la moitié du travail ; l'interface doit la refléter. Next.js expose deux fonctions d'invalidation depuis `next/cache`, et choisir la bonne est un critère fréquent en entretien.
| Fonction | Invalide | Idéale quand |
|----------|-------------|-----------|
| `revalidatePath("/posts")` | Chaque entrée en cache pour une route | La mutation affecte une page ou un layout précis |
| `revalidateTag("posts")` | Chaque fetch en cache étiqueté avec ce tag | La même donnée apparaît sur plusieurs routes |
`revalidatePath` est grossière et centrée sur la route : elle vide le cache d'une URL et de son arbre de layouts. `revalidateTag` est granulaire et centrée sur la donnée : tout `fetch` ou fonction mise en cache étiqueté avec cette chaîne est purgé où qu'il se trouve. Les tags passent mieux à l'échelle dans les grandes applications, car une seule mutation peut rafraîchir une barre latérale, une liste et une page de détail en un seul appel. Les deux fonctions marquent les données comme périmées plutôt que de les recharger immédiatement, si bien que la requête suivante régénère le contenu.
Avec les Cache Components de Next.js 16, l'étiquetage s'intègre à la directive `"use cache"` via `cacheTag`, ce qui modifie la manière de raisonner sur le cache à l'échelle de l'application. Cette interaction est traitée en détail dans le [guide des Cache Components de Next.js 16](/blog/react-next/nextjs-16-cache-components-use-cache-ppr-interview-questions) sur SharpSkill.
## Mises à jour d'UI optimistes avec useOptimistic
Les allers-retours réseau ajoutent une latence perceptible. Le hook `useOptimistic` affiche instantanément le résultat attendu, puis se réconcilie avec la réponse du serveur une fois l'action résolue. Il prend l'état courant et un reducer qui produit la version optimiste.
```tsx
// app/posts/like-button.tsx
"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 (
)
}
```
Si l'action échoue, React ramène automatiquement la valeur optimiste à l'état confirmé du serveur, aucun rollback manuel n'est donc nécessaire. La [référence useOptimistic sur react.dev](https://react.dev/reference/react/useOptimistic) détaille comment le cycle de réconciliation interagit avec les transitions. C'est ce pattern qui rend les formulaires à base de Server Actions aussi réactifs qu'une SPA entièrement rendue côté client.
## Lier des arguments et appeler des actions depuis des gestionnaires d'événements
Toutes les mutations ne proviennent pas d'une soumission de formulaire. Supprimer une ligne, basculer un paramètre ou réordonner une liste part souvent d'un clic sur un bouton ou d'un autre événement. Une Server Action est une simple référence de fonction côté client, elle peut donc être appelée depuis n'importe quel gestionnaire, à condition que l'appel s'exécute dans une transition pour garder l'interface réactive.
Les arguments supplémentaires qui ne sont pas des champs de formulaire sont attachés avec `bind`, ce qui produit une nouvelle action à laquelle ces valeurs sont ajoutées en tête. C'est la manière idiomatique de passer un identifiant en même temps que le `FormData` soumis.
```tsx
// app/posts/post-actions.tsx
"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 (
{/* Event-handler invocation wrapped in a transition */}
)
}
```
Les arguments liés sont chiffrés comme n'importe quelle autre valeur capturée par fermeture, si bien que le `postId` n'est pas altéré en transit, même si l'action doit toujours vérifier que l'appelant est autorisé à agir sur cet enregistrement. Envelopper l'appel direct dans `startTransition` permet à React de garder l'interface interactive et d'exposer l'état pending sans passer par un formulaire.
## Sécurité des Server Actions : traiter chaque action comme une API publique
L'idée reçue la plus dangereuse est qu'une Server Action serait privée parce qu'elle est écrite à côté du code serveur. En réalité, dès qu'une action est utilisée, Next.js génère un endpoint POST public que n'importe qui peut appeler avec une requête forgée. Le framework fournit des identifiants d'action sécurisés et élimine les actions inutilisées lors du `next build`, mais il n'autorise pas l'appelant pour autant.
> **Autoriser à l'intérieur de chaque action**
>
> Les Server Actions sont des endpoints HTTP accessibles. Les vérifications de session dans un layout ou un middleware ne les protègent pas, car un attaquant peut envoyer une requête POST directement à l'action. Il faut vérifier la session et les permissions de l'appelant à l'intérieur du corps de l'action avant de toucher la moindre donnée.
```typescript
// app/admin/actions.ts
"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)
}
```
Deux autres règles comptent. Les valeurs capturées par fermeture dans une action en ligne sont chiffrées avant d'être envoyées au client et déchiffrées sur le serveur, de sorte qu'un token capturé n'est pas divulgué en clair, mais s'appuyer là-dessus reste fragile : mieux vaut bannir totalement les secrets des fermetures. Par ailleurs, tout argument provenant du client est une entrée non fiable qui doit être validée, exactement comme un corps de requête REST. Le [guide de sécurité des données de Next.js](https://nextjs.org/docs/app/guides/data-security) formalise le modèle de teinte (taint) derrière ces garanties. Pour s'entraîner de manière structurée sur ces compromis, le [module d'entretien sur les Server Actions de Next.js](/technologies/react-next/interview-questions/nextjs-server-actions) de SharpSkill fait travailler les questions exactes posées par les jurys de recrutement.
## Questions d'entretien sur les Server Actions de Next.js 16
Ces questions reviennent régulièrement dans les processus React et full-stack senior de 2026.
**Pourquoi une Server Action ne peut-elle accepter et retourner que des valeurs sérialisables ?** Parce que les arguments et les résultats franchissent la frontière réseau entre client et serveur sous forme de payloads encodés. Les fonctions, les instances de classe et les nœuds du DOM ne peuvent pas être sérialisés, les passer lève donc une exception. `FormData`, les objets simples, les tableaux et les primitives sont sans risque.
**Comment fonctionne l'amélioration progressive avec les Server Actions ?** Lorsqu'une action est passée directement à la prop `action` d'un formulaire, le navigateur soumet le formulaire nativement via une requête POST, avant même l'hydratation de React. Next.js intercepte et exécute l'action côté serveur, de sorte que le formulaire est fonctionnel sans JavaScript client et évolue vers une expérience pilotée par le client après l'hydratation.
**Quelle est la différence entre lever et retourner une erreur dans une action ?** Lever une exception la propage vers l'error boundary la plus proche et convient aux défaillances imprévues. Retourner un objet d'état structuré via `useActionState` convient aux erreurs de validation attendues, qui doivent s'afficher en ligne sans démonter le formulaire.
**Appeler revalidatePath recharge-t-il les données immédiatement ?** Non. Cette fonction marque les entrées en cache comme périmées afin que la requête suivante les régénère. La réponse en cours n'est pas affectée, c'est pourquoi une redirection après une mutation aboutit sur un contenu fraîchement rendu.
Pour le contexte de rendu plus large dans lequel s'exécutent ces mutations, l'analyse [React 19 Server Components en production](/blog/react-next/react-19-server-components-production) se combine naturellement avec la connaissance des Server Actions.
## Conclusion
Les Server Actions de Next.js 16 réunissent mutations, revalidation et amélioration progressive dans une même primitive orientée serveur. Les points clés à retenir :
- Marquer les mutations avec `"use server"` et les passer à la prop `action` d'un formulaire pour obtenir gratuitement la gestion réseau et l'amélioration progressive.
- Piloter l'état pending et de validation avec `useActionState`, en retournant un objet structuré pour les erreurs attendues plutôt que de lever une exception.
- Recourir à `revalidatePath` lorsqu'une seule route change et à `revalidateTag` lorsque la même donnée s'étend sur plusieurs routes.
- Utiliser `useOptimistic` pour afficher instantanément le résultat attendu et laisser React réconcilier ou revenir en arrière automatiquement.
- Autoriser et valider à l'intérieur du corps de chaque action, car chaque action utilisée est un endpoint HTTP public que le middleware seul ne protège pas.
---
Source: SharpSkill (https://sharpskill.dev), tech interview preparation for your real stack.
HTML version of this page: https://sharpskill.dev/fr/blog/react-next/nextjs-16-server-actions-mutations-revalidation-interview-questions