JavaScript

React Server Components: cosa cambiano davvero nel modo di costruire app web

Da quando Next.js App Router è diventato lo standard, capire i Server Components non è più opzionale. Ecco cosa cambia nel modo concreto di costruire applicazioni.

13 Apr 2026·8 min di lettura·Antonio Tufo
Schermata di codice React con componenti server e client su un editor VS Code scuro

React Server Components: cosa cambiano davvero nel modo di costruire app web

Nei progetti che seguo, da quando Next.js ha adottato l'App Router come standard, la domanda che ricevo più spesso da sviluppatori alle prime armi con l'architettura moderna è sempre la stessa: "Perché il mio componente non riesce a usare `useState` se è dentro la cartella `app/`?" La risposta è che stiamo parlando, molto probabilmente, di un Server Component, e capire cosa questo significhi nella pratica è uno di quei passaggi che, una volta interiorizzato, cambia completamente il modo in cui scrivi JavaScript per il web.

I React Server Components (RSC) non sono una novità assoluta del 2026, dal momento che il lavoro sperimentale del team di React risale al 2020, ma è soltanto con l'adozione massiccia di Next.js 13 in poi che sono diventati una realtà concreta nella vita quotidiana di chi costruisce applicazioni. Dunque, quello che voglio fare in questo articolo è andare oltre la definizione da documentazione ufficiale e ragionare su cosa cambia nel modo concreto di costruire un'app, quali sono i vantaggi reali e dove, di fatto, i Server Components non sono la scelta giusta.

La distinzione di base: dove gira il codice

Per capire i React Server Components bisogna prima mettere da parte l'idea che React sia soltanto un framework che gira nel browser. Prima dell'App Router, quando costruivi un'applicazione Next.js con le Pages Router, avevi un'unica separazione netta: il codice server stava in `getServerSideProps` o `getStaticProps`, e tutto il resto, ossia i componenti React, girava sul client oppure veniva pre-renderizzato lato server ma poi IDRATATO nel browser.

L'idratazione è proprio il concetto chiave da cui partire. Quando un componente React viene "idratato", significa che il browser scarica il bundle JavaScript corrispondente, lo esegue, e "attiva" il markup HTML statico rendendolo interattivo. Questo processo ha un costo: più componenti hai nell'albero, più JavaScript il browser deve scaricare, analizzare ed eseguire. In un'applicazione con decine o centinaia di componenti, questo peso diventa tangibile, in particolar modo su dispositivi mobili o connessioni lente.

I React Server Components rompono questa dinamica in modo RADICALE. Un Server Component non viene mai spedito al browser come JavaScript: gira soltanto sul server, produce il suo output HTML, e quest'ultimo viene inviato direttamente al client senza che ci sia nessun bundle associato da scaricare. Il browser riceve markup, non logica.

Cosa puoi (e non puoi) fare in un Server Component

Nella pratica, un Server Component in Next.js App Router è semplicemente un file `.tsx` o `.jsx` senza la direttiva `"use client"` all'inizio. Per impostazione predefinita, tutti i componenti dentro la cartella `app/` sono Server Components, dal momento che questa è la scelta di default dell'App Router.

Nei Server Components puoi fare cose che prima richiedevano passaggi espliciti lato server: accedere direttamente al database, leggere variabili d'ambiente sensibili, fare fetch a API esterne senza esporre chiavi al browser, leggere il filesystem. Ho usato questa caratteristica in un progetto recente in cui, seppur il frontend fosse completamente in React, avevo bisogno di accedere a dati da un database PostgreSQL in modo diretto, senza costruire un'API REST intermedia soltanto per passare dati da server a client. Un Server Component fa la query, costruisce il JSX con i dati, e spedisce il risultato al browser, senza nemmeno che una riga del codice del database raggiunga mai il client.

Quello che non puoi fare in un Server Component è tutto ciò che dipende dal browser o dall'interattività: `useState`, `useEffect`, `useRef`, event handler come `onClick` o `onChange`, Context React lato client. Qualsiasi componente che ha bisogno di interazione diretta dell'utente deve essere un Client Component, il che significa che devi aggiungere la direttiva `"use client"` all'inizio del file.

Dunque la domanda che ti poni quando costruisci una nuova feature è diventata: "Questo componente ha bisogno di stato o di interazione?" Se la risposta è no, probabilmente è un Server Component. Se la risposta è sì, è un Client Component. Sembra semplice, e in buona parte lo è, ma ci sono alcune sfumature che vale la pena approfondire prima che diventino problemi reali in produzione.

