Dart Code Style Guide

This guide summarizes key recommendations from the official Effective Dart documentation, covering style, documentation, language usage, and API design principles. Adhering to these guidelines promotes consistent, readable, and maintainable Dart code.

1. Style

1.1. Identifiers

  • DO name types, extensions, and enum types using UpperCamelCase.
  • DO name packages, directories, and source files using lowercase_with_underscores.
  • DO name import prefixes using lowercase_with_underscores.
  • DO name other identifiers (class members, top-level definitions, variables, parameters) using lowerCamelCase.
  • PREFER using lowerCamelCase for constant names.
  • DO capitalize acronyms and abbreviations longer than two letters like words (e.g., Http, Nasa, Uri). Two-letter acronyms (e.g., ID, TV, UI) should remain capitalized.
  • PREFER using wildcards (_) for unused callback parameters in anonymous and local functions.
  • DON'T use a leading underscore for identifiers that aren't private.
  • DON'T use prefix letters (e.g., kDefaultTimeout).
  • DON'T explicitly name libraries using the library directive.

1.2. Ordering

  • DO place dart: imports before other imports.
  • DO place package: imports before relative imports.
  • DO specify exports in a separate section after all imports.
  • DO sort sections alphabetically.

1.3. Formatting

  • DO format your code using dart format.
  • CONSIDER changing your code to make it more formatter-friendly (e.g., shortening long identifiers, simplifying nested expressions).
  • PREFER lines 80 characters or fewer.
  • DO use curly braces for all flow control statements (if, for, while, do, try, catch, finally).

2. Documentation

2.1. Comments

  • DO format comments like sentences (capitalize the first word, end with a period).
  • DON'T use block comments (/* ... */) for documentation; use // for regular comments.

