Bootstrap Command
This command initializes the workspace, links local packages together and installs remaining package dependencies.
melos bootstrap
# or
melos bs
Bootstrapping has two primary functions:
- Installing all package dependencies (internally using
pub get
). - Locally linking any packages together via path dependency overrides without having to edit your pubspec.yaml.
Why is bootstrapping required?
In normal projects, packages can be linked by providing a path
within the
pubspec.yaml
. This works for small projects however presents a problem at
scale. Packages cannot be published with a locally defined path, meaning once
you're ready to publish your packages you'll need to manually update all the
packages pubspec.yaml
files with the versions. If your packages are also
tightly coupled (dependencies of each other), you'll also have to manually check
which versions should be updated. Even with a few of packages this can become a
long and error-prone task.
Melos solves this problem by overriding local files which the Dart analyzer uses
to read packages from. If a local package exists (defined in the melos.yaml
file) and a different local package has it listed as a dependency, it will be
linked regardless of whether a version has been specified.
Benefits
- All local packages in the repository can be interlinked by Melos to point to
their local directories rather than 'remote' without pubspec.yaml
modifications.
- Example Scenario: In a repository, package
A
depends on packageB
. Both packagesA
&B
exist in the monorepo. However, if youpub get
inside packageA
,pub
will retrieve packageB
from the pub.dev registry as it's unaware ofB
existing locally. However, with Melos, it's aware that packageB
exists locally too, so it will generate the various pub files to point to a relative path in the local repository.- If you wanted to use pub you could of course define a dependency override
in the pubspec of package
A
that sets a path for packageB
but, then you'd have to do this manually every time and then manually remove it again when you want to publish or even commit your changes. This doesn't scale well and doesn't help with making a repository contributor friendly. FlutterFire for example has over 40 packages with various interlinking levels (try runmelos list --graph
to see its local dependency graph).- This can also get phenomenally worse for example say if we introduce
package
C
that packageB
depends on but packageC
then also depends onA
.
- This can also get phenomenally worse for example say if we introduce
package
- If you wanted to use pub you could of course define a dependency override
in the pubspec of package
- Example Scenario: In a repository, package
- Interlinking highlights dart/analyzer issues early.
- Example Scenario: Package
A
relies on packageB
from the same mono repo. PackageB
gets a minor API change. Viapub get
on packageA
the dart analyzer and IDEs report no issues with the package as it installed packageB
from the remote pub registry and not local (which hasn't been published yet). With Melos, the dart analyzer / IDEs would highlight this issue immediately since local versions are used. The same applies for non-breaking deprecations, packageA
wouldn't show there was a deprecated API in use without being interlinked through Melos.
- Example Scenario: Package
- Interlinking allows working on new, not yet published (or private) packages easily, without defining dependency overrides.
Combining with filters
Bootstrap supports all package filtering options, therefore if you wanted to you could bootstrap only a specific subset of your packages, for example:
# Only bootstrap packages that have
# changed since the main branch.
melos bootstrap --diff="main"
Bootstrap flags
- The
--no-example
flag is used to exclude flutter package's example's dependencies (https://github.com/dart-lang/pub/pull/3856)- This will run
pub get
with the--no-example
flag.
- This will run
- The
--enforce-lockfile
flag is used to enforce versions from.lock
files.- Ensure .lock files exist, as failure may occur if they're not checked in.
- The
--no-enforce-lockfile
flag is used to disregard versions from.lock
files ifenforce-lockfile
is configured in themelos.yaml
file. - The
--skip-linking
flag is used to skip the local linking of workspace packages. - The
--offline
flag is used to only resolve dependencies from the local cache by runningpub get
with the--offline
flag.
In addition to the above flags, the melos bootstrap
command supports a few different flags that
can be defined in your melos.yaml
file.
Shared dependencies
If you want to share dependency versions between your packages in your Melos
project, just add the dependencies you wish to share between the packages to
your bootstrap config in your melos.yaml
file.
If a dependency from environment
, dependencies
or dev_dependencies
in
your melos.yaml
exists in a package, the dependency version in this
package will be updated to match the version defined in your
bootstrap config every time melos bootstrap
is run.
# melos.yaml
# ...
command:
bootstrap:
environment:
sdk: ">=3.0.0 <4.0.0"
flutter: ">=3.0.0 <4.0.0"
dependencies:
collection: ^1.18.0
integral_isolates: any
uni_links2:
uni_links_macos:
git: https://github.com/SamJakob/uni_links_macos.git
dev_dependencies:
build_runner: ^2.3.3
# ...
Adding a post bootstrap lifecycle script
Melos supports various command lifecycle hooks
that can be defined in your melos.yaml
.
For example, if you needed to run something such as a build runner automatically
after melos bootstrap
is run, you can add a post
hook script:
# melos.yaml
# ...
command:
bootstrap:
hooks:
post: dart pub run build_runner build
# ...
This is useful to ensure any local project requirements, such as generated files being built, are met when anyone is working on your mono repo code base, e.g. external contributors.