Next.js con API Laravel: architettura SSR per applicazioni marketing e e-commerce
A ottobre 2024 un cliente del settore retail online mi ha chiamato con un problema che non era di performance ma di visibilità: il suo e-commerce - 50.000 prodotti, backend Laravel 11 con API REST, frontend React 18 come single-page application - generava 2,1 milioni di euro di fatturato annuo, ma il traffico organico da Google era in calo costante da sei mesi. L'analisi di Google Search Console raccontava una storia inequivocabile: delle 50.000 pagine prodotto che il sito avrebbe dovuto avere indicizzate, Google ne vedeva 8.200. Il motivo era strutturale: la SPA React caricava una pagina HTML vuota con un bundle JavaScript da 1,4 MB, e il rendering del contenuto avveniva interamente nel browser. Googlebot eseguiva il JavaScript nella maggior parte dei casi, ma con latenze di indicizzazione di settimane e una coverage incompleta - i prodotti aggiunti al catalogo impiegavano 15-25 giorni per apparire nei risultati di ricerca, e un quarto delle pagine non veniva mai indicizzato perché il rendering JavaScript falliva per timeout.
La soluzione non era riscrivere il backend - Laravel funzionava perfettamente e l'API REST era ben progettata. La soluzione era sostituire il frontend React SPA con Next.js, il framework React di Vercel che supporta nativamente il server-side rendering (SSR) e l'Incremental Static Regeneration (ISR). Con ISR, le pagine prodotto vengono pre-renderizzate in HTML statico al primo accesso e rigenerate in background a intervalli configurabili - il risultato è una pagina che Google può indicizzare istantaneamente (HTML statico, zero JavaScript richiesto per il contenuto), che si carica in meno di un secondo per l'utente (HTML pre-renderizzato + hydration React), e che resta aggiornata con i dati del catalogo senza rebuild completi. In tre mesi dal go-live del nuovo frontend, il traffico organico è aumentato del 40% e le pagine indicizzate sono passate da 8.200 a 47.300.
Perché un frontend Next.js con un backend Laravel e non un monolite full-stack?
La risposta è che questa architettura ha senso solo quando hai entrambi i requisiti: un backend Laravel che funziona bene e che non vuoi riscrivere, e un frontend che deve avere SEO ottimizzato su migliaia di pagine pubbliche. Se il tuo sito è un gestionale dietro login (SEO irrilevante), usa Inertia.js o Livewire come ho descritto in altri articoli - sono più semplici, più economici da mantenere, e non richiedono un team con competenze React. Se invece hai un e-commerce con un catalogo di migliaia di prodotti, un blog con centinaia di articoli, o un portale marketing che deve posizionarsi su Google e sugli answer engine AI, allora Next.js con SSR/ISR è la scelta architetturale che produce il ROI più alto sul traffico organico.
L'architettura è a due layer: il backend Laravel espone un'API REST (che probabilmente hai già se usi una SPA React o Vue), e il frontend Next.js consuma quell'API per generare le pagine HTML. Le due applicazioni sono deployment separati - il backend su un VPS Hetzner o OVH come sempre, il frontend su Vercel (la scelta più semplice perché Vercel è costruito per Next.js) o su un VPS Node.js separato. Nel mio profilo professionale trovi il dettaglio dell'esperienza multi-stack che porto in queste architetture - la scelta dello strumento giusto per ogni componente è ciò che distingue un progetto che scala da un progetto che accumula complessità inutile.
ISR in pratica: pagine statiche che si aggiornano da sole
La funzionalità killer di Next.js per un e-commerce è l'Incremental Static Regeneration. Il concetto è questo: la prima volta che un utente (o Googlebot) visita una pagina prodotto, Next.js chiama l'API Laravel per ottenere i dati del prodotto, renderizza la pagina in HTML statico, la salva in cache, e la serve. Tutte le visite successive alla stessa pagina servono l'HTML dalla cache - zero chiamate all'API, zero rendering, latenza di millisecondi. In background, Next.js rigenera la pagina a intervalli configurabili (nel nostro caso, ogni 60 secondi), così che le modifiche al catalogo (prezzo aggiornato, disponibilità cambiata, descrizione modificata) vengono riflesse nella pagina senza un rebuild manuale.
// pages/prodotti/[slug].tsx - Pagina prodotto con ISR
import { GetStaticPaths, GetStaticProps } from 'next'
interface ProdottoProps {
prodotto: {
nome: string
slug: string
prezzo: number
descrizione: string
disponibile: boolean
immagini: string[]
}
}
// Genera i path statici per i prodotti più popolari
export const getStaticPaths: GetStaticPaths = async () => {
// Pre-genera solo i 500 prodotti più visitati
// Gli altri vengono generati on-demand al primo accesso
const res = await fetch(`${process.env.LARAVEL_API}/api/prodotti/top-500`)
const prodotti = await res.json()
return {
paths: prodotti.map((p: any) => ({ params: { slug: p.slug } })),
fallback: 'blocking', // Genera on-demand se non pre-generato
}
}
// Fetch dati dal backend Laravel con ISR a 60 secondi
export const getStaticProps: GetStaticProps = async ({ params }) => {
const res = await fetch(
`${process.env.LARAVEL_API}/api/prodotti/${params?.slug}`
)
if (!res.ok) {
return { notFound: true }
}
const prodotto = await res.json()
return {
props: { prodotto },
revalidate: 60, // Rigenera la pagina ogni 60 secondi
}
}
export default function PaginaProdotto({ prodotto }: ProdottoProps) {
return (
<article>
<h1>{prodotto.nome}</h1>
<p className="prezzo">€{prodotto.prezzo.toFixed(2)}</p>
<div dangerouslySetInnerHTML={{ __html: prodotto.descrizione }} />
{prodotto.disponibile ? (
<button>Aggiungi al carrello</button>
) : (
<p>Prodotto non disponibile</p>
)}
</article>
)
}Il parametro revalidate: 60 è il cuore dell'ISR: dice a Next.js "dopo 60 secondi dalla generazione, la prossima richiesta a questa pagina triggera una rigenerazione in background." L'utente che arriva durante la rigenerazione vede la versione cached (non aspetta il rendering), e il prossimo utente vede la versione aggiornata. Per un catalogo e-commerce dove i prezzi cambiano poche volte al giorno, 60 secondi è un intervallo perfetto - abbastanza frequente da mostrare dati attuali, abbastanza raro da non sovraccaricare l'API Laravel con richieste di rendering.
Il fallback: 'blocking' gestisce i prodotti che non sono stati pre-generati: la prima richiesta viene renderizzata server-side (con un tempo di attesa visibile per l'utente), e da quel momento la pagina è in cache come tutte le altre. Questo pattern permette di pre-generare solo i 500 prodotti più visitati (build time di 3-4 minuti) e lasciare che i restanti 49.500 vengano generati on-demand - un compromesso tra build time e user experience che funziona molto bene per cataloghi grandi.
SEO e dati strutturati: dove Next.js batte qualsiasi SPA
Il vantaggio SEO di Next.js non si limita al rendering HTML. Con il server-side rendering, hai il controllo completo sui meta tag, sull'Open Graph, sullo schema markup e sulle informazioni strutturate prima che la pagina arrivi al browser o al crawler. In una SPA React tradizionale, i meta tag vengono impostati dal JavaScript dopo il caricamento - il che significa che i crawler che non eseguono JavaScript (la maggior parte dei bot dei social network, alcuni crawler di Bing, e i crawler degli answer engine AI come Perplexity) vedono solo i meta tag di default, non quelli specifici del prodotto.
Con Next.js, ogni pagina prodotto ha i propri meta tag renderizzati nel HTML statico, con il titolo del prodotto, la descrizione, il prezzo, la disponibilità e l'immagine principale già presenti nel <head> della pagina. Lo schema markup Product (JSON-LD) viene generato dal server a partire dai dati dell'API Laravel e incluso nell'HTML - Google lo parsa istantaneamente e lo mostra come rich snippet nei risultati di ricerca, con prezzo, disponibilità e rating visualizzati direttamente nella SERP. Sul cliente e-commerce, l'introduzione dei rich snippet ha aumentato il click-through rate delle pagine prodotto del 18% - un incremento significativo ottenuto senza nessuna modifica al backend, semplicemente rendendo disponibili nel markup HTML le informazioni che la SPA React nascondeva nel JavaScript.
Un altro aspetto critico è la gestione del sitemap.xml dinamico. Con 50.000 prodotti, la sitemap deve essere generata automaticamente e aggiornata quotidianamente per segnalare a Google i prodotti nuovi, modificati o rimossi. Next.js supporta la generazione server-side della sitemap: un endpoint che chiama l'API Laravel per la lista completa dei prodotti e genera il XML al volo, con lastmod basato sulla data di ultimo aggiornamento del prodotto nel database. Questa sitemap viene rigenerata ogni ora e sottomessa automaticamente a Google Search Console - un livello di automazione SEO che in una SPA React richiederebbe un servizio separato.
Autenticazione cross-domain: il problema che nessun tutorial copre bene
Quando il frontend Next.js e il backend Laravel vivono su domini diversi (ad esempio shop.esempio.it e api.esempio.it), l'autenticazione diventa significativamente più complessa rispetto a un monolite. Le session cookie di Laravel non funzionano cross-domain per default (SameSite policy), e la soluzione standard - token JWT nel localStorage - è un antipattern di sicurezza che OWASP sconsiglia esplicitamente perché qualsiasi script XSS può leggere il localStorage.
La soluzione che implemento è Laravel Sanctum con cookie SameSite configurato correttamente per il dominio condiviso. Se frontend e API condividono lo stesso dominio di secondo livello (es. shop.esempio.it e api.esempio.it), Sanctum può emettere cookie con domain=.esempio.it che sono accessibili da entrambi i sottodomini. La configurazione richiede tre passaggi: primo, configurare Sanctum per i cookie con SANCTUM_STATEFUL_DOMAINS=shop.esempio.it e SESSION_DOMAIN=.esempio.it nel .env di Laravel; secondo, configurare CORS nel backend per accettare richieste dal frontend (allowed_origins: ['https://shop.esempio.it']); terzo, configurare Next.js per inviare le credenziali (cookie) con ogni richiesta all'API usando credentials: 'include' nel fetch.
Per il cliente e-commerce, l'autenticazione è necessaria solo per il checkout e l'area account - il 90% delle pagine (catalogo, pagine prodotto, blog) sono pubbliche e non richiedono autenticazione. Questa separazione è un vantaggio architetturale: le pagine pubbliche sono servite come HTML statico dalla cache di ISR senza nessuna interazione con il backend, e solo il checkout e l'account fanno richieste autenticate all'API Laravel.
Deployment: Vercel, VPS Node.js o Docker
Il deployment del frontend Next.js offre tre opzioni con trade-off diversi. Vercel è la scelta più semplice: push su GitHub, build automatica, deployment globale su edge network con ISR gestito nativamente. Il costo per un e-commerce con 50.000 pagine è nel piano Pro a 20 dollari al mese - un prezzo ragionevole per la zero-maintenance. Il limite è il vendor lock-in: alcune funzionalità di Next.js (middleware edge, image optimization) funzionano meglio o solo su Vercel, e migrare a un'altra piattaforma richiede lavoro. L'alternativa self-hosted è un VPS Node.js su Hetzner con il server Next.js standalone - il costo è inferiore (un CPX11 da 4,15 euro al mese è sufficiente per un sito con 1.000 visite al giorno), ma la gestione di TLS, reverse proxy Nginx, processo manager PM2 e aggiornamenti è responsabilità tua. Per il cliente e-commerce, ho scelto Vercel per il frontend (velocità di deploy, ISR nativo, CDN globale) e il VPS Hetzner esistente per il backend Laravel - un'architettura ibrida che ottimizza ogni componente sulla piattaforma più adatta.
Il risultato a tre mesi dal go-live: pagine indicizzate da 8.200 a 47.300, traffico organico +40%, tempo di caricamento medio delle pagine prodotto da 3,2 secondi (SPA React con client-side rendering) a 0,8 secondi (HTML statico ISR), e un aumento del tasso di conversione del 12% attribuibile alla velocità di caricamento - confermando i dati di Google che correlano ogni 100 ms di latenza in più con una riduzione dell'1% delle conversioni. Il backend Laravel non è stato toccato: l'API REST che alimentava la vecchia SPA alimenta il nuovo frontend Next.js senza modifiche. Se gestisci un e-commerce o un portale marketing con un backend Laravel e il tuo frontend SPA non viene indicizzato correttamente da Google, contattami per valutare l'introduzione di Next.js con ISR: in una giornata di analisi verifichiamo la coverage di indicizzazione attuale, stimiamo l'impatto del SSR sul traffico organico, e definiamo un piano di migrazione del frontend che non tocca il backend.