2.2. Doc Comments

  • DO use /// doc comments to document members and types.
  • PREFER writing doc comments for public APIs.
  • CONSIDER writing a library-level doc comment.
  • CONSIDER writing doc comments for private APIs.
  • DO start doc comments with a single-sentence summary.
  • DO separate the first sentence of a doc comment into its own paragraph.
  • AVOID redundancy with the surrounding context (e.g., don't repeat the class name in its doc comment).
  • PREFER starting comments of a function or method with third-person verbs if its main purpose is a side effect (e.g., “Connects to...”).
  • PREFER starting a non-boolean variable or property comment with a noun phrase (e.g., “The current day...”).
  • PREFER starting a boolean variable or property comment with “Whether” followed by a noun or gerund phrase (e.g., “Whether the modal is...”).
  • PREFER a noun phrase or non-imperative verb phrase for a function or method if returning a value is its primary purpose.
  • DON'T write documentation for both the getter and setter of a property.
  • PREFER starting library or type comments with noun phrases.
  • CONSIDER including code samples in doc comments using triple backticks.
  • DO use square brackets ([]) in doc comments to refer to in-scope identifiers (e.g., [StateError], [anotherMethod()], [Duration.inDays], [Point.new]).
  • DO use prose to explain parameters, return values, and exceptions.
  • DO put doc comments before metadata annotations.

2.3. Markdown

  • AVOID using markdown excessively.
  • AVOID using HTML for formatting.
  • PREFER backtick fences (```) for code blocks.

2.4. Writing

  • PREFER brevity.
  • AVOID abbreviations and acronyms unless they are obvious.
  • PREFER using “this” instead of “the” to refer to a member's instance.

3. Usage

3.1. Libraries

  • DO use strings in part of directives.
  • DON'T import libraries that are inside the src directory of another package.
  • DON'T allow an import path to reach into or out of lib.
  • PREFER relative import paths when not crossing the lib boundary.

3.2. Null Safety

  • DON'T explicitly initialize variables to null.
  • DON'T use an explicit default value of null.
  • DON'T use true or false in equality operations (e.g., if (nonNullableBool == true)).
  • AVOID late variables if you need to check whether they are initialized; prefer nullable types.
  • CONSIDER type promotion or null-check patterns for using nullable types.

3.3. Strings

  • DO use adjacent strings to concatenate string literals.
  • PREFER using interpolation ($variable, ${expression}) to compose strings and values.
  • AVOID using curly braces in interpolation when not needed (e.g., '$name' instead of '${name}').

3.4. Collections

  • DO use collection literals ([], {}, <type>{}) when possible.
  • DON'T use .length to check if a collection is empty; use .isEmpty or .isNotEmpty.
  • AVOID using Iterable.forEach() with a function literal; prefer for-in loops.
  • DON'T use List.from() unless you intend to change the type of the result; prefer .toList().
  • DO use whereType() to filter a collection by type.
  • AVOID using cast() when a nearby operation (like List<T>.from() or map<T>()) will do.

3.5. Functions

  • DO use a function declaration to bind a function to a name.
  • DON'T create a lambda when a tear-off will do (e.g., list.forEach(print) instead of list.forEach((e) => print(e))).

3.6. Variables

  • DO follow a consistent rule for var and final on local variables (either final for non-reassigned and var for reassigned, or var for all locals).
  • AVOID storing what you can calculate (e.g., don't store area if you have radius).

3.7. Members

  • DON'T wrap a field in a getter and setter unnecessarily.
  • PREFER using a final field to make a read-only property.
  • CONSIDER using => for simple members (getters, setters, single-expression methods).
  • DON'T use this. except to redirect to a named constructor or to avoid shadowing.
  • DO initialize fields at their declaration when possible.

3.8. Constructors

  • DO use initializing formals (this.field) when possible.
  • DON'T use late when a constructor initializer list will do.
  • DO use ; instead of {} for empty constructor bodies.
  • DON'T use new.
  • DON'T use const redundantly in constant contexts.

3.9. Error Handling

  • AVOID catch clauses without on clauses.
  • DON'T discard errors from catch clauses without on clauses.
  • DO throw objects that implement Error only for programmatic errors.
  • DON'T explicitly catch Error or types that implement it.
  • DO use rethrow to rethrow a caught exception to preserve the original stack trace.

3.10. Asynchrony

  • PREFER async/await over using raw Futures.
  • DON'T use async when it has no useful effect.
  • CONSIDER using higher-order methods to transform a stream.
  • AVOID using Completer directly.

4. API Design

4.1. Names

  • DO use terms consistently.
  • AVOID abbreviations unless more common than the unabbreviated term.
  • PREFER putting the most descriptive noun last (e.g., pageCount).
  • CONSIDER making the code read like a sentence when using the API.
  • PREFER a noun phrase for a non-boolean property or variable.
  • PREFER a non-imperative verb phrase for a boolean property or variable (e.g., isEnabled, canClose).
  • CONSIDER omitting the verb for a named boolean parameter (e.g., growable: true).
  • PREFER the “positive” name for a boolean property or variable (e.g., isConnected over isDisconnected).
  • PREFER an imperative verb phrase for a function or method whose main purpose is a side effect (e.g., list.add(), window.refresh()).
  • PREFER a noun phrase or non-imperative verb phrase for a function or method if returning a value is its primary purpose (e.g., list.elementAt(3)).
  • CONSIDER an imperative verb phrase for a function or method if you want to draw attention to the work it performs (e.g., database.downloadData()).
  • AVOID starting a method name with get.
  • PREFER naming a method to___() if it copies the object's state to a new object (e.g., toList()).
  • PREFER naming a method as___() if it returns a different representation backed by the original object (e.g., asMap()).
  • AVOID describing the parameters in the function‘s or method’s name.
  • DO follow existing mnemonic conventions when naming type parameters (e.g., E for elements, K, V for map keys/values, T, S, U for general types).

4.2. Libraries

  • PREFER making declarations private (_).
  • CONSIDER declaring multiple classes in the same library if they logically belong together.

4.3. Classes and Mixins

  • AVOID defining a one-member abstract class when a simple function (typedef) will do.
  • AVOID defining a class that contains only static members; prefer top-level functions/variables or a library.
  • AVOID extending a class that isn't intended to be subclassed.
  • DO use class modifiers (e.g., final, interface, sealed) to control if your class can be extended.
  • AVOID implementing a class that isn't intended to be an interface.
  • DO use class modifiers to control if your class can be an interface.
  • PREFER defining a pure mixin or pure class to a mixin class.

4.4. Constructors

  • CONSIDER making your constructor const if the class supports it (all fields are final and initialized in the constructor).

4.5. Members

  • PREFER making fields and top-level variables final.
  • DO use getters for operations that conceptually access properties (no arguments, returns a result, no user-visible side effects, idempotent).
  • DO use setters for operations that conceptually change properties (single argument, no result, changes state, idempotent).
  • DON'T define a setter without a corresponding getter.
  • AVOID using runtime type tests to fake overloading.
  • AVOID public late final fields without initializers.
  • AVOID returning nullable Future, Stream, and collection types; prefer empty containers or non-nullable futures of nullable types.
  • AVOID returning this from methods just to enable a fluent interface; prefer method cascades.

4.6. Types

  • DO type annotate variables without initializers.
  • DO type annotate fields and top-level variables if the type isn't obvious.
  • DON'T redundantly type annotate initialized local variables.
  • DO annotate return types on function declarations.
  • DO annotate parameter types on function declarations.
  • DON'T annotate inferred parameter types on function expressions.
  • DON'T type annotate initializing formals.
  • DO write type arguments on generic invocations that aren't inferred.
  • DON'T write type arguments on generic invocations that are inferred.
  • AVOID writing incomplete generic types.
  • DO annotate with dynamic instead of letting inference fail silently.
  • PREFER signatures in function type annotations.
  • DON'T specify a return type for a setter.
  • DON'T use the legacy typedef syntax.
  • PREFER inline function types over typedefs.
  • PREFER using function type syntax for parameters.
  • AVOID using dynamic unless you want to disable static checking.
  • DO use Future<void> as the return type of asynchronous members that do not produce values.
  • AVOID using FutureOr<T> as a return type.

4.7. Parameters

  • AVOID positional boolean parameters.
  • AVOID optional positional parameters if the user may want to omit earlier parameters.
  • AVOID mandatory parameters that accept a special “no argument” value.
  • DO use inclusive start and exclusive end parameters to accept a range.

4.8. Equality

  • DO override hashCode if you override ==.
  • DO make your == operator obey the mathematical rules of equality (reflexive, symmetric, transitive, consistent).
  • AVOID defining custom equality for mutable classes.
  • DON'T make the parameter to == nullable.

Sources: