# Server Actions di Next.js 16 nel 2026: mutazioni, revalidation e domande da colloquio
> Come le Server Actions di Next.js 16 gestiscono mutazioni, revalidation, stato di attesa, UI ottimistica e sicurezza, con le domande da colloquio che verificano ogni concetto.
- Published: 2026-06-24
- Updated: 2026-07-06
- Author: SharpSkill
- Tags: next.js, server-actions, react, mutations, revalidation, interview
- Reading time: 11 min
---
Le Server Actions di Next.js trasformano una semplice funzione async in un endpoint di mutazione lato server che un form può chiamare direttamente, senza route API, senza `fetch` lato client e senza serializzazione JSON manuale. In Next.js 16 sono il modo predefinito per scrivere le mutazioni dei dati e compaiono in quasi ogni colloquio React senior del 2026. Questa analisi approfondita spiega come vengono eseguite, come la revalidation propaga dati aggiornati all'interfaccia, come modellare gli stati di attesa ed errore e le regole di sicurezza che mettono in difficoltà la maggior parte degli sviluppatori.
> **Definizione in una frase**
>
> Una Server Action è una funzione async contrassegnata con `"use server"` che viene eseguita solo sul server e può essere chiamata da un componente client o da un form come se fosse locale, mentre Next.js gestisce automaticamente la richiesta di rete, la serializzazione degli argomenti e la protezione CSRF.
## Come vengono eseguite le Server Actions dietro le quinte
Una Server Action è una funzione eseguita solo sul server e invocata attraverso la rete tramite un endpoint generato dal compilatore. Quando una funzione riporta la direttiva `"use server"`, il compilatore di Next.js non invia mai il suo corpo al browser. Al suo posto sostituisce la funzione con un riferimento leggero: un ID di azione con hash mappato su una route POST generata. Chiamare l'azione dal client invia una richiesta a quella route, la funzione reale viene eseguita sul server e il risultato serializzato viene trasmesso in streaming al chiamante.
Questo design ha tre conseguenze da ricordare sia per il codice di produzione sia per i colloqui. Primo, gli argomenti e i valori di ritorno devono essere serializzabili, perché attraversano la rete come payload codificati. Secondo, i segreti restano sul server, dato che il corpo della funzione non viene mai incluso nel bundle destinato al client. Terzo, le azioni collegate a un `
)
}
```
L'attributo `name` di ogni campo diventa la chiave letta da `formData.get()`. Il [riferimento MDN su FormData](https://developer.mozilla.org/en-US/docs/Web/API/FormData) spiega come il browser assembla questo oggetto a partire dal form. Per un controllo più ricco, `next/form` estende l'elemento nativo con navigazione lato client e prefetching, mantenendo lo stesso contratto basato sulle azioni.
## Gestire lo stato di attesa ed errore con useActionState
I form reali hanno bisogno di feedback di validazione e di un indicatore di caricamento. L'hook di React 19 `useActionState` avvolge una Server Action, propaga un valore di stato attraverso ogni invio ed espone un flag `isPending`. Sostituisce la vecchia denominazione `useFormState` e restituisce una tupla composta dallo stato corrente, dall'azione avvolta e dal booleano di attesa.
```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 (
)
}
```
Quando un hook guida l'azione, la firma della funzione acquisisce un primo parametro `prevState` prima di `FormData`. Restituire un oggetto invece di lanciare un'eccezione permette al componente di mostrare la validazione inline senza un 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: "" }
}
```
Il [riferimento a useActionState su react.dev](https://react.dev/reference/react/useActionState) illustra pattern avanzati come il supporto ai permalink per gli invii precedenti all'hydration. Restituire uno stato strutturato mantiene il percorso corretto e quello di errore in un unico punto prevedibile.
## revalidatePath vs revalidateTag: scegliere l'invalidazione giusta
Una mutazione è solo metà del lavoro: l'interfaccia deve rifletterla. Next.js espone due funzioni di invalidazione da `next/cache`, e scegliere quella corretta è un discriminante frequente nei colloqui.
| Funzione | Invalida | Ideale quando |
|----------|-------------|-----------|
| `revalidatePath("/posts")` | Ogni voce in cache di una route | La mutazione riguarda una pagina o un layout ben preciso |
| `revalidateTag("posts")` | Ogni fetch in cache etichettata con quel tag | Gli stessi dati compaiono su più route |
`revalidatePath` è grossolana e orientata alle route: svuota la cache per un URL e per il suo albero di layout. `revalidateTag` è granulare e orientata ai dati: qualsiasi `fetch` o funzione in cache etichettata con quella stringa viene svuotata ovunque si trovi. I tag scalano meglio nelle applicazioni di grandi dimensioni, perché una singola mutazione può aggiornare una sidebar, un elenco e una pagina di dettaglio con una sola chiamata. Entrambe le funzioni contrassegnano i dati come obsoleti anziché ricaricarli immediatamente, così la richiesta successiva rigenera il contenuto.
Con i Cache Components di Next.js 16, il tagging si integra con la direttiva `"use cache"` tramite `cacheTag`, cosa che cambia il modo di ragionare sulla cache in tutta l'applicazione. Questa interazione è trattata in modo approfondito nella [guida ai Cache Components di Next.js 16](/blog/react-next/nextjs-16-cache-components-use-cache-ppr-interview-questions) su SharpSkill.
## Aggiornamenti ottimistici dell'interfaccia con useOptimistic
I round trip di rete aggiungono una latenza percepibile. L'hook `useOptimistic` mostra istantaneamente il risultato atteso, poi si riconcilia con la risposta del server una volta che l'azione si risolve. Riceve lo stato corrente e un reducer che produce la versione ottimistica.
```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 (
)
}
```
Se l'azione fallisce, React ripristina automaticamente il valore ottimistico allo stato confermato dal server, quindi non è necessario alcun rollback manuale. Il [riferimento a useOptimistic su react.dev](https://react.dev/reference/react/useOptimistic) descrive nel dettaglio come il ciclo di riconciliazione interagisce con le transizioni. È questo pattern a far percepire i form basati su Server Actions reattivi quanto una SPA renderizzata interamente sul client.
## Associare argomenti e chiamare le azioni dagli event handler
Non tutte le mutazioni hanno origine dall'invio di un form. Eliminare una riga, attivare o disattivare un'impostazione o riordinare un elenco spesso parte dal clic su un pulsante o da un altro evento. Sul client una Server Action è un normale riferimento a funzione, quindi può essere chiamata da qualsiasi handler, a patto che la chiamata avvenga all'interno di una transizione per mantenere l'interfaccia reattiva.
Gli argomenti aggiuntivi che non sono campi del form si collegano con `bind`, che produce una nuova azione con quei valori anteposti. È il modo idiomatico per passare un ID insieme ai `FormData` inviati.
```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 */}
)
}
```
Gli argomenti associati sono cifrati come qualsiasi altro valore catturato in closure, quindi il `postId` non viene manomesso durante il transito, anche se l'azione deve comunque verificare che il chiamante sia autorizzato ad agire su quel record. Avvolgere la chiamata diretta in `startTransition` permette a React di mantenere l'interfaccia interattiva ed espone lo stato di attesa senza bisogno di un form.
## Sicurezza delle Server Actions: ogni azione è un'API pubblica
L'equivoco più pericoloso è credere che una Server Action sia privata perché scritta accanto al codice server. In realtà, non appena un'azione viene utilizzata, Next.js genera un endpoint POST pubblico che chiunque può chiamare con una richiesta costruita ad hoc. Il framework fornisce ID di azione sicuri ed elimina le azioni inutilizzate durante `next build`, ma non autorizza il chiamante.
> **Autorizzare all'interno di ogni azione**
>
> Le Server Actions sono endpoint HTTP raggiungibili. I controlli di sessione in un layout o in un middleware non le proteggono, perché un aggressore può inviare una richiesta POST direttamente all'azione. Occorre verificare la sessione e i permessi del chiamante all'interno del corpo dell'azione prima di toccare qualsiasi dato.
```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)
}
```
Contano altre due regole. I valori catturati in closure da un'azione inline vengono cifrati prima di essere inviati al client e decifrati sul server, quindi un token catturato non viene esposto in chiaro, ma affidarsi a questo è fragile: è meglio tenere del tutto i segreti fuori dalle closure. Inoltre, qualsiasi argomento proveniente dal client è input non attendibile che deve essere validato, esattamente come il body di una richiesta REST. La [guida alla sicurezza dei dati di Next.js](https://nextjs.org/docs/app/guides/data-security) formalizza il modello di taint alla base di queste garanzie. Per esercitarsi in modo strutturato su questi compromessi, il [modulo di domande da colloquio sulle Server Actions di Next.js](/technologies/react-next/interview-questions/nextjs-server-actions) su SharpSkill propone esattamente le domande poste dalle commissioni di selezione.
## Domande da colloquio sulle Server Actions di Next.js 16
Queste domande ricorrono con costanza nei colloqui React e full-stack senior del 2026.
**Perché una Server Action può accettare e restituire solo valori serializzabili?** Perché argomenti e risultati attraversano il confine di rete tra client e server come payload codificati. Funzioni, istanze di classi e nodi del DOM non possono essere serializzati, quindi passarli genera un'eccezione. `FormData`, oggetti semplici, array e valori primitivi sono sicuri.
**Come funziona il progressive enhancement con le Server Actions?** Quando un'azione viene passata direttamente alla prop `action` di un form, il browser invia il form in modo nativo tramite una richiesta POST ancora prima che React esegua l'hydration. Next.js intercetta ed esegue l'azione lato server, così il form è funzionante senza JavaScript lato client e si aggiorna a un'esperienza guidata dal client dopo l'hydration.
**Qual è la differenza tra lanciare e restituire un errore in un'azione?** Lanciare un'eccezione la propaga all'error boundary più vicino ed è la scelta giusta per i guasti imprevisti. Restituire un oggetto di stato strutturato tramite `useActionState` è la scelta giusta per gli errori di validazione previsti, che dovrebbero essere mostrati inline senza smontare il form.
**Chiamare revalidatePath ricarica i dati immediatamente?** No. Contrassegna le voci in cache come obsolete, così la richiesta successiva le rigenera. La risposta corrente non ne è influenzata, ed è per questo che un redirect dopo una mutazione porta a contenuti appena renderizzati.
Per il contesto di rendering più ampio in cui vengono eseguite queste mutazioni, l'analisi [React 19 Server Components in produzione](/blog/react-next/react-19-server-components-production) si abbina naturalmente alla conoscenza delle Server Actions.
## Conclusione
Le Server Actions di Next.js 16 consolidano mutazioni, revalidation e progressive enhancement in un unico primitivo server-first. I punti chiave:
- Contrassegnare le mutazioni con `"use server"` e passarle alla prop `action` di un form per ottenere gratuitamente la gestione della rete e il progressive enhancement.
- Gestire lo stato di attesa e di validazione con `useActionState`, restituendo un oggetto strutturato per gli errori previsti invece di lanciare eccezioni.
- Ricorrere a `revalidatePath` quando cambia una sola route e a `revalidateTag` quando gli stessi dati si estendono su più route.
- Usare `useOptimistic` per mostrare istantaneamente il risultato atteso e lasciare che React riconcili o esegua il rollback automaticamente.
- Autorizzare e validare all'interno del corpo di ogni azione, perché ogni azione utilizzata è un endpoint HTTP pubblico che il solo middleware non protegge.
---
Source: SharpSkill (https://sharpskill.dev), tech interview preparation for your real stack.
HTML version of this page: https://sharpskill.dev/it/blog/react-next/nextjs-16-server-actions-mutations-revalidation-interview-questions