# Cannot find module after `shadcn add`: the aliases are the problem

The file is added, but TypeScript cannot find it. Usually the alias in components.json does not match tsconfig, or a runtime dependency is missing.

> Page: https://ui.eneawork.it/blog/cannot-find-module-dopo-shadcn-add
> Markdown: https://ui.eneawork.it/blog/cannot-find-module-dopo-shadcn-add.md

*2026-11-01*

Risposta breve: il componente è stato scritto, ma l'import usa un alias che TypeScript non conosce. Confronta components.json con tsconfig.json: se gli alias non coincidono, il file esiste e non viene risolto.

La domanda non ha un punteggio alto dedicato; la misura utile è il perimetro: 1.472 librerie e 111.985 componenti indicizzati da EneUI il 1 novembre 2026, quasi tutti distribuiti con alias configurabili. Le cifre del catalogo EneUI, misurate da /api/stats il 1 novembre 2026, sono 111.985 componenti, 1.556 blocchi, 12.808 icone da 1.472 librerie. Ogni comando qui sotto è eseguibile in locale: nessun passaggio richiede un account.

## Perché il file c'è e il compilatore non lo vede

Le due parti prendono decisioni indipendenti. Il CLI scrive il file dove dice aliases, cioè nel punto che l'autore della ricetta ha scelto. TypeScript costruisce il programma da include e rootDir, e risolve gli alias con paths relativo a baseUrl. Se il file finisce fuori da include, tsc non lo legge affatto e l'errore che stampa è Cannot find module, non not part of the project: la diagnosi parte dal messaggio sbagliato, e per questo la correzione di solito tocca l'alias quando il problema era il perimetro.

## Le quattro cause

## Confronto diretto

// components.json { "$schema": "https://ui.shadcn.com/schema.json", "aliases": { "components": "@/components", "utils": "@/lib/utils", "ui": "@/components/ui" } }

// tsconfig.json { "compilerOptions": { "baseUrl": ".", "paths": { "@/*": ["./src/*"] } } }

Se components.json dice @/components e tsconfig mappa @/* su ./src/*, il file finisce in src/components e l'import funziona. Se uno dei due usa ~/, il file viene scritto in un posto e cercato in un altro.

## La sequenza di verifica

## Il comando che dice dove guarda TypeScript

# ogni tentativo di risoluzione, con il percorso cercato npx tsc --noEmit --traceResolution | grep "button" # PowerShell npx tsc --noEmit --traceResolution | Select-String "button"

L'output è lungo e utile: per ogni import elenca i candidati nell'ordine in cui paths li propone, e chiude con la riga che dice se ha risolto. Cerca la prima riga not resolved e leggi il percorso che ha provato. Se il percorso è giusto e il file non c'è, il CLI ha scritto altrove; se il percorso è sbagliato, l'alias è sbagliato. In entrambi i casi il file di configurazione da aprire è deciso dall'output, non dall'intuito.

## Quando la correzione non funziona

Se l'alias è corretto e l'errore resta, il problema può essere il resolver del bundler: Vite e Next.js leggono paths in modo diverso e alcuni setup richiedono anche vite-tsconfig-paths. Controlla che il file di configurazione del bundler estenda lo stesso tsconfig. Nei monorepo, un pacchetto può avere il proprio tsconfig e ignorare quello della root.

## Quando la correzione tipica peggiora le cose

La correzione che si trova nei forum è aggiungere un secondo schema ai paths: "@/*": ["./src/*", "./*"], così qualunque posizione funziona. Funziona per il caso di oggi e introduce due sorgenti valide per lo stesso nome. TypeScript prende il primo che esiste, il bundler può prendere l'altro, e il progetto inizia a compilare contro una copia vecchia di un componente rimasta nella root da un init precedente. La build passa, la pagina mostra il componente sbagliato, e il sintomo somiglia a una cache. È l'unico caso di questa lista in cui il rosso sparisce e il difetto resta.

## Il limite dell'allineamento

Un limite da dichiarare: allineare gli alias risolve la risoluzione, non il contratto della ricetta. Il CLI non riscrive import arbitrari dentro il codice che copia, quindi una ricetta di terze parti può importare un percorso che nel tuo progetto non esiste, o esiste con un altro nome. Il componente compila e manca un pezzo. Dopo ogni add la verifica completa è due comandi, non uno: il controllo dei tipi e l'apertura della pagina.

## Come prevenirlo

## Dove continuare

Per capire il sistema: componenti, temi, blocchi e blocco newsletter. Le guide: temi gratuiti e premium e struttura App Router; il confronto: registry privati, token e namespace.

## FAQ

### Il file esiste ma l'import è rosso: cosa controllo?

Apri `components.json`, guarda `aliases.components` e `aliases.utils`, poi confrontali con `compilerOptions.paths` in tsconfig. Devono descrivere lo stesso percorso.

### Perché funziona con Vite e non con Next.js?

I due progetti hanno alias iniziali diversi e un tsconfig diverso. La ricetta usa l'alias dichiarato in components.json: se manca, applica quello di default.

### Devo riavviare il dev server?

Per un file nuovo spesso sì, perché il resolver tiene una cache dei percorsi. Se dopo il riavvio resta rosso, il problema è di configurazione, non di cache.

### Cosa significa `Missing dependency` nell'output?

Che la ricetta importa un pacchetto non presente nel progetto. Installa quello che il comando elenca, poi riprova.

### Posso spostare i componenti fuori da `src`?

Sì, ma aggiorna alias e `content` di Tailwind insieme. Spostare solo i file produce componenti che esistono e non vengono stilizzati.
