[{"data":1,"prerenderedAt":27},["ShallowReactive",2],{"articolo-monorepo-flutter-con-melos-gestire-piu-app-e-pacchetti-in-un-solo-repository":3,"comments-article-monorepo-flutter-con-melos-gestire-piu-app-e-pacchetti-in-un-solo-repository":26},{"id":4,"title":5,"slug":6,"excerpt":7,"body":8,"cover_image":9,"cover_remote_url":10,"cover_credit":11,"video_url":15,"status":16,"published_at":17,"meta_title":18,"meta_description":19,"category":20,"author":24},79,"Monorepo Flutter con Melos: gestire più app e pacchetti in un solo repository","monorepo-flutter-con-melos-gestire-piu-app-e-pacchetti-in-un-solo-repository","Come organizzare app e pacchetti condivisi in un unico repository con Melos: bootstrap, script, filtri, versionamento automatico con Conventional Commits e integrazione con i pub workspaces di Dart 3.6.","## Perché un monorepo\n\nQuando un progetto Flutter cresce, prima o poi ci si ritrova con più artefatti da mantenere: l'app mobile, magari una variante \"admin\", un design system condiviso, un client HTTP, un pacchetto di modelli di dominio. Tenerli in repository separati significa gestire pubblicazioni, tag di versione e allineamento delle dipendenze a mano, con il rischio classico: la modifica al pacchetto `core` rompe l'app e ce ne accorgiamo tre giorni dopo.\n\nIl **monorepo** risolve il problema mettendo tutto sotto lo stesso versionamento Git: una singola PR può modificare contemporaneamente il pacchetto condiviso e le app che lo usano, e la CI valida il tutto insieme. Il prezzo da pagare è la gestione operativa: eseguire `flutter pub get` in dieci cartelle, lanciare i test ovunque, tenere in ordine i changelog. È esattamente qui che entra in gioco **Melos**.\n\n## Che cos'è Melos\n\nMelos è un CLI scritto in Dart (mantenuto da Invertase) che orchestra monorepo Dart e Flutter. In sintesi fa quattro cose:\n\n- **collega i pacchetti locali** tra loro senza dover scrivere a mano decine di `path:` nelle dipendenze;\n- **esegue comandi in parallelo** su tutti i pacchetti, con filtri potenti;\n- **gestisce versioni e changelog** a partire dai Conventional Commits;\n- **pubblica** i pacchetti pubblici su pub.dev.\n\nInstallazione globale:\n\n```bash\ndart pub global activate melos\nmelos --version\n```\n\n## Struttura tipica di un workspace\n\n```\nmy_workspace\u002F\n├── melos.yaml\n├── pubspec.yaml            # root (publish_to: none)\n├── apps\u002F\n│   ├── mobile\u002F             # app Flutter principale\n│   └── admin\u002F              # seconda app Flutter\n└── packages\u002F\n    ├── core_models\u002F        # pacchetto Dart puro\n    ├── core_network\u002F       # client HTTP condiviso\n    └── design_system\u002F      # widget e tema condivisi\n```\n\nLa regola pratica: dentro `packages\u002F` mettiamo codice **riutilizzabile e senza dipendenze dalle app**, dentro `apps\u002F` gli eseguibili. Un pacchetto Dart puro (senza `flutter`) si testa più velocemente e si riusa anche lato backend o CLI.\n\n## Il file melos.yaml\n\nÈ il cuore della configurazione:\n\n```yaml\nname: my_workspace\n\npackages:\n  - apps\u002F**\n  - packages\u002F**\n\nignore:\n  - \"**\u002Fexample\u002F**\"\n\ncommand:\n  bootstrap:\n    # dipendenze applicate a TUTTI i pacchetti del workspace\n    environment:\n      sdk: \">=3.5.0 \u003C4.0.0\"\n      flutter: \">=3.24.0\"\n    dependencies:\n      collection: ^1.18.0\n    dev_dependencies:\n      very_good_analysis: ^6.0.0\n  version:\n    linkToCommits: true\n    workspaceChangelog: true\n    branch: main\n    message: \"chore(release): publish packages\\n\\n{new_package_versions}\"\n```\n\nDue punti importanti:\n\n- la sezione `command.bootstrap.dependencies` permette di **centralizzare le versioni** delle dipendenze comuni: Melos le scrive nei `pubspec.yaml` dei pacchetti durante il bootstrap, evitando derive di versione tra un pacchetto e l'altro;\n- `ignore` esclude cartelle che non vogliamo trattare come pacchetti (tipicamente gli `example` dei plugin).\n\n> Da Melos 6.x la configurazione può vivere anche direttamente nel `pubspec.yaml` di root sotto la chiave `melos:`, utile se preferite un file in meno.\n\n## Bootstrap: il comando che userete ogni giorno\n\n```bash\nmelos bootstrap   # oppure: melos bs\n```\n\n`bootstrap` esegue il `pub get` su tutti i pacchetti e, soprattutto, **collega i pacchetti locali** generando un file `pubspec_overrides.yaml` in ciascuna cartella:\n\n```yaml\n# packages\u002Fdesign_system\u002Fpubspec_overrides.yaml (generato da Melos)\ndependency_overrides:\n  core_models:\n    path: ..\u002Fcore_models\n```\n\nIl vantaggio rispetto ai vecchi override scritti a mano è che il `pubspec.yaml` resta **pulito e pubblicabile**: dentro dichiarate la versione reale (`core_models: ^1.2.0`), mentre in locale lavorate sempre sul codice del repository. Ricordatevi di aggiungere a `.gitignore`:\n\n```\npubspec_overrides.yaml\n```\n\nNel codice non cambia nulla: gli import restano quelli di un normale pacchetto.\n\n```dart\nimport 'package:core_models\u002Fcore_models.dart';\nimport 'package:design_system\u002Fdesign_system.dart';\n\nclass ProductTile extends StatelessWidget {\n  const ProductTile({required this.product, super.key});\n\n  final Product product; \u002F\u002F definito in core_models\n\n  @override\n  Widget build(BuildContext context) {\n    return DsCard(   \u002F\u002F widget del design system condiviso\n      title: product.name,\n      subtitle: product.formattedPrice,\n    );\n  }\n}\n```\n\n## Script: automatizzare i task ripetitivi\n\nLa sezione `scripts` trasforma Melos in un piccolo task runner condiviso da tutto il team.\n\n```yaml\nscripts:\n  analyze:\n    description: Analisi statica su tutti i pacchetti\n    run: melos exec -c 5 -- dart analyze . --fatal-infos\n\n  format:\n    run: dart format --set-exit-if-changed .\n\n  test:\n    description: Test unitari e widget\n    run: melos exec -c 4 --dir-exists=test -- flutter test --coverage\n\n  gen:\n    description: build_runner sui pacchetti che lo usano\n    run: melos exec -c 1 --depends-on=build_runner -- \\\n      dart run build_runner build --delete-conflicting-outputs\n\n  ci:\n    description: Pipeline locale completa\n    run: melos run format && melos run analyze && melos run test\n```\n\nEsecuzione:\n\n```bash\nmelos run analyze\nmelos run test\nmelos run gen\n```\n\nAlcune opzioni utili di `melos exec`:\n\n- `-c N` \u002F `--concurrency N`: quanti pacchetti in parallelo (usate `-c 1` per i comandi che scrivono file, come `build_runner`);\n- `--fail-fast`: interrompe al primo errore;\n- `--order-dependents`: rispetta l'ordine del grafo delle dipendenze.\n\n## Filtri: lavorare solo su ciò che serve\n\nSu un monorepo grande, rieseguire tutto è uno spreco. Melos offre filtri combinabili:\n\n```bash\n# solo il design system\nmelos exec --scope=\"design_system\" -- flutter test\n\n# tutto tranne le app\nmelos exec --ignore=\"apps\u002F**\" -- dart analyze .\n\n# solo i pacchetti che dipendono da core_models\nmelos exec --depends-on=\"core_models\" -- flutter test\n\n# solo i pacchetti modificati rispetto a main (perfetto in CI)\nmelos exec --diff=origin\u002Fmain -- flutter test\n\n# solo i pacchetti pubblicabili\nmelos exec --no-private -- dart pub publish --dry-run\n```\n\nIl filtro `--diff` è quello che fa davvero la differenza sui tempi di build: nella PR eseguite i test solo sui pacchetti toccati **e sui loro dipendenti**.\n\n## Versionamento e changelog automatici\n\nMelos legge i **Conventional Commits** e calcola le nuove versioni:\n\n```\nfeat(core_network): aggiunge interceptor di retry\nfix(design_system): corregge il padding di DsCard\nrefactor(core_models)!: rinomina Product.price in Product.amount\n```\n\n- `fix:` → bump patch\n- `feat:` → bump minor\n- `!` o `BREAKING CHANGE:` → bump major\n\nPoi basta:\n\n```bash\nmelos version           # calcola versioni, aggiorna CHANGELOG, crea commit e tag\nmelos version --dry-run # anteprima senza scrivere nulla\nmelos publish           # dry-run di default; --no-dry-run per pubblicare davvero\n```\n\nMelos propaga automaticamente il bump ai pacchetti dipendenti: se `core_models` passa a `2.0.0`, i vincoli in `design_system` e nelle app vengono aggiornati e viene generata anche una voce di changelog \"dependency update\". Con `workspaceChangelog: true` ottenete inoltre un `CHANGELOG.md` di root con il riepilogo della release.\n\nSe i pacchetti non vanno su pub.dev, ricordatevi `publish_to: none` nei loro `pubspec.yaml`: Melos li tratterà come privati e li escluderà dalla pubblicazione pur continuando a versionarli.\n\n## Melos e i pub workspaces di Dart 3.6\n\nDa Dart 3.6 il tool `pub` supporta nativamente i **workspaces**: una sola risoluzione delle dipendenze e un unico `.dart_tool\u002Fpackage_config.json` per l'intero repository, con `pub get` molto più rapido. Si configura così nel `pubspec.yaml` di root:\n\n```yaml\nname: my_workspace\npublish_to: none\nenvironment:\n  sdk: ^3.6.0\nworkspace:\n  - apps\u002Fmobile\n  - apps\u002Fadmin\n  - packages\u002Fcore_models\n  - packages\u002Fcore_network\n  - packages\u002Fdesign_system\n```\n\nE in ogni pacchetto figlio:\n\n```yaml\nname: core_models\nenvironment:\n  sdk: ^3.6.0\nresolution: workspace\n```\n\nI due strumenti non sono alternativi: le versioni recenti di Melos riconoscono i pub workspaces e, quando sono attivi, delegano a `pub` la risoluzione (niente più `pubspec_overrides.yaml` generati), continuando a offrire script, filtri, versionamento e changelog. È la combinazione consigliata sui progetti nuovi con SDK ≥ 3.6.\n\nUn avvertimento pratico: con i workspaces la risoluzione è **unica**, quindi tutti i pacchetti devono essere compatibili con lo stesso set di versioni. Se avete bisogno di versioni divergenti della stessa dipendenza, restate sull'approccio classico con gli override.\n\n## Integrazione con la CI\n\nUn workflow GitHub Actions minimale ma efficace:\n\n```yaml\nname: CI\non:\n  pull_request:\n    branches: [main]\n\njobs:\n  build:\n    runs-on: ubuntu-latest\n    steps:\n      - uses: actions\u002Fcheckout@v4\n        with:\n          fetch-depth: 0   # necessario per --diff\n\n      - uses: subosito\u002Fflutter-action@v2\n        with:\n          channel: stable\n          cache: true\n\n      - name: Install Melos\n        run: dart pub global activate melos\n\n      - name: Bootstrap\n        run: melos bootstrap\n\n      - name: Format & analyze\n        run: melos run format && melos run analyze\n\n      - name: Test (solo pacchetti modificati)\n        run: melos exec --diff=origin\u002Fmain --dir-exists=test -- flutter test\n```\n\nNote operative:\n\n- `fetch-depth: 0` è indispensabile perché `--diff` possa confrontare i branch;\n- mettete in cache `~\u002F.pub-cache` per accorciare i tempi;\n- se pubblicate su pub.dev, aggiungete un job separato su `main` che esegue `melos version` e `melos publish --no-dry-run` con le credenziali OIDC.\n\n## Supporto negli IDE\n\nMelos genera automaticamente le configurazioni di avvio per VS Code e IntelliJ\u002FAndroid Studio:\n\n```yaml\nide:\n  intellij:\n    enabled: true\n```\n\nSu VS Code conviene inoltre creare un file `my_workspace.code-workspace` con le cartelle dei singoli pacchetti: l'analyzer di Dart lavora meglio quando ogni pacchetto è una root del workspace, evitando falsi errori sugli import.\n\n## Errori comuni da evitare\n\n1. **Dimenticare `melos bootstrap` dopo un `git pull`**: se qualcuno ha aggiunto un pacchetto, gli override locali sono obsoleti. Rendetelo parte del vostro `make setup` o di un hook `post-merge`.\n2. **Committare i `pubspec_overrides.yaml`**: sono artefatti locali, vanno in `.gitignore`.\n3. **Dipendenze circolari tra pacchetti**: Melos le segnala, ma il vero problema è di design. Tenete un grafo aciclico: `app → feature → core`, mai il contrario.\n4. **Un unico pacchetto \"utils\" tuttofare**: diventa in fretta il collo di bottiglia che invalida la cache di build ad ogni modifica. Meglio pacchetti piccoli e coesi.\n5. **`build_runner` in parallelo**: usate sempre `-c 1` o `--order-dependents` per evitare conflitti sui file generati.\n6. **Versionare a mano**: se scrivete i Conventional Commits, lasciate calcolare tutto a `melos version`; i changelog manuali si disallineano sempre.\n\n## Conclusione\n\nMelos non è un framework né cambia il modo in cui scrivete Flutter: è l'infrastruttura che rende sostenibile un monorepo. Con un `melos.yaml` di venti righe ottenete link automatici tra pacchetti, script condivisi da tutto il team, esecuzione mirata dei test in CI e release versionate senza intervento manuale.\n\nSe state avviando un progetto nuovo su Dart 3.6 o superiore, partite direttamente con i **pub workspaces** più Melos per script e versionamento: è la configurazione più veloce e con meno file generati. Su progetti esistenti, il passaggio a Melos si può fare in modo incrementale, un pacchetto alla volta, iniziando a estrarre il design system o i modelli di dominio.","https:\u002F\u002Fflutter.it\u002Fstorage\u002Farticles\u002F10e68611-c421-4c7a-a566-1638b68acd8c.jpg","https:\u002F\u002Fimages.unsplash.com\u002Fphoto-1622858674121-e8cb8b5e6d9f?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3w5NzA2NTJ8MHwxfHJhbmRvbXx8fHx8fHx8fDE3ODc4MDMyOTZ8&ixlib=rb-4.1.0&q=80&w=1080",{"name":12,"author_url":13,"photo_url":14},"Job Ferrari","https:\u002F\u002Funsplash.com\u002F@jobferrera","https:\u002F\u002Funsplash.com\u002Fphotos\u002Fa-computer-screen-with-a-red-light-on-it--1ZgKN9FBMI",null,"published","2026-08-27T04:01:36+00:00","Monorepo Flutter con Melos: guida pratica","Guida a Melos per gestire monorepo Flutter: bootstrap, script, filtri, versionamento con Conventional Commits, CI e pub workspaces di Dart 3.6.",{"id":21,"name":22,"slug":23},1,"Guide","guide",{"id":21,"name":25},"Flutter Bot",[],1789120585567]