skip to content

How do you scaffold a new Dart command-line package with dart create, and how does dart run find the program to execute?

level: juniorimportance: should knowfreq 45%

answer

  1. -t picks the template
  2. console is the default
  3. cli adds package:args
  4. runs pub get unless --no-pub
  5. dart run looks in bin/

basics

~20 s

dart create -t cli my_tool generates a package from a template (console by default, or cli, package, server-shelf, web) and runs pub get. Inside it, dart run executes bin/my_tool.dart; dart run :name runs another file in bin/.

solid answer

~40 s

`dart create <directory>` builds a project that follows the package layout conventions and then runs `pub get` unless you pass `--no-pub`. `-t` / `--template` picks the starting point: `console` (the default, a plain command-line app), `cli` (a command-line app with argument parsing via `package:args`), `package` (shared libraries), `server-shelf` (a server using `package:shelf`) and `web`. It refuses an existing directory unless you add `--force`. `dart run` with no target runs the current package's main program, `bin/<package name>.dart`; `dart run :baz` runs `bin/baz.dart`; `dart run bar:baz` runs `bin/baz.dart` from a dependency `bar`; and `dart run tool/debug.dart` runs a file by path. Arguments after the target go to `main`, and VM flags such as `--enable-asserts` go before it.

code

bash · 4 lines
bash
dart create -t cli my_tool
cd my_tool
dart run my_tool --help
dart run --enable-asserts my_tool --verbose

go deeper

for a junior

Recall the templates, that console is the default, and that dart run looks in bin/.

for a middle

Explain dart run's target forms, where VM flags and program arguments go, and what --no-pub and --force change.

for a senior

Structure a tool package so its executables live in bin/ and dependent packages can run them by name.

for a principal

Choose a starting template and layout that scales from a script to a published tool without restructuring.

## Scaffolding with dart create `dart create` is the SDK's project generator. It creates a directory, writes a set of files from a **template**, and then runs `pub get` so dependencies are ready - pass `--no-pub` to skip that step, for example offline. | Template (`-t`) | What you get | |---|---| | `console` (default) | a command-line application | | `cli` | a command-line application with argument parsing using `package:args` | | `package` | a package containing shared Dart libraries | | `server-shelf` | a server built with `package:shelf` | | `web` | a web app using core Dart libraries | An older `console-simple` template still exists in the tool but is marked deprecated and hidden from help. Every template produces the standard **package layout**: a `pubspec.yaml`, an `analysis_options.yaml`, a `README.md` and `CHANGELOG.md`, a `.gitignore`, and code under `bin/`, `lib/` and `test/` as appropriate. If the target directory already exists, `dart create` fails unless you pass `--force`. ## Scenario: a new command-line package For a tool that will take flags and subcommands, `dart create -t cli my_tool` is the better start than the default, because it wires `package:args` in from the beginning. The package name comes from the directory name, and the entry point is `bin/my_tool.dart`. A reasonable first session is: 1. `dart create -t cli my_tool` and `cd my_tool`. 2. `dart run my_tool --help` to exercise the argument parser; with the package name as the target, the arguments after it reach `main`. 3. `dart format .` and `dart analyze` before the first commit. 4. `dart test` once the first test exists. ## How dart run resolves its target `dart run` runs a Dart program from a file, from the current package, or from a dependency. Only programs in a package's **`bin/`** directory are visible by name; everything else is private and must be run by path. - **`dart run`** - in the package root, runs the main program `bin/<package name>.dart`. - **`dart run :baz`** - runs `bin/baz.dart` in the current package. - **`dart run bar`** - runs `bin/bar.dart` from the dependency `bar`. - **`dart run bar:baz`** - runs `bin/baz.dart` from the dependency `bar`; for example `dart run test:test` runs the `test` package's executable. - **`dart run tool/debug.dart`** - runs any file by relative path. Arguments **after** the target are passed to `main(List<String> args)`. Flags for the VM go **before** it: `--enable-asserts` turns on `assert` statements, and `--observe` enables DevTools debugging and profiling. ## Why dart run instead of dart file.dart Both run code on the VM, but `dart run` understands **package targets**, so a dependency's tool can be invoked by name at the version your lockfile pins. That is why generated-code workflows are written as `dart run <package>:<executable>` rather than by path into the pub cache. ## Common mistakes - Expecting `dart create` to add `package:args` without choosing the `cli` template. - Putting a runnable script in `lib/` and wondering why `dart run :name` cannot find it. - Passing `--enable-asserts` after the script name, where it becomes an argument to `main`. - Running `dart create` into an existing folder without `--force` and misreading the failure.

  • Which directory must a script live in for dart run to find it by name?
    The package's `bin/` directory. `dart run :name` resolves `bin/name.dart` in the current package and `dart run pkg:name` resolves `bin/name.dart` in a dependency; files elsewhere, such as `tool/`, must be run by path.
  • What does dart create do if the target directory already exists?
    It fails rather than overwrite anything. Passing `--force` makes it generate the project into the existing directory anyway.

saying these in an interview costs you the question

  • Thinks dart create uses the cli template by default
  • Believes dart run can find any file in the package by name
  • Puts VM flags such as --enable-asserts after the script name
  • Expects dart create to skip pub get unless asked
  • Thinks lib/ files are runnable executables of a dependency