# load server vs universal in SvelteKit: chi gira dove

In SvelteKit +page.server.ts esegue load solo sul server, +page.ts anche nel browser: la scelta dipende da cosa il dato tocca e da quante volte lo paghi.

> Pagina: https://ui.eneawork.it/blog/sveltekit-load-server-vs-universal
> Markdown: https://ui.eneawork.it/blog/sveltekit-load-server-vs-universal.md

*2026-11-01*

In SvelteKit +page.server.ts esegue load solo sul server, mentre +page.ts esegue lo stesso codice sul server durante il render e nel browser a ogni navigazione: la scelta dipende da cosa il dato tocca.

## Due file, due contratti

Il suffisso .server tiene il modulo fuori dal bundle del browser: lì puoi importare il database e leggere variabili d’ambiente private. Il file universale finisce nel browser, quindi niente segreti e niente driver.

npx sv check

// src/routes/orders/+page.server.ts import { db } from "$lib/server/db"; export const load = async () => { const orders = await db.order.findMany({ take: 20 }); return { orders }; };

Nel file universale ricevi fetch, params, url e depends: la fetch è quella di SvelteKit, che inoltra i cookie e deduplica le richieste durante il render.

// src/routes/products/+page.ts export const load = async ({ fetch, depends }) => { depends("app:products"); const res = await fetch("/api/products"); return { products: await res.json() }; };

## Il dato deve attraversare il confine

Quello che load restituisce viene serializzato: numeri, stringhe, array, Date e Map passano, un’istanza di classe o una connessione al database no. L’errore arriva in build o al primo render, non dove lo cerchi.

## Come scegliere

Misurato il 1 novembre 2026: i 1.556 blocchi del catalogo distribuiscono 2.116 file su 99 categorie, quindi una pagina che carica un blocco intero porta con sé più file. Metodo: conteggio dei campi blocks, files e categories di data/blocks.json con uno script Node, sul repository EneUI.

## Il limite da mettere in conto

Il load universale viene eseguito due volte: sul server per l’HTML iniziale e nel browser quando navighi. Una fetch lenta lì costa due volte, e un load server che restituisce molta roba scrive tutto nell’HTML e nella cache del client.

## Errori che si vedono

Nel catalogo i dati arrivano in tabelle già pronte: table raccoglie i componenti, il blocco table porta le righe, e svelte-bits si installa come sorgente per il resto della pagina. Le azioni di form sono in form actions in SvelteKit, i file di rotta in routing e layout in SvelteKit, la sessione in hook per l’autenticazione, il confronto in Svelte vs React.

## FAQ

### Posso usare entrambi nella stessa rotta?

Sì, ma solo uno dei due restituisce dati alla pagina: se esistono entrambi, il load universale riceve il risultato del load server in data e non può sovrascriverlo. Tieni il server per i dati e l’universale per ciò che dipende dal browser.

### Perché la fetch nel load universale è meglio di quella globale?

Perché quella fornita da SvelteKit inoltra i cookie durante il render sul server e deduplica le richieste identiche. La fetch globale non sa nulla della richiesta in corso e non può farlo.

### Il load server gira anche nelle navigazioni client?

Sì. Sul client SvelteKit chiama un endpoint interno generato per la rotta, quindi il codice resta sul server ma il risultato arriva comunque. Per questo una query lenta si sente anche dopo il primo caricamento.

### Dove metto il codice condiviso?

In $lib. Se tocca il database o i segreti va in $lib/server, che la build rifiuta di importare da un modulo destinato al browser. Il resto può stare in $lib senza suffisso.

### Perché ottengo un errore di serializzazione?

Perché il valore restituito contiene qualcosa che non sopravvive al trasporto, come una funzione, una classe o un BigInt non gestito. Restituisci dati semplici e ricostruisci l’oggetto nel componente.
