Dart 87 🎯 Monorepo Management for Dart Packages using melos
A Dart monorepo without a management tool is a collection of packages that happen to share a Git repository. Each package has its own pubspec.yaml, its own dependencies, and its own version. Changing a shared package requires manually updating every dependent package, and publishing a release requires bumping versions in the correct order. melos solves this by providing a workspace abstraction: a root configuration that knows where every package lives, commands that run across all of them, and an automated versioning system driven by Conventional Commits . The tool is inspired by JavaScript’s Lerna, but it is built specifically for the Dart and Flutter ecosystem, understanding pubspec.yaml files, pub.dev publishing, and the pub workspaces feature that Dart 3.6 introduced .
The architecture changed significantly in Melos 7.x. The separate melos.yaml file is gone; its contents moved into the root pubspec.yaml under a melos key. The workspace is defined by Dart’s native workspace list in the root pubspec.yaml, and each package declares resolution: workspace to opt into the shared resolution . This means Melos 7 is not a standalone tool layered on top of pub; it is a tool that builds on pub workspaces, using the same dependency resolution mechanism that dart pub get uses. The root pubspec.yaml becomes both the workspace definition and the Melos configuration.
This chapter covers the workspace structure and pubspec.yaml configuration, the melos bootstrap and melos exec commands that replace per-package pub get and shell loops, the melos version and melos publish pipeline driven by Conventional Commits, the scripts configuration that standardizes common development tasks, and the migration path from Melos 6 to 7. It assumes familiarity with pubspec.yaml and the concept of a Dart package.
Key point: Melos 7 is a layer on top of Dart pub workspaces. The root pubspec.yaml defines the workspace and the Melos configuration; each package declares resolution: workspace. melos bootstrap links local packages and runs pub get across the workspace; melos version reads Conventional Commits to bump versions and generate changelogs; melos publish publishes unpublished packages to pub.dev. The melos.yaml file from Melos 6 no longer exists.
Why Melos exists as a workspace manager
Manual package linking does not scale. In a repository with multiple packages, a package that depends on a sibling cannot use a path dependency in its published pubspec.yaml, because pub.dev rejects packages with path dependencies. The workaround is a dependency_overrides entry, which must be added before development and removed before publishing. With ten packages, this is ten overrides to add and remove. Melos solves this by using pub workspaces to link local packages automatically: a package that depends on shared_utils resolves to the local directory during development, and to the published version when the package is published .
Commands that should run everywhere are run one package at a time. Running dart test in twenty packages means twenty cd commands and twenty invocations. melos exec -- dart test runs the command in every package, with options for concurrency and fail-fast behavior . The command supports package filters, so “run tests only in packages changed since main” is melos exec --diff=main -- dart test .
Versioning across packages is error-prone. When shared_utils changes, every package that depends on it may need a version bump. The correct bump depends on whether the change was a fix, a feature, or a breaking change. Conventional Commits encode that information in the commit message, and melos version reads the commit history to determine which packages need which bump, updates the pubspec.yaml versions, generates CHANGELOG.md entries, and creates the git tags . The alternative is a manual release checklist that is easy to get wrong.
The trade-off. Melos adds a configuration layer and a command vocabulary that every contributor must learn. The melos bootstrap command must replace dart pub get in every workflow, including CI and pre-commit hooks . The versioning system depends on Conventional Commits, which means contributors must follow the commit format or the automated versioning produces incorrect results. For a single-package repository, Melos is optional; for a repository with more than a few packages, the overhead is repaid by the automation.
a. Workspace structure and pubspec.yaml configuration
A Melos 7 workspace has a root pubspec.yaml and a directory tree of packages. The root file declares the workspace list, which contains the paths to every package. Each package’s pubspec.yaml declares resolution: workspace and does not need a melos section .
# Root pubspec.yaml
name: my_workspace
publish_to: none
environment:
sdk: ^3.9.0
workspace:
- packages/helper
- packages/client_package
- packages/server_package
dev_dependencies:
melos: ^7.0.0
# Melos configuration moved from melos.yaml.
melos:
name: my_workspace
scripts:
test: dart test
analyze: dart analyze
# packages/helper/pubspec.yaml
name: helper
environment:
sdk: ^3.9.0
resolution: workspace
dependencies:
# No path dependency needed; workspace resolution links it.
The workspace list does not support glob patterns in Melos 7. Every package path must be listed explicitly . This is a limitation of the current implementation, not a configuration choice. The packages key from Melos 6 is replaced by workspace, and the melos key in the root pubspec.yaml holds the configuration that previously lived in melos.yaml .
A package that depends on a sibling uses a normal version constraint. The workspace resolution links it to the local directory during development, and the constraint is used when the package is published. If helper is at version 1.2.0 and client_package depends on helper: ^1.2.0, the workspace links client_package to the local helper directory, and the published client_package declares the version constraint .
b. melos bootstrap and melos exec
melos bootstrap (alias melos bs) is the first command after cloning a workspace. It installs dependencies and links local packages. The linking is handled by pub workspaces, not by Melos generating pubspec_overrides.yaml files as it did in version 6 . The command runs pub get across the workspace, and a postbootstrap script can run additional setup, such as build_runner .
# After cloning, bootstrap the workspace.
melos bootstrap
# Equivalent shorthand.
melos bs
melos exec runs an arbitrary command in every package, with filters and concurrency options. The command is passed after --, and Melos provides environment variables like MELOS_PACKAGE_NAME and MELOS_PACKAGE_PATH in each execution .
# Run tests in all packages.
melos exec -- dart test
# Run tests only in packages changed since main.
melos exec --diff=main -- dart test
# Run analyze only in Flutter packages.
melos exec --flutter -- flutter analyze
# Run with fail-fast and limited concurrency.
melos exec --concurrency=4 --fail-fast -- dart test
The filter flags are the mechanism for targeting subsets. --scope matches package names with a glob. --diff includes packages changed since a Git ref. --no-private excludes packages with publish_to: none. --depends-on includes packages that depend on a specific package . The combination of exec and filters replaces a shell script that iterates over directories and runs commands conditionally.
c. melos version, melos publish, and Conventional Commits
The versioning system reads the Git commit history and uses Conventional Commits to determine the bump type for each package. A commit with fix: triggers a patch bump; feat: triggers a minor bump; a commit with BREAKING CHANGE: in the footer triggers a major bump. The package that the commit touches is identified by the file paths in the commit, and packages that depend on it may also receive a bump depending on the configuration .
# Determine version bumps from commits and update files.
melos version
# Version as a prerelease.
melos version --prerelease
# Graduate a prerelease to stable.
melos version --graduate
# Skip changelog generation.
melos version --no-changelog
melos version updates the pubspec.yaml version fields, generates or appends to CHANGELOG.md for each package, and creates Git tags. The commit message and tag format are configurable under command.version.message in the root pubspec.yaml . The default message is chore(release): publish packages followed by the list of new versions.
melos publish publishes any package whose current local version does not exist on pub.dev. It runs in dry-run mode by default, validating the package without publishing. The --no-dry-run flag performs the actual publish .
# Dry run: validate packages without publishing.
melos publish
# Publish for real.
melos publish --no-dry-run
The --no-private filter is implicit in publish: private packages (publish_to: none) are skipped. The --published and --no-published filters allow targeting packages that have or have not been published at their current version .
Complete Example Session
# ============================================
# PART 1: ROOT PUBSPEC.YAML
# ============================================
# my_workspace/pubspec.yaml
name: my_workspace
publish_to: none
environment:
sdk: ^3.9.0
workspace:
- packages/helper
- packages/client_package
- packages/server_package
dev_dependencies:
melos: ^7.0.0
melos:
name: my_workspace
scripts:
test:
description: Run tests in all packages
run: melos exec -- dart test
analyze:
description: Run analyzer in all packages
run: melos exec -- dart analyze
format:
description: Format all packages
run: melos exec -- dart format .
command:
version:
branch: main
linkToCommits: true
# ============================================
# PART 2: PACKAGE PUBSPEC.YAML
# ============================================
# packages/helper/pubspec.yaml
name: helper
environment:
sdk: ^3.9.0
resolution: workspace
# ============================================
# PART 3: BOOTSTRAP
# ============================================
# After cloning:
melos bootstrap
# Installs dependencies in all packages.
# Links local packages via pub workspaces.
# postbootstrap script runs if defined.
# ============================================
# PART 4: RUN SCRIPTS
# ============================================
melos run test
melos run analyze
melos run format
# Or with no argument, prompts for selection:
melos run
# ============================================
# PART 5: EXEC WITH FILTERS
# ============================================
# Tests only in packages changed since main.
melos exec --diff=main -- dart test
# Analyze only Flutter packages.
melos exec --flutter -- flutter analyze
# Run with fail-fast and concurrency limit.
melos exec --concurrency=4 --fail-fast -- dart test
# ============================================
# PART 6: VERSIONING
# ============================================
# Commit messages since last version:
# feat(helper): add format function
# fix(client): handle null response
melos version
# Result:
# helper: 1.2.0 → 1.3.0 (feat)
# client: 0.9.0 → 0.9.1 (fix)
# CHANGELOG.md updated for both.
# Git tags created.
# ============================================
# PART 7: PUBLISHING
# ============================================
# Dry run first.
melos publish
# Publish for real.
melos publish --no-dry-run
# ============================================
# PART 8: MIGRATION FROM MELOS 6
# ============================================
# 1. melos clean (removes pubspec_overrides.yaml)
# 2. Add resolution: workspace to each package.
# 3. Add workspace list to root pubspec.yaml.
# 4. Move melos.yaml content to melos key in root pubspec.yaml.
# 5. Delete melos.yaml.
# ============================================
# PART 9: GITHUB ACTIONS
# ============================================
# Melos has a GitHub Action for CI.
# - uses: invertase/melos@main
# with:
# command: bootstrap
#
# Or use the CLI directly:
# - run: dart pub global activate melos
# - run: melos bootstrap
# - run: melos exec -- dart test
# ============================================
# PART 10: THE COMPLETE FLOW
# ============================================
# 1. Root pubspec.yaml: workspace + melos config.
# 2. Packages: resolution: workspace.
# 3. melos bootstrap: link + install.
# 4. melos run: predefined scripts.
# 5. melos exec: arbitrary commands with filters.
# 6. melos version: Conventional Commits → bumps.
# 7. melos publish: publish unpublished packages.
Quick Reference
Workspace Configuration
| Key | Location | Purpose |
|---|---|---|
workspace | Root pubspec.yaml | List of package paths |
resolution: workspace | Each package pubspec.yaml | Opt into workspace resolution |
melos | Root pubspec.yaml | Melos configuration (was melos.yaml) |
melos.name | Root pubspec.yaml | Workspace display name |
melos.scripts | Root pubspec.yaml | Custom commands for melos run |
Core Commands
| Command | Alias | Purpose |
|---|---|---|
melos bootstrap | bs | Install deps, link local packages |
melos exec -- <cmd> | Run command in all packages | |
melos run <script> | Run predefined script | |
melos version | Bump versions from Conventional Commits | |
melos publish | Publish unpublished packages | |
melos list | List packages | |
melos clean | Remove generated files |
Filter Flags
| Flag | Effect |
|---|---|
--scope=<glob> | Match package names |
--diff=<ref> | Packages changed since Git ref |
--no-private | Exclude publish_to: none |
--flutter | Only Flutter packages |
--depends-on=<pkg> | Packages depending on a package |
Conventional Commits
| Commit Type | Version Bump |
|---|---|
fix: | Patch |
feat: | Minor |
BREAKING CHANGE: | Major |
Best Practices
✅ Do This:
# Define workspace explicitly. // ✅
workspace:
- packages/helper
- packages/client
# Add resolution: workspace to each package. // ✅
resolution: workspace
# Use Conventional Commits for versioning. // ✅
feat(helper): add format function
# Run melos bootstrap in CI, not per-package pub get. // ✅
melos bootstrap
# Define scripts for common tasks. // ✅
scripts:
test: melos exec -- dart test
❌ Don’t Do This:
# Use globs in workspace list (unsupported). // ❌
workspace:
- packages/* # Must list explicitly.
# Keep melos.yaml from Melos 6. // ❌
# Migrate to root pubspec.yaml.
# Skip resolution: workspace in packages. // ❌
# Package will not be linked.
# Commit without Conventional Commit format. // ❌
# melos version cannot determine bumps.
Common Pitfalls
| Pitfall | Why It Happens | Fix |
|---|---|---|
| Package not linked | Missing resolution: workspace | Add to package pubspec.yaml |
melos.yaml not found | Melos 7 removed it | Move config to root pubspec.yaml |
| Version bump incorrect | Commit not Conventional | Follow commit format |
Glob in workspace | Not supported in 7.x | List packages explicitly |
pub get in package | Breaks workspace resolution | Use melos bootstrap |
Real-World Examples
1. Root Workspace Definition
workspace:
- packages/helper
- apps/client
2. Package Resolution
resolution: workspace
3. Bootstrap
melos bootstrap
4. Run Tests in Changed Packages
melos exec --diff=main -- dart test
5. Version from Commits
melos version
6. Publish Dry Run
melos publish
7. Script Definition
scripts:
analyze: melos exec -- dart analyze
8. Conventional Commit
git commit -m "feat(helper): add format function"
9. Filter by Flutter
melos exec --flutter -- flutter analyze
10. Migration Clean
melos clean
Visual: Workspace Structure
┌──────────────────────────────────────────────┐
│ my_workspace/ │
│ ├── pubspec.yaml ← workspace + melos │
│ ├── packages/ │
│ │ ├── helper/ │
│ │ │ └── pubspec.yaml ← resolution: workspace
│ │ ├── client/ │
│ │ │ └── pubspec.yaml │
│ │ └── server/ │
│ │ └── pubspec.yaml │
│ └── apps/ │
│ └── example/ │
│ │
│ workspace list in root pubspec.yaml. │
│ Each package opts in with resolution. │
│ │
└──────────────────────────────────────────────┘
Command Flow
┌──────────────────────────────────────────────┐
│ WORKFLOW │
│ │
│ Clone │
│ │ │
│ ▼ │
│ melos bootstrap │
│ → pub get across workspace │
│ → link local packages │
│ │ │
│ ▼ │
│ Development │
│ melos run test │
│ melos exec --diff=main -- dart test │
│ │ │
│ ▼ │
│ Release │
│ melos version │
│ → read Conventional Commits │
│ → bump versions │
│ → update CHANGELOG.md │
│ │ │
│ ▼ │
│ melos publish │
│ → dry run, then --no-dry-run │
│ │
└──────────────────────────────────────────────┘
Versioning Pipeline
┌──────────────────────────────────────────────┐
│ CONVENTIONAL COMMITS → VERSIONS │
│ │
│ feat(helper): add function │
│ │ │
│ ▼ │
│ helper: 1.2.0 → 1.3.0 (minor) │
│ │ │
│ │ dependents may bump │
│ ▼ │
│ client: 0.9.0 → 0.9.1 (patch) │
│ │
│ fix(client): handle null │
│ │ │
│ ▼ │
│ client: 0.9.1 → 0.9.2 (patch) │
│ │
│ BREAKING CHANGE in footer │
│ │ │
│ ▼ │
│ major bump │
│ │
└──────────────────────────────────────────────┘
Melos 6 vs 7
┌──────────────────────────────────────────────┐
│ MELOS 6 MELOS 7 │
│ │
│ melos.yaml root pubspec.yaml │
│ packages: workspace: │
│ - packages/** - packages/a │
│ - packages/b │
│ │
│ pubspec_overrides resolution: workspace │
│ generated per pkg in each package │
│ │
│ melos bootstrap melos bootstrap │
│ → overrides → pub workspace │
│ │
└──────────────────────────────────────────────┘
Summary
| Item | Value |
|---|---|
| Workspace definition | workspace list in root pubspec.yaml |
| Package opt-in | resolution: workspace |
| Melos config location | melos key in root pubspec.yaml (7.x) |
| Bootstrap | melos bootstrap |
| Run command in all | melos exec -- <cmd> |
| Run predefined script | melos run <script> |
| Versioning | melos version from Conventional Commits |
| Publishing | melos publish (dry run default) |
| Filter changed | --diff=<ref> |
| Minimum Dart SDK | 3.6.0 for pub workspaces |
Key takeaways:
- Melos 7 builds on Dart pub workspaces, not on its own linking mechanism. The root
pubspec.yamldeclares theworkspacelist, each package declaresresolution: workspace, and themelos.yamlfile no longer exists. The Melos configuration moves into the rootpubspec.yamlunder ameloskey . melos bootstrapreplaces per-packagepub get. It installs dependencies across the workspace and links local packages so that a dependency on a sibling resolves to the local directory during development .melos execruns commands across packages with filters. The--diffflag targets packages changed since a Git ref,--fluttertargets Flutter packages, and--concurrencyand--fail-fastcontrol execution .melos versionreads Conventional Commits to determine bumps. Afix:commit triggers a patch bump,feat:triggers a minor bump, andBREAKING CHANGE:triggers a major bump. The command updatespubspec.yamlversions, generatesCHANGELOG.md, and creates Git tags .melos publishpublishes unpublished packages topub.dev. It runs in dry-run mode by default and skips private packages. The--no-dry-runflag performs the actual publish .- The
workspacelist does not support globs in Melos 7. Every package path must be listed explicitly. This is a current limitation, not a configuration choice . - Migration from Melos 6 requires moving the configuration and removing overrides. The
melos cleancommand removes thepubspec_overrides.yamlfiles, themelos.yamlcontent moves to the rootpubspec.yaml, and each package needsresolution: workspace.
Remember: Melos is the monorepo tool for the Dart and Flutter ecosystem. It does three things that a plain Git repository cannot: it links local packages so that a dependency on a sibling resolves to the local directory, it runs commands across every package with filters, and it automates versioning and publishing from Conventional Commits. Melos 7 is not a standalone tool; it is a layer on top of Dart’s native pub workspaces. The root pubspec.yaml is both the workspace definition and the Melos configuration, and each package opts in with resolution: workspace. The melos.yaml file from version 6 is gone. Use melos bootstrap instead of dart pub get, use melos exec instead of a shell loop, and use melos version instead of a manual release checklist.
Stop using slow, ad-bloated tool sites! 🤮
🔎 Search “KandZ Tools” on Google to use many professional utilities for free.
KandZ.me is the ultimate minimalist hub for:
✅ Finance (Mortgage, Interest, Inflation)
✅ Tech (Base64, JSON, Dev Suite, IP)
✅ Health (BMI, BMR, TDEE)
✅ Productivity (Timer, Workspace, QR)
⚡️ Fast & Private
🔒 No data leaves your device
💎 100% Free
🔗 Use it now: https://tools.kandz.me
🔖 Bookmark it—you’ll need it later!