Il confine tra server e client nell'albero dei componenti

Uno degli aspetti più importanti, e spesso fonte di confusione, è capire come funziona il confine tra Server e Client Components nell'albero React. La regola è semplice ma non sempre intuitiva: un Server Component può importare e renderizzare un Client Component, ma un Client Component non può importare un Server Component aspettandosi che quest'ultimo rimanga un Server Component.

Questo significa che il confine "scende" verso il basso: puoi avere una pagina che è un Server Component, che renderizza un componente di layout che è un Client Component (perché, per esempio, gestisce lo stato del menu mobile su smartphone), e dentro quest'ultimo puoi passare dati via props dal server. Quello che non puoi fare è importare un Server Component all'interno di un Client Component e aspettarti che rimanga lato server, dal momento che tutto ciò che si trova dentro un Client Component viene, di fatto, considerato parte del bundle client.

Una tecnica che nei progetti che seguo uso spesso è quella di passare Server Components come `children` ai Client Components, invece di importarli direttamente. In questo modo il Server Component mantiene la sua natura, viene renderizzato sul server, e il Client Component lo riceve già come markup pronto da mostrare. Quest'ultima tecnica è particolarmente utile quando hai un componente di layout interattivo (come una sidebar con animazioni o un drawer per il mobile) che deve contenere componenti che accedono al database o leggono dati riservati.

Streaming e Suspense: il vantaggio che si vede in produzione

Un aspetto che cambia profondamente l'esperienza dell'utente finale, seppur sia meno visibile al livello del codice durante lo sviluppo, è l'integrazione tra Server Components e React Suspense per lo streaming dell'HTML.

Con l'App Router puoi andare a avvolgere parti lente della tua pagina in un `` con un fallback, e Next.js invierà al browser prima il markup della pagina con il fallback (un skeleton o un semplice loader), e poi, man mano che i dati arrivano dal server, invierà i blocchi HTML dei componenti che stavano caricando. Di fatto il browser inizia a mostrare contenuto immediatamente, senza aspettare che tutti i dati siano pronti.

Ho visto questo pattern fare una differenza concreta su pagine con più sorgenti di dati indipendenti: una sezione che carica prodotti in evidenza, un'altra che mostra le ultime recensioni, un'altra ancora con statistiche aggregate. Con il vecchio approccio basato su `getServerSideProps`, la pagina aspettava la risposta più lenta prima di mostrare qualsiasi cosa. Con lo streaming, ogni sezione appare non appena i suoi dati sono pronti, e il risultato percepito dall'utente è quello di una pagina molto più reattiva, anche quando la connessione non è delle migliori.

Dal punto di vista del codice, la cosa interessante è che non devi fare nulla di speciale nei componenti: basta che siano `async` (caratteristica possibile soltanto nei Server Components), che facciano `await` sui dati, e React gestirà automaticamente lo streaming in collaborazione con Next.js. Questa combinazione di `async/await` nativi nei componenti è, di fatto, una delle differenze più significative rispetto al mondo delle Pages Router, dove ogni dato asincrono doveva passare per hook dedicati o per le funzioni di fetching dell'App Router.

Quando i Server Components non sono la scelta giusta

Di certo non voglio darti l'impressione che i Server Components siano la risposta a tutto, dal momento che ci sono scenari in cui la loro adozione aggiunge complessità senza un vantaggio reale.

Il primo caso è quello delle applicazioni molto interattive, come dashboard con aggiornamenti in tempo reale, editor collaborativi, o qualsiasi cosa che abbia bisogno di uno stato che cambia frequentemente in risposta all'utente. In questi contesti la maggior parte dei componenti ha bisogno di `useState` o di connessioni WebSocket, dunque finiranno tutti nel bundle client comunque, e il beneficio dei Server Components si riduce considerevolmente. Non significa che non dovresti usarli, ma che la loro presenza nell'architettura sarà limitata ai componenti di scaffolding più esterni.

Il secondo caso riguarda applicazioni già costruite con l'architettura Pages Router di Next.js o con altri framework come Create React App (ormai deprecato, ma ancora molto diffuso in progetti legacy). Migrare una codebase esistente verso l'App Router e i Server Components non è un'operazione banale, dal momento che richiede di ripensare l'intera gestione dello stato e del fetching, e in alcuni casi anche di riscrivere integrazioni con librerie di terze parti che non sono ancora compatibili con il modello RSC. In questo caso, valuta concretamente se i benefici giustificano l'investimento di migrazione, oppure se ha più senso continuare con l'architettura esistente che funziona e porta risultati.

