È uscito il Corso Java Completo
Torna al blog

Monorepo: cos'è, quando conviene e quando no

Cos'è un monorepo, quali problemi risolve rispetto a repository separati, che strumenti servono e perché per un progetto piccolo è complessità inutile.

Edoardo Midali

Edoardo Midali

Developer · Content Creator

6 min di lettura

Hai un frontend, un backend e un'app mobile che condividono dei tipi e delle funzioni di utilità. Tenerli in tre repository separati significa duplicare codice o pubblicare pacchetti interni; tenerli insieme sembra la soluzione ovvia. È il monorepo — con una serie di conseguenze che conviene conoscere prima di adottarlo.

Cos'è

Un monorepo è un unico repository che contiene più progetti distinti — applicazioni, librerie, servizi — ciascuno con la propria configurazione, ma con una storia e uno strumento di versionamento condivisi.

Va chiarita subito una confusione frequente: monorepo non significa monolite. Sono due dimensioni indipendenti.

  • Un monolite è un'applicazione unica che gira come un blocco solo — vedi monolite vs microservizi.
  • Un monorepo è una scelta su dove sta il codice.

Puoi avere microservizi in un monorepo, e un monolite spalmato su più repository. Sono decisioni separate.

Cosa risolve

I problemi concreti che spingono verso il monorepo:

Il codice condiviso senza attriti. Tipi, componenti, funzioni di utilità usati da più progetti. Senza monorepo le opzioni sono duplicare (e divergere) o pubblicare pacchetti interni (e gestire versioni e rilasci).

Le modifiche coordinate. Cambi l'interfaccia dell'API e aggiorni il client nello stesso commit. Con repository separati sono due proposte di modifica da coordinare, con una finestra in cui le cose non combaciano.

Una versione sola della verità sulle dipendenze. Tutti i progetti usano la stessa versione di una libreria, invece di tre versioni diverse che divergono nel tempo.

Configurazione unificata. Un solo formattatore, un solo linter, una sola configurazione di test.

Visibilità. Chiunque può leggere il codice di qualunque parte del sistema senza dover chiedere accessi.

Cosa costa

E qui sta la parte che va valutata prima.

Servono strumenti. Con più progetti in un repository, npm install alla radice non basta più. Serve un gestore di spazi di lavoro e, sopra una certa dimensione, uno strumento che sappia costruire solo ciò che è cambiato.

Le automazioni diventano complesse. Un invio tocca un progetto, ma i controlli automatici partirebbero su tutti. Servono filtri per percorso e cache, altrimenti ogni piccola modifica lancia venti minuti di verifica — con i costi che descrivo in cosa sono le GitHub Actions.

Il repository cresce. Su progetti molto grandi, le operazioni Git rallentano. Esistono soluzioni (cloni parziali, checkout ridotti) ma sono complessità aggiuntiva.

I permessi sono grossolani. Git non gestisce accessi per cartella: chi può leggere il repository legge tutto. Se serve isolare parti del codice, il monorepo non è adatto.

Il rilascio richiede una scelta. Tutti i progetti alla stessa versione, o versioni indipendenti? Entrambe le strade hanno implicazioni, e vanno decise all'inizio.

Gli strumenti

Senza entrare nei prodotti specifici, servono tre livelli:

1. Gli spazi di lavoro del gestore di pacchetti. La funzione base — presente in npm, pnpm, yarn — che permette a più progetti nello stesso repository di condividere le dipendenze e riferirsi l'uno all'altro. Per un monorepo piccolo, questo da solo basta.

2. Un orchestratore di build. Sa quali progetti dipendono da quali, e quando modifichi qualcosa costruisce e testa solo ciò che è effettivamente coinvolto. È il salto che rende praticabile un monorepo medio.

3. La cache condivisa. Se qualcuno ha già costruito quella versione di un pacchetto, il risultato viene riutilizzato invece di rifare il lavoro. Su team di più persone è ciò che tiene i tempi accettabili.

La progressione sensata: parti dal livello 1, aggiungi il 2 quando i tempi di build diventano un fastidio, il 3 quando siete in tanti. Adottare tutto e tre subito è la ricetta per passare più tempo sulla configurazione che sul prodotto.

Come è fatto

Una struttura tipica:

mio-progetto/
├── apps/
│   ├── web/           # il sito
│   ├── api/           # il backend
│   └── mobile/        # l'app
├── packages/
│   ├── ui/            # componenti condivisi
│   ├── types/         # tipi condivisi
│   └── config/        # configurazioni condivise
├── package.json       # spazi di lavoro
└── README.md

La convenzione diffusa separa apps (cose che si eseguono) da packages (cose che vengono usate dalle altre).

Quando conviene

Sì, se:

  • Hai più progetti che condividono codice in modo sostanziale
  • Le modifiche coordinate tra progetti sono frequenti
  • Il team è unico, o comunque tutti possono vedere tutto
  • Vuoi una configurazione uniforme

No, se:

  • Hai un progetto solo. È il caso più comune, e il monorepo è complessità pura.
  • I progetti sono davvero indipendenti e non condividono nulla
  • Servono permessi differenziati per parti diverse del codice
  • Team diversi lavorano con cicli di rilascio scollegati
  • Nessuno ha tempo di occuparsi degli strumenti

Il caso di gran lunga più frequente in cui il monorepo ha senso per un progetto piccolo: frontend e backend che condividono i tipi. Se stai già copiando le definizioni delle API da una parte all'altra, quello è il segnale.

Un'alternativa spesso trascurata

Prima di adottare un monorepo, vale la pena considerare la via di mezzo: repository separati con un pacchetto condiviso pubblicato su un registro privato.

Costa la gestione dei rilasci del pacchetto, ma mantiene i progetti indipendenti — e per molti team con cicli di lavoro diversi è la soluzione più sensata.

Il criterio: se le modifiche coordinate sono rare, il pacchetto condiviso basta. Se sono settimanali, il monorepo ripaga.

Errori comuni

Adottarlo troppo presto. Con un progetto solo, tutti i costi e nessun beneficio.

Non filtrare i controlli automatici. Se ogni modifica lancia la verifica di tutto, il monorepo diventa un fastidio quotidiano. È la prima cosa da configurare.

Mescolare tutto. Un monorepo non è un contenitore dove buttare progetti scollegati: se non condividono nulla, non c'è ragione di tenerli insieme.

Dipendenze circolari tra pacchetti. Il pacchetto A usa B che usa A. Va evitato per costruzione, con una gerarchia chiara.

Non decidere la strategia di versionamento all'inizio. Cambiarla dopo è laborioso — e il tema si lega a conventional commits e semantic versioning.

In sintesi

Un monorepo tiene più progetti in un unico repository con una storia condivisa. Non ha nulla a che vedere con l'essere un monolite: sono decisioni indipendenti.

Risolve bene due problemi reali: il codice condiviso senza attriti e le modifiche coordinate in un solo commit. In cambio richiede strumenti, automazioni filtrate e una scelta esplicita sul versionamento.

Per un progetto solo è complessità inutile. Il caso in cui conviene davvero a un team piccolo è quando frontend e backend condividono tipi o componenti — se stai già copiando definizioni da una parte all'altra, il segnale c'è.

E la progressione giusta è graduale: spazi di lavoro del gestore di pacchetti prima, orchestratore quando i tempi diventano un fastidio, cache condivisa quando siete in tanti.