| |

Dart 87 🎯 Monorepo Management for Dart Packages using melos

⏱️ Estimated read: 14 min | |

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

KeyLocationPurpose
workspaceRoot pubspec.yamlList of package paths
resolution: workspaceEach package pubspec.yamlOpt into workspace resolution
melosRoot pubspec.yamlMelos configuration (was melos.yaml)
melos.nameRoot pubspec.yamlWorkspace display name
melos.scriptsRoot pubspec.yamlCustom commands for melos run

Core Commands

CommandAliasPurpose
melos bootstrapbsInstall deps, link local packages
melos exec -- <cmd>Run command in all packages
melos run <script>Run predefined script
melos versionBump versions from Conventional Commits
melos publishPublish unpublished packages
melos listList packages
melos cleanRemove generated files

Filter Flags

FlagEffect
--scope=<glob>Match package names
--diff=<ref>Packages changed since Git ref
--no-privateExclude publish_to: none
--flutterOnly Flutter packages
--depends-on=<pkg>Packages depending on a package

Conventional Commits

Commit TypeVersion 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

PitfallWhy It HappensFix
Package not linkedMissing resolution: workspaceAdd to package pubspec.yaml
melos.yaml not foundMelos 7 removed itMove config to root pubspec.yaml
Version bump incorrectCommit not ConventionalFollow commit format
Glob in workspaceNot supported in 7.xList packages explicitly
pub get in packageBreaks workspace resolutionUse 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

ItemValue
Workspace definitionworkspace list in root pubspec.yaml
Package opt-inresolution: workspace
Melos config locationmelos key in root pubspec.yaml (7.x)
Bootstrapmelos bootstrap
Run command in allmelos exec -- <cmd>
Run predefined scriptmelos run <script>
Versioningmelos version from Conventional Commits
Publishingmelos publish (dry run default)
Filter changed--diff=<ref>
Minimum Dart SDK3.6.0 for pub workspaces

Key takeaways:

  • Melos 7 builds on Dart pub workspaces, not on its own linking mechanism. The root pubspec.yaml declares the workspace list, each package declares resolution: workspace, and the melos.yaml file no longer exists. The Melos configuration moves into the root pubspec.yaml under a melos key .
  • melos bootstrap replaces per-package pub 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 exec runs commands across packages with filters. The --diff flag targets packages changed since a Git ref, --flutter targets Flutter packages, and --concurrency and --fail-fast control execution .
  • melos version reads Conventional Commits to determine bumps. A fix: commit triggers a patch bump, feat: triggers a minor bump, and BREAKING CHANGE: triggers a major bump. The command updates pubspec.yaml versions, generates CHANGELOG.md, and creates Git tags .
  • melos publish publishes unpublished packages to pub.dev. It runs in dry-run mode by default and skips private packages. The --no-dry-run flag performs the actual publish .
  • The workspace list 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 clean command removes the pubspec_overrides.yaml files, the melos.yaml content moves to the root pubspec.yaml, and each package needs resolution: 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.

Was this helpful?


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!