skip to content

In the Dart CLI, how do dart run pkg@version and dart install differ when you want to use a command-line tool published on pub.dev?

level: middleimportance: nice to knowfreq 25%

answer

  1. one-off versus on the PATH
  2. @ with an optional descriptor
  3. no dependency, no activation
  4. AOT-compiled, self-contained binaries
  5. dart installed, dart uninstall

basics

~10 s

dart run pkg@ (Dart 3.12+) resolves, downloads and runs a remote package's executable once, without adding a dependency. dart install (3.10+) compiles a package's executables into native binaries on your PATH for repeated use.

solid answer

~40 s

`dart run <package>[:<executable>]@[<descriptor>]` runs a tool that is not a dependency of the current package: `dart run dhttpd@` resolves the latest stable version from pub.dev, downloads it if needed, compiles it and runs its default executable. After the `@` you can give a version constraint (`pubviz@^4.0.0`) or a YAML descriptor for a custom host or a git source. It fits one-off tasks and scripts. `dart install <package>` is for tools you use repeatedly: it installs every executable in the package's `executables` section (or every `bin/*.dart` if there is none) as a self-contained AOT-compiled binary on your PATH, and overwrites a previous install of the same package. `dart installed` lists installs and `dart uninstall` removes them. Both are newer alternatives to `dart pub global activate`.

go deeper

for a junior

Recall that the @ marks a remote package for dart run and that dart install puts a tool on the PATH.

for a middle

Explain descriptor syntax, how dart install chooses executables and why installed tools start fast as AOT binaries.

for a senior

Choose between project-pinned dev dependencies, one-off remote runs and global installs to keep builds reproducible.

for a principal

Set a team policy for developer tooling versions so local machines, scripts and CI run identical tools.

## Two ways to use someone else's tool Many Dart packages ship **executables**: code in `bin/`, optionally listed under `executables:` in their `pubspec.yaml`. Dart 3.10 and 3.12 added two commands that use them without making the tool a dependency of your project. | | `dart run <pkg>@...` | `dart install <pkg>` | |---|---|---| | Added in | Dart 3.12 | Dart 3.10 | | Purpose | run once, now | keep available on the PATH | | Result | runs the executable with your arguments | self-contained AOT binaries in a bin directory | | Housekeeping | none | `dart installed`, `dart uninstall` | | Replaces | ad-hoc activation | `dart pub global activate` for most uses | ## dart run with a remote package The syntax is `dart run <PACKAGE>[:<EXECUTABLE>]@[<DESCRIPTOR>] [args]`. The **`@` is what marks the package as remote**: - `dart run dhttpd@` - latest stable version from pub.dev, default executable. - `dart run pubviz@^4.0.0` - a version constraint after the `@`. - `dart run 'pubviz@{hosted: https://my_repository.com, version: ^1.0.0}'` - a YAML descriptor for a custom host. - `dart run 'pubviz@{git: https://github.com/...}'` - a git source. - `dart run pkg:tool@` - a named executable other than the default. Dart resolves the package, downloads it if it is not already cached, compiles and runs it. The current project's `pubspec.yaml` is not touched. The dart.dev guide for `dart doc` uses exactly this to preview generated docs: `dart run dhttpd@ --path doc/api`. Without the `@`, `dart run foo` means something different: run the executable of **`foo` as a dependency of the current package**, at the version your lockfile resolves. ## dart install `dart install` installs or upgrades a tool for global use: 1. It resolves the package - from pub.dev by name, from a git URL, or from a local path; the `<package>@<descriptor>` form accepts the same descriptors as `dart run`, and a version constraint can also follow the name. 2. It installs the executables declared in the package's `executables` section, or all `bin/*.dart` entry points if that section is missing. 3. Per the 3.10 release notes, it compiles them into **self-contained native AOT binaries** using `dart build cli`, so they start quickly and do not need the SDK to resolve packages at launch. 4. It places them in a directory it expects on your PATH and, if that directory is missing from PATH, prints the line to add. Installing the same package again **overwrites** it; `--overwrite` additionally allows replacing an executable of the same name that belongs to a different package. ## Choosing - One-off or scripted use, where pinning the version in the command is useful: `dart run pkg@version`. - A tool you type every day: `dart install`. - A tool the **project** depends on, such as a code generator: add it to `dev_dependencies` and use `dart run pkg:exe`, so everyone gets the version in the lockfile. ## Common mistakes - Adding a one-off tool to `dev_dependencies` just to run it once. - Forgetting the `@`, so `dart run` looks for the package among the project's dependencies and fails. - Using a globally installed code generator instead of the project-pinned one, so teammates generate different output.

  • What is the difference between dart run foo and dart run foo@?
    `dart run foo` runs the executable of `foo` as a dependency of the current package, at the version the lockfile resolves. `dart run foo@` treats `foo` as a remote package: it resolves the latest stable version from pub.dev, downloads it if needed and runs it without touching the project.
  • Why should a project's code generator be a dev dependency rather than a dart install tool?
    A dev dependency is pinned in `pubspec.lock`, so every developer and CI job runs the same version and generates the same output. A globally installed tool is whatever version each machine happened to install.

saying these in an interview costs you the question

  • Thinks dart run pkg@ adds the package to pubspec.yaml
  • Believes dart install only works for packages already in the project
  • Assumes dart run foo and dart run foo@ are the same
  • Uses a globally installed code generator instead of a pinned dev dependency
  • Thinks dart install keeps running tools through the JIT from source