dart_style: the opinionated formatter every Dart project inherits
An opinionated formatter/linter for Dart code
At a glance
- What is it?
- dart_style is the formatter bundled with the Dart SDK, an opinionated and only minimally configurable engine that rewrites whitespace, trailing commas and parameter list brackets in your code. It is safe to run automatically because it never breaks your code, and its line splitting is the part of the Dart toolchain most likely to surprise you.
- Who is it for?
- Adopt dart_style if you write Dart, because the SDK ships it and a project that does not run it will show up as a diff in every review. Do not adopt it as a general formatter for other languages, and do not expect the line splitting to match what you would have written by hand, since the formatter is deliberately opinionated and only minimally configurable.
- Can I use it commercially?
- Yes. BSD-3-Clause is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository received new commits within the last day.
- What is it written in?
- Mainly Dart, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 23, 2026, and from our analysis. They are not legal advice.
Editorial analysis
A formatter that rewrites whitespace and punctuation
The dart_style package defines an opinionated, minimally configurable automated formatter for Dart code. What it does is narrow and precise: it replaces the whitespace in your program with what it deems to be the best formatting for it, and it makes minor changes around non-semantic punctuation such as trailing commas and brackets in parameter lists.
The result is meant to follow the Dart style guide and to look nice to most human readers most of the time. The claim is modest and specific, and it is the right kind of claim for a formatter: it is not trying to restructure your code, only to lay it out.
The scope of what it handles is stated in the README in a way that explains why the formatter is more than a pretty printer. It handles indentation, inline whitespace and, by far the most difficult part, intelligent line wrapping. The documentation says it has no problems with nested collections, function expressions, long argument lists, or otherwise tricky code. That sentence is the whole difficulty of the project, and it is worth holding in mind when you read the rest of this: the formatter is not doing anything to the tokens, it is solving a layout problem, and the layout problem is genuinely hard.
The safety property is the one that makes automatic use viable. The formatter will never break your code, so you can safely invoke it automatically from build and presubmit scripts.
The before and after that shows what the line splitter does
The README shows the transformation with a real piece of code, a call to Process.start with a path expression, a list with a spread and a comment inside it, a working directory and an environment map with a nested conditional.
The input is a single run of long lines with the ternary and the list concatenated. The output breaks the call across many lines, splits the path.join call into its own block with one argument per line, expands the list so the spread and the comment sit on their own line, expands the environment map with each key on its own line, and splits the long conditional expression inside the map value across three lines. The trailing commas appear where the closing brackets move to their own line, which is the non-semantic punctuation change the README mentions.
Two observations. The formatter is not shy about vertical space: it would rather use more lines than produce a line that is too long, and the result reads top to bottom as a series of short expressions. And the comment inside the list is preserved and moved along with the item it belongs to, which is the sort of detail that separates a formatter that works on real code from one that works on expressions.
The nesting depth of the example is the point. Path joins, ternaries, a spread operator, an environment map and a null assertion all appear at once, and the output remains readable, which is the claim the documentation makes about nested collections, function expressions and long argument lists.
dart format is the entry point, not the package
Most people never install this package. The formatter is part of the unified dart developer tool included in the Dart SDK, so the command you actually run is dart format:
$ dart format my_file.dartThat command formats the file and writes the result back to the same file. It also takes a list of paths, and a path that points to a directory is processed recursively, so every .dart file in it and in all its subdirectories gets formatted.
Editors usually do this for you. IDEs and editors that support Dart normally provide easy ways to run the formatter, and in Visual Studio Code formatting Dart code uses the dart_style formatter by default, with most users having it set to reformat on every save. That last point matters for adoption: the formatter is often already running in a team without anyone deciding to adopt it, and the real decision is whether to keep it.
The output behaviour has one option that matters. By default dart format writes the result back to the same files. Passing --output show prints the formatted code to stdout and leaves the files alone, which is the switch to use when you want to see the diff before committing to it.
The exit code mode for a presubmit check
If you want the formatter in a presubmit script or a commit hook, the README describes a different invocation. The flags omit writing formatting changes to disk and change the exit code to indicate success or failure:
$ dart format --output=none --set-exit-if-changed .That is a different tool from the one most people use. The first form is an editor experience, a transformation applied to your files as you work. The second is a gate, a question asked of a tree of files: is every file in this repository already formatted, yes or no.
The distinction is worth getting right when you set this up in CI, because the two forms have different failure behaviour and different cost. The gate answers one question and is fast to reason about. The transform is the thing that has to run on every save on every machine, and if a developer's local SDK version formats differently from the one in CI, the gate will fail on files the developer believes are formatted. Pinning the SDK version across the team is what makes the gate meaningful, and that is a project decision rather than a formatter decision.
The repository layout gives a sense of the engineering behind the tool. Alongside lib/ and test/ there is a benchmark/ directory, a bin/ and a dist/ directory, an example/ directory containing format.dart, a tool/ directory for maintenance scripts, an analysis_options.yaml for the project's own static analysis, a CHANGELOG.md, and an AUTHORS file.
Using the formatter as a library from your own tools
The package also exposes a library API, and the README gives the shape of it. You import the package, construct a DartFormatter with a language version, and call format or formatStatement:
import 'package:dart_style/dart_style.dart';
main() {
final formatter = DartFormatter(
languageVersion: DartFormatter.latestLanguageVersion,
);
try {
print(formatter.format("""
library an_entire_compilation_unit;
class SomeClass {}
"""));
print(formatter.formatStatement("aSingle(statement);"));
} on FormatterException catch (ex) {
print(ex);
}
}Three things in that snippet carry information. The language version is passed explicitly rather than inferred, so a tool can format code according to the version of the language the target package declares, which matters for a language with evolving syntax. There are two entry points, one for a whole compilation unit and one for a single statement, so a tool that only has a fragment does not have to wrap it in a fake file. And the call is wrapped in a try for FormatterException, which is the error type the formatter raises, so a tool that formats user supplied or generated code can handle input that does not parse.
That last point is the practical reason to use the library rather than the command. A code generator, a template engine or a code review bot that produces Dart source needs to format its output, and it needs to deal with the case where the output is not valid Dart.
Opinionated by default, configurable only a little
The word opinionated in the first sentence of the README is load bearing, and the configuration link points to a wiki page rather than to a set of documented options. That is a deliberate choice, and it has consequences.
A formatter that is configurable in many dimensions is a formatter where every project ends up with a different dialect, and where the question of whether a diff is acceptable is settled by reading a config file rather than by knowing the language. dart_style takes the opposite position: the layout is decided, the code reads the same everywhere, and the few settings that exist are about which language version to target and how to treat trailing commas.
The trailing comma behaviour is where this is most visible in practice. The formatter makes minor changes around non-semantic punctuation like trailing commas, and in the example the transformed code gains trailing commas wherever a bracket moves onto its own line. In Dart, a trailing comma is a signal to the formatter that a construct should be split across lines, so the choice of whether to write one is not a style detail, it is an instruction. A team that fights the formatter is usually fighting this: a developer writes a call on one line, the formatter refuses to split it because there is no trailing comma, and the developer adds one to get the split they wanted.
The other side of the same coin is that the output is predictable. Since there are few settings, two developers on the same SDK version produce byte-identical output, which is the property that makes the presubmit gate in the previous section viable at all.
What the formatter will not do for you
The first limitation is that it is a formatter, not a linter, and the project description is precise about that, calling it an opinionated formatter and linter for Dart code, but the package itself documents only formatting. It will not tell you that a function is too long, that a name is unclear, or that a dependency is unused. Those are the analyzer's job, and the repository does carry an analysis_options.yaml, which is the static analysis configuration for the project itself rather than part of the formatter.
The second limitation is the one every Dart team meets eventually: the formatter's line splitting does not always match human intuition, and there is no escape hatch per expression. The rule is that the formatter decides where the line goes, and where the developer disagrees, the resolution in the Dart ecosystem is to restructure the code so the intent is unambiguous, for example by extracting a variable or introducing a named local. That is a real cost, and it is a genuine argument against enabling the formatter on an old codebase with unusual formatting habits: the diff is not cosmetic, it is a rewrite of how the expressions are laid out.
The third is version coupling. The formatter's output depends on the SDK version, because the language version is part of the decision. Two machines on different SDK versions can produce different output for the same file, and the fix is not a formatter setting but a version pin in the project's toolchain.
The real alternative is not another formatter, it is doing nothing. Plenty of Dart codebases run without a formatter, and the cost of that choice is that every review contains whitespace arguments and nobody can read a diff for anything but logic. The other alternative is a more configurable formatter such as a general-purpose code formatter that can be pointed at Dart, which trades the guaranteed consistency for a configuration file and a larger install. For a language with a first-party formatter shipped in the SDK, the choice is usually between the official opinion and nothing, and the official one has the advantage of already being on every developer's machine.
Editorial conclusion
Adopt dart_style if you write Dart, because the SDK ships it and a project that does not run it will show up as a diff in every review. Do not adopt it as a general formatter for other languages, and do not expect the line splitting to match what you would have written by hand, since the formatter is deliberately opinionated and only minimally configurable. Before you enforce it, run dart format --output=show over the existing codebase and read the diff, because a repository that was never formatted will produce a large first commit, and check the configuration wiki for the language version and trailing comma settings, since those are the knobs that decide how the formatter splits your code.
Frequently asked questions
What is dart_style?
It is an opinionated, minimally configurable automated formatter for Dart code that replaces the whitespace in your program and makes minor changes around non-semantic punctuation such as trailing commas. It is part of the unified dart developer tool included in the Dart SDK, so most users run it as dart format rather than installing the package.
How do I format Dart code from the command line?
Run dart format with a path. A file path formats that file, a directory path processes every .dart file in it and all its subdirectories, and by default the result is written back to the same files. Passing --output show prints the formatted code to stdout instead of modifying anything.
How do I check formatting in CI without changing files?
Use dart format --output=none --set-exit-if-changed . The output=none flag omits writing changes to disk and the set-exit-if-changed flag updates the exit code to indicate whether anything was unformatted, which is the form the documentation recommends for presubmit scripts and commit hooks.
Can I use dart_style as a library in my own tool?
Yes. The package exposes a library API: construct a DartFormatter with a languageVersion, then call format for a whole compilation unit or formatStatement for a single statement. Failures are reported as a FormatterException, which matters for tools that format generated or user supplied code.
Is dart_style still maintained?
The repository is not archived and the last push was on 2026-10-15, which is also the date of the v3.1.14 release. Earlier releases in the same series are v3.1.13 from 2026-08-26 and v3.1.12 from 2026-07-10, and the package is published under the BSD-3-Clause licence.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/dart-lang-dart-style)Was this useful?