# Structuring a Nuxt 3 project: folders and boundaries

In Nuxt 3 folders are APIs: pages, server and composables change behaviour. A structure that says where each file belongs.

> Page: https://ui.eneawork.it/blog/nuxt-3-struttura-progetto
> Markdown: https://ui.eneawork.it/blog/nuxt-3-struttura-progetto.md

*2026-11-01*

In Nuxt 3 la struttura del progetto è configurazione: ogni cartella con un nome riservato attiva un comportamento, quindi spostare un file cambia l’app. La regola utile è tenere pages/ per le rotte, server/ per il codice che il client non deve vedere e composables/ per lo stato condiviso.

Il pacchetto nuxt ha 3.328.960 download settimanali nella settimana 23-29 ottobre 2026, letto da api.npmjs.org il 1 novembre 2026. Il catalogo EneUI misura 111.985 componenti, 1.556 blocchi, 12.808 icone da 1.472 librerie, letti da /api/stats il 1 novembre 2026. Ogni comando qui sotto gira in locale, senza account.

## Le cartelle che cambiano il comportamento

Il suffisso del plugin decide il confine: .client.ts gira solo nel browser, .server.ts solo su Node. Senza suffisso gira in entrambi, e un accesso a window rompe la build.

## Un albero che regge

app.vue pages/ index.vue blog/[slug].vue layouts/ default.vue components/ ui/ # primitive: button, input, dialog app/ # composizioni legate a una pagina composables/ useSession.ts server/ api/posts.get.ts utils/db.ts middleware/auth.ts nuxt.config.ts

I componenti in sottocartella prendono il nome dalla cartella: components/ui/Button.vue diventa <UiButton />. È la causa più frequente di «componente non trovato» dopo uno spostamento.

## Server e client: due mondi, un repository

// server/api/posts.get.ts export default defineEventHandler(async (event) => { const limit = Number(getQuery(event).limit ?? 10); return await db.post.findMany({ take: limit }); });

Il codice in server/ non finisce nel bundle del browser. Una chiamata al database dentro un componente client non è un errore di sintassi: è un errore a runtime, quando la build prova a includerla.

## Errori che costano tempo

Lo stesso confine server/client vale negli altri framework: le form actions di SvelteKit funzionano proprio perché il codice di scrittura non arriva al browser.

## Il limite noto

L’auto-import riduce le righe e nasconde le dipendenze. In un progetto con più team conviene disattivarlo per i componenti e importarli a mano, oppure accettare che la ricerca del simbolo passi dall’estensione dell’editor e non dal file.

## Comandi

npx nuxi prepare npx nuxi dev

Dal catalogo: shadcn-vue, l’icona Nuxt e il blocco logo Vue. Le guide: le librerie UI per Vue 3 e le guardie di Vue Router; il confronto: Vue contro React nel 2026.

## FAQ

### Dove va app.vue in Nuxt 3?

Nella radice del progetto, accanto a nuxt.config.ts. Da Nuxt 4 il codice dell’app vive in app/ e app.vue si sposta dentro quella cartella.

### La cartella pages è obbligatoria?

No. Senza pages l’app usa app.vue come unica pagina. La cartella serve quando vuoi le rotte generate dal file system.

### Perché il mio componente non viene trovato?

Il nome include la sottocartella: components/ui/Button.vue si usa come UiButton. Sposta il file in components/ se vuoi il nome breve.

### Posso usare server/utils in un componente?

No. Quel codice è compilato per il server e non entra nel bundle del browser; estrai la parte condivisa in utils/ o in un pacchetto.

### Come disattivo l’auto-import?

In nuxt.config.ts imposta imports.autoImport a false per le API e components a false per i componenti, poi importa tutto a mano.
