skip to content

SDK Tooling

The dart command, JIT and AOT compilation to native code, JavaScript and WebAssembly, the analyzer and lint sets, build_runner and package:test. Interviewers probe the daily loop.

part ofDartoverview, primer and where to startread it →
on this pageshow

explore

questions

26

How do you make a CI job fail when Dart code is not formatted, using dart format, and what does the command change by default?

level: juniorimportance: must knowfreq 60%

answer

  1. overwrites files unless told otherwise
  2. -o none reports without writing
  3. --set-exit-if-changed returns 1
  4. page width 80 by default
  5. run dart pub get first

basics

~20 s

Run dart format -o none --set-exit-if-changed . in CI: it writes nothing and exits with code 1 if any file would change. Without flags, dart format rewrites files in place, wrapping to 80 columns and managing trailing commas.

solid answer

~40 s

By default `dart format <paths>` **overwrites** each Dart file with the formatted version, recursing into directories. For CI you want a check, not a rewrite: `-o none` (short for `--output none`) makes it report which files would change without touching them, and `--set-exit-if-changed` makes the process exit with code `1` when any change is needed and `0` otherwise, which fails the job. `-o show` or `-o json` print the formatted content instead. The formatter wraps to a page width of 80 unless configured, and in the current tall style it adds and removes trailing commas itself. Because it picks the style from each file's language version, the CI job must run `dart pub get` first so the `package_config.json` it reads exists.

code

bash · 2 lines
bash
dart pub get
dart format -o none --set-exit-if-changed .

go deeper

for a junior

Recall the check command: -o none to avoid writing and --set-exit-if-changed to exit 1 on unformatted code.

for a middle

Explain the output modes, the exit codes and why the package configuration must exist before formatting.

for a senior

Keep formatter results identical across machines by pinning the SDK and putting page width in analysis_options.yaml.

for a principal

Treat formatting as a non-negotiable automated gate so review time goes to design, and plan how SDK formatter changes land.

## What dart format does `dart format` is the Dart SDK's code formatter, the same one IDEs call on save. You pass it files or directories; a directory is processed **recursively**. Its output is deterministic: there are very few options, by design, so a team never argues about style. By default it: - **overwrites** each file in place with the formatted version; - wraps lines to **80 characters** (the page width) unless configured otherwise; - in the tall style used for language version 3.7 and later, **adds trailing commas** to argument and parameter lists that split across lines and **removes** them from ones that fit on one line; - normalises whitespace and may move comments across a comma. ## Output modes The `--output` option, short `-o`, controls where results go: | Flag | Effect | |---|---| | (none) | rewrite files in place | | `-o show` | print formatted contents, leave files untouched | | `-o json` | print formatted contents as JSON | | `-o none` | print nothing but the list of files that would change | ## Failing a CI job The second piece is the exit code. With `--set-exit-if-changed`, the command exits with **1** if any file would change and **0** if all are already formatted. Combined with `-o none`, that is a pure check: 1. `dart pub get` - so the formatter can find `.dart_tool/package_config.json`. 2. `dart format -o none --set-exit-if-changed .` 3. The CI step fails on exit code 1, and the log lists the offending files. Step 1 matters more than it looks. Since Dart 3.7 the formatter chooses between the old short style and the tall style **per file**, based on that file's language version, and it learns the language version from the package configuration. The Dart 3.7 release notes explicitly tell teams with CI format checks to run `dart pub get` first; without it, the check may format against the wrong assumptions and disagree with developers' machines. ## Keeping local and CI results identical - Use the **same SDK version** locally and in CI. The formatter ships with the SDK, and style fixes land in SDK releases; Dart 3.13, for example, changed several tall-style details for code at language version 3.13, including separating imports into sections. - Put any **page width** in `analysis_options.yaml` under `formatter: page_width:` rather than a command-line flag, so every developer and the CI job read the same value. - Enable **format on save** in the editor so the check rarely fires. ## Scenario: a new command-line package After `dart create my_tool`, the generated project already follows the package layout. A minimal CI workflow for it runs `dart pub get`, `dart format -o none --set-exit-if-changed .`, then the analyzer and tests. The format step is the cheapest of the three and the first to fail, which is why it usually runs first. ## Common mistakes - Running plain `dart format .` in CI, which rewrites files in the CI workspace and always passes. - Forgetting `--set-exit-if-changed`, so the job logs changes but still succeeds. - Skipping `dart pub get`, so the language version cannot be resolved. - Using `dart format --fix`, which was removed in Dart 3.7; fixes now belong to `dart fix`.

  • Why does a dart format check in CI need dart pub get to run first?
    The formatter picks the short or tall style per file from its language version, which it reads from the package configuration that `dart pub get` writes. Without it, the formatter cannot resolve the language version the way developers' machines do, and results can differ.
  • What exit code does dart format --set-exit-if-changed return when nothing needs formatting?
    It returns 0. It returns 1 only when at least one file would change, which is what lets a CI system treat the step as pass or fail.