Il terzo caso è quello delle library React: se stai costruendo un componente da pubblicare su npm e destinato a essere usato in contesti diversi, è difficile fare affidamento sui Server Components proprio perché non tutti i progetti che useranno la tua library saranno su Next.js App Router. In questo caso il Client Component rimane la scelta più portabile e compatibile.

Come strutturare un progetto con i Server Components

Nella pratica, dopo aver lavorato su più progetti con l'App Router, mi sono fatto una regola semplice: comincio tutto come Server Component, e passo a Client Component soltanto quando incontro qualcosa che il server non può fare. Questo approccio mi porta quasi sempre a una struttura in cui le foglie dell'albero di componenti (i bottoni, i form, le dropdown, gli elementi interattivi puri) sono Client Components, mentre tutto ciò che riguarda il layout, il fetching e la struttura della pagina rimane sul server.

Un pattern che uso spesso, in particolar modo nei progetti con molte pagine di contenuto come blog o siti istituzionali, è separare la logica di fetching dalla logica di presentazione: un Server Component asincrono si occupa di prendere i dati e li passa come props a un Client Component che li visualizza con animazioni, tooltip o interazioni specifiche. Quest'ultimo approccio mantiene pulita la separazione tra responsabilità, rende più semplice il debugging (sai sempre dove sta il dato e dove sta l'interazione) e, cosa non trascurabile, riduce il rischio di esporre accidentalmente dati o chiavi API al browser per via di una direttiva `"use client"` messa nel posto sbagliato.

Un'altra cosa che faccio sistematicamente è tenere separati i file che contengono la logica di accesso ai dati (query al database, chiamate API) dai componenti React stessi, collocandoli in una cartella `lib/` o `server/` chiaramente dedicata al codice server. Questo mi aiuta a mantenere la distinzione mentale netta anche quando il progetto cresce, dal momento che in un codebase grande è facile perdere traccia di dove gira cosa.

L'impatto reale sulle performance

Hai probabilmente sentito parlare di Core Web Vitals e di quanto Google li usi come segnale di ranking. Tra questi, il Largest Contentful Paint (LCP) misura quanto tempo impiega il contenuto principale della pagina a diventare visibile. Con i Server Components e lo streaming, questo valore migliora in modo misurabile, proprio perché l'HTML arriva al browser in modo progressivo e il contenuto visivo non aspetta il JavaScript.

Nei progetti su cui ho fatto A/B testing tra Pages Router e App Router, ho visto miglioramenti nell'LCP nell'ordine del 30-40% su pagine con contenuto prevalentemente statico o semi-dinamico, ossia esattamente il tipo di pagine che compone la stragrande maggioranza dei siti web aziendali e dei blog. Questo si traduce in un vantaggio concreto sia per l'esperienza dell'utente sia per il posizionamento organico su Google, il che rende i Server Components rilevanti non soltanto dal punto di vista tecnico ma anche da quello del business.

I React Server Components, dunque, non sono una feature da imparare una volta e mettere da parte: sono, di fatto, un cambiamento nel modello mentale con cui si costruisce un'applicazione React moderna. Una volta che hai capito dove gira il codice e perché, il confine tra server e client smette di essere un ostacolo e diventa uno strumento di progettazione architetturale consapevole. E quando quel confine lo gestisci bene, si vede nel prodotto finale, dalle performance all'esperienza utente fino alla manutenibilità nel tempo.

Se stai lavorando su un progetto Next.js con l'App Router e hai dubbi su come strutturare i tuoi componenti o stai valutando una migrazione dall'architettura precedente, possiamo analizzarlo insieme: scrivi dal modulo di contatto e ti rispondo entro 24 ore.

react server componentsnext.js app routerserver components vs client componentsnext.js 16 tutorial
AT

Antonio Tufo

Full-Stack Developer & Interaction Designer. Lavoro con startup e PMI italiane.

Chi sono

Tutti gli articoli

Torna al blog

Hai un progetto da realizzare?

Dalla consulenza al deploy: trasformo le idee in prodotti digitali che funzionano.

Parliamo del tuo progetto

Preferenze Cookie

Scegli i cookie non tecnici

Questo sito utilizza Google Analytics 4 per analizzare il traffico in forma aggregata. I cookie analitici vengono attivati solo con il tuo consenso e puoi modificare la scelta in qualsiasi momento.