saying these in an interview costs you the question

  • Runs plain dart format . in CI and expects it to fail
  • Thinks dart format only reports and never writes files by default
  • Believes --set-exit-if-changed alone stops files from being rewritten
  • Uses dart format --fix, which no longer exists
  • Skips dart pub get before the format check
open as a page

In a Dart or Flutter project, what does dart run build_runner build do, and when do you use watch or clean instead?

level: juniorimportance: must knowfreq 55%

basics

~20 s

build_runner build runs every applicable builder once and writes outputs such as .g.dart parts beside your sources; watch keeps running and rebuilds incrementally on each save; clean deletes the build cache so the next build is a full one.

open as a page

In Dart's package:test, how do test, group, setUp, tearDown and setUpAll organise a suite, and in what order do the hooks run?

level: juniorimportance: must knowfreq 55%

basics

~20 s

test declares one case; group nests cases under a name prefix. setUp runs before each test, outer groups first; tearDown runs after each test, even a failing one, inner groups first; setUpAll and tearDownAll run once per group.

open as a page

In a Dart or Flutter analysis_options.yaml, what do include:, linter: rules, analyzer: errors: and analyzer: exclude: each control?

level: middleimportance: must knowfreq 58%

basics

~20 s

include: pulls in shared option files such as a lint set; linter: rules switches individual lints on or off; analyzer: errors: changes a diagnostic's severity or ignores it; analyzer: exclude: removes files matching globs from analysis.

open as a page

In Dart, how does JIT compilation on the Dart VM differ from AOT compilation, and when do you use each?

level: middleimportance: must knowfreq 60%

basics

~20 s

JIT compiles Dart code while the VM runs it, which enables incremental recompilation, hot reload and rich debugging during development. AOT compiles to native machine code before shipping, giving consistent, short startup for production executables and apps.

open as a page

In Dart's package:test, how do you assert that a call throws or that a Future completes or fails, and when do you need expectLater?

level: middleimportance: must knowfreq 50%

basics

~10 s

Wrap a throwing call in a closure: expect(() => parse('x'), throwsFormatException). For Futures use completion(matcher) or throwsA(isA<T>()); expect returns before those async matches finish, so await expectLater when later code depends on the result.

open as a page

In Dart and Flutter, what are the lints package's core and recommended sets and flutter_lints, and which does a new Flutter app include?

level: juniorimportance: should knowfreq 45%

basics

~10 s

The lints package ships two Dart-team rule sets: core catches critical problems, and recommended includes core plus idiomatic-style rules. flutter_lints builds on recommended with Flutter rules, and flutter create includes package:flutter_lints/flutter.yaml.

open as a page

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%

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/.

open as a page

What does dart compile exe produce, and how does it differ from dart compile aot-snapshot run with dartaotruntime?

level: juniorimportance: should knowfreq 40%

basics

~10 s

dart compile exe produces a self-contained native executable: AOT machine code plus a small Dart runtime. dart compile aot-snapshot produces the same machine code without the runtime, a .aot file you launch with dartaotruntime.

open as a page

How do you make dart analyze fail a CI job on lint findings, and what do its --fatal-infos and --fatal-warnings flags change?

level: middleimportance: should knowfreq 34%

basics

~20 s

Lints report at info severity, and dart analyze exits 0 on infos unless you pass --fatal-infos (exit 1). Warnings are fatal by default (exit 2), errors always exit 3; alternatively raise chosen rules to warning or error under analyzer: errors:.

open as a page

In Dart, when do you silence an analyzer finding with an ignore comment, ignore_for_file, analyzer errors: ignore, or analyzer exclude:?

level: middleimportance: should knowfreq 40%

basics

~10 s

Use // ignore: for one line, // ignore_for_file: for one file (type=lint covers every lint), analyzer errors: <code>: ignore to drop one diagnostic package-wide, and analyzer exclude: to stop reporting whole files by glob.

open as a page

Since Dart 3.7, how does dart format choose between the short and tall styles, and how do you configure page width and trailing commas?

level: middleimportance: should knowfreq 40%

basics

~20 s

dart format picks the style per file from its language version: 3.6 or lower gets the old short style, 3.7 or later the tall style. Page width and trailing-comma behaviour are set under formatter: in analysis_options.yaml.

open as a page

In a Dart package's build.yaml, how do targets, generate_for and builder options configure the generators build_runner runs?

level: middleimportance: should knowfreq 30%

basics

~20 s

build.yaml's targets: $default: builders: section configures each builder applied to the package: generate_for limits it to matching files, enabled switches it on or off, and options passes settings such as json_serializable's explicit_to_json to every generated class.

open as a page

Why did the Dart team cancel macros, and what does that mean for code generation with build_runner in a Dart 3.13 project?

level: middleimportance: should knowfreq 30%

basics

~20 s

Macros needed deep semantic introspection at compile time, which slowed static analysis, code completion and the incremental compile behind hot reload, so the Dart team stopped work in January 2025. build_runner generators remain the way to generate code.

open as a page

What do dart compile js and dart compile wasm produce for a Dart web app, and what must the app avoid to compile to WebAssembly?

level: middleimportance: should knowfreq 30%

basics

~20 s

dart compile js emits optimised JavaScript plus a source map; dart compile wasm emits a WasmGC module, a .mjs JavaScript loader and a source map. Wasm builds support only the new JS interop, so avoid dart:html and dart:js.

open as a page

Which dart test flags and package:test annotations control which tests run, on which platform, how many at once and how long each may take?

level: middleimportance: should knowfreq 32%

basics

~20 s

dart test -n filters by name regex, -t/-x by @Tags, -p picks platforms such as vm or chrome, and -j sets concurrent suites. skip: and @Skip disable tests; Timeout and @Timeout change the 30-second default, which dart_test.yaml can set package-wide.

open as a page

In Dart's package:test, how do you assert what a Stream emits, including an error event and the done event?

level: middleimportance: should knowfreq 38%

basics

~20 s

Use stream matchers: expect(stream, emitsInOrder([a, b, emitsDone])) checks a sequence and the end; emits(x) matches one event, emitsError(m) an error event, and emitsThrough skips ahead. Wrap a StreamQueue and await expectLater to check events step by step.

open as a page

A legacy Dart codebase leans on dynamic values and raw generic types; how do you roll out strict-inference, strict-casts and the no_raw_types lint without stalling the team?

level: seniorimportance: should knowfreq 24%

basics

~20 s

Measure first, then tighten in stages: enable one check at a time, fix module by module starting at dynamic boundaries such as jsonDecode, keep new code clean, and make it blocking once findings reach zero. On Dart 3.13 prefer the no_dynamic_casts and no_raw_types lints.

open as a page

When upgrading a large Dart or Flutter codebase to a new SDK, how do you use dart fix to migrate deprecated APIs safely?

level: seniorimportance: should knowfreq 35%

basics

~20 s

Run dart fix --dry-run to list proposed fixes per file, then dart fix --apply, optionally narrowed with --code to one diagnostic. It fixes diagnostics that have automated fixes, including data-driven API migrations that SDKs and packages ship.

open as a page

A Flutter app's generated fromJson, toJson and copyWith code keeps going stale in CI; do you commit the build_runner output, and how does --only-check help?

level: seniorimportance: should knowfreq 35%

basics

~20 s

Either commit .g.dart and .freezed.dart files and have CI run dart run build_runner build --only-check, which writes nothing and fails on any difference, or commit nothing and generate in CI before analyzing. Published packages must ship generated files.

open as a page

How do Dart conditional imports such as if (dart.library.io) let one package ship native and web implementations, and what are the pitfalls?

level: seniorimportance: should knowfreq 35%

basics

~20 s

A conditional import names a default file and alternatives guarded by dart.library.* conditions; the compiler picks the first alternative whose library is available on the target, otherwise the default. All alternatives must expose the same API.

open as a page

A Dart date library's retry-with-timeout and 'in 5 minutes' parsing tests wait real seconds and flake; how does fake_async make them fast and deterministic?

level: seniorimportance: should knowfreq 22%

basics

~20 s

fakeAsync runs the test in a zone whose timers and microtasks fire only when you call elapse or flushMicrotasks, so a 30-second timeout takes no real time; reading time through package:clock's clock.now() lets it fake the current time too.

open as a page

What are the Dart SDK's stable, beta and dev release channels, and what does dart info report when you file a tooling bug?

level: juniorimportance: nice to knowfreq 15%

basics

~20 s

Stable ships about every three months for production; beta about monthly as a pre-release; dev about twice a week for recent fixes and experiments. dart info prints the SDK version and channel, OS, locale, running Dart processes and, in a package, project details.

open as a page

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%

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.

open as a page

In Dart's source_gen, how does SharedPartBuilder let several generators share one .g.dart file, and how do PartBuilder and LibraryBuilder differ?

level: middleimportance: nice to knowfreq 18%

basics

~20 s

Each SharedPartBuilder writes a hidden .<partId>.g.part piece to the build cache; source_gen's combining_builder merges all pieces into one .g.dart part. PartBuilder writes its own part extension such as .freezed.dart, and LibraryBuilder writes a standalone importable library.

open as a page

How do you build Linux x64 and ARM64 executables of a Dart CLI from a macOS machine, and what limits apply?

level: seniorimportance: nice to knowfreq 18%

basics

~10 s

Pass --target-os=linux and --target-arch=x64 or arm64 to dart compile exe or aot-snapshot. Since Dart 3.8 any 64-bit Linux, macOS or Windows host can cross-compile, but only to Linux targets.

open as a page