Emergency server help: get in touch

Dart 3 Cheat Sheet: Null Safety, Records, Patterns and async

A compact Dart 3.13 reference covering the dart tool, null safety, collections, classes, records and patterns, errors, async code and dart:io.

Published 6 min read

Short answer: Create a command-line app with dart create -t console app, run it with dart run and build a native binary with dart compile exe. Types are non-nullable unless marked ?; handle null with ??, ?. and if (x != null). Use final for values set once and const for compile-time constants. Dart 3 adds records, pattern matching and sealed classes; Dart 3.13 adds primary constructors. Asynchronous code uses Future, async/await and Stream.

The examples in this Dart cheat sheet were run with the Dart SDK 3.13.5 (stable) on Linux on 9 October 2026, and checked with dart analyze.

The dart command

CommandWhat it does
dart create -t console appNew command-line project (bin/, lib/, test/, pubspec.yaml)
dart run / dart run bin/app.dart --flagRun the package or one file with arguments
dart compile exe bin/app.dart -o appSelf-contained native binary for the current OS
dart pub add httpAdd a dependency to pubspec.yaml and fetch it
dart pub get / dart pub upgradeFetch / upgrade dependencies
dart analyzeStatic analysis and lints
dart format .Format all Dart files
dart fix --applyApply automated fixes, e.g. after an SDK upgrade
dart testRun tests in test/ (uses package:test)
dart --versionShow the SDK version

New language features are enabled by the lower bound of the SDK constraint in pubspec.yaml. For example, sdk: ^3.13.0 turns on primary constructors.

Variables, types and null safety

SyntaxWhat it doesExample
varInferred, reassignablevar name = 'web01';
finalSet once at run timefinal port = 443;
constCompile-time constantconst maxUsers = 1_000;
int, double, num, String, boolCore typesdouble ratio = 0.75;
'$name:$port' / '${a + b}'String interpolation
'''...'''Multi-line string
int? maybe;Nullable type; defaults to null
maybe ?? 0Default when null
maybe ??= 5;Assign only if null
nick?.lengthNull-aware access; result is nullable
maybe!Assert non-null; throws if it is null
late String lazy;Non-nullable, initialised later (error if read first)
int.tryParse('8080')Parse, or null on failure (int.parse throws)

Control flow and functions

final msg = switch (code) {          // switch expression
  200 => 'ok',
  301 || 302 => 'redirect',
  >= 400 && < 500 => 'client error',
  _ => 'other',
};

String greet(String name, {String city = 'Leeds', required bool formal}) =>
    formal ? 'Good day $name from $city' : 'Hi $name';

int add(int a, [int b = 0]) => a + b;  // optional positional parameter

greet('Ali', formal: true);
greet('Sam', city: 'York', formal: false);
SyntaxWhat it does
for (var i = 0; i < 3; i++)Classic loop
for (final n in list)Loop over any Iterable
while / do { } whileLoops
{required String x}Named parameter that callers must pass
=> exprArrow body for a single expression
(int x) => x * xAnonymous function (closure)

Collections

SyntaxWhat it does
final nums = [5, 3, 8];List<int>; add, sort(), length, first, contains
nums.where((n) => n.isEven).toList()Filter (lazy until toList())
nums.map((n) => n * n).toList()Transform
nums.fold(0, (a, b) => a + b)Reduce to one value
final ports = {'ssh': 22};Map<String, int>; ports['ssh'] returns int?
ports.remove('ssh'), containsKeyRemove / test a key
counts.update(w, (v) => v + 1, ifAbsent: () => 1)Counting
final tags = {'a', 'b'};Set<String>
[...a, ...b]Spread
['-v', if (debug) '--debug', for (final t in tags) '#$t']Collection if and for
['-v', ?extra]Null-aware element: added only when extra is not null (Dart 3.8+)
list..sort()..add(1)Cascade: several calls on the same object

Classes, enums and extensions

// Dart 3.13 primary constructor: fields declared in the header
class Server(final String name, var int port) {
  String get address => '$name:$port';
}

class Host {
  final String name;
  final int port;
  Host(this.name, {this.port = 22});
  Host.web(String name) : this(name, port: 443);       // named constructor
  factory Host.fromJson(Map<String, dynamic> j) =>
      Host(j['name'] as String, port: j['port'] as int);
}

enum Level {
  low(1),
  high(5);

  const Level(this.weight);
  final int weight;
  bool get isHigh => weight > 3;
}

Level lv = .low;      // Dart 3.10 dot shorthand: type is inferred

extension on String {
  bool get isIp => RegExp(r'^\d{1,3}(\.\d{1,3}){3}$').hasMatch(this);
}
KeywordMeaning
extendsInherit from one class
implementsPromise to provide another type’s interface
with LoggerMix in a mixin
abstract interface classCan only be implemented, not instantiated
sealed classAll subtypes are in the same library, so switch can be exhaustive
final class / base classRestrict extending or implementing outside the library
@overrideMark an overriding member

Dart 3.13 also reserves final and var on ordinary parameters for primary constructors, so code such as void f(final int x) no longer compiles with sdk: ^3.13.0.

Records and pattern matching

(String, int) parseAddr(String s) {
  final parts = s.split(':');
  return (parts[0], int.parse(parts[1]));
}
final (host, port) = parseAddr('db1:5432');   // destructuring
final rec = (name: 'web', port: 80);          // named record fields
print(rec.port);

sealed class Event {}
class Login extends Event { Login(this.user, this.ok); final String user; final bool ok; }
class Restart extends Event { Restart(this.service); final String service; }
class Quit extends Event {}

String describe(Event e) => switch (e) {      // exhaustive: no default needed
      Login(user: var u, ok: false) => 'failed login $u',
      Login(:var user) => 'login $user',
      Restart(:var service) => 'restart $service',
      Quit() => 'quit',
    };

final json = {'user': 'bob', 'roles': ['admin']};
if (json case {'user': String u, 'roles': [String first, ...]}) {
  print('$u $first');                          // bob admin
}

Errors and async code

class ConfigException implements Exception {
  ConfigException(this.message);
  final String message;
  @override
  String toString() => 'ConfigException: $message';
}

try {
  parsePort('70000');
} on ConfigException catch (e) {
  print(e);
} catch (e, st) {            // anything else, with stack trace
  print('$e\n$st');
} finally {
  print('done');
}

Future<int> fetchStatus(String host) async {
  await Future.delayed(const Duration(milliseconds: 10));
  return host.length;
}

final results = await Future.wait([fetchStatus('a'), fetchStatus('bbb')]);
final v = await fetchStatus('db1').timeout(const Duration(seconds: 5));
SyntaxWhat it does
Future<T> + async / awaitOne value that arrives later
Future.wait([...])Run several futures and wait for all
.timeout(duration)Throws TimeoutException if too slow
Stream<T> + async* / yieldA sequence of values over time
await for (final x in stream)Consume a stream
await Isolate.run(() => heavyWork())Run CPU-heavy work on another isolate (dart:isolate)
rethrowRe-throw inside a catch block, keeping the stack trace

Files, processes and a log example

For server admins: a small dart:io tool that counts requests per client IP, compiled to a single binary with dart compile exe.

import 'dart:io';

Future<void> main(List<String> args) async {
  final path = args.isNotEmpty ? args.first : '/var/log/nginx/access.log';
  final file = File(path);
  if (!await file.exists()) {
    stderr.writeln('cannot read $path');
    exit(1);
  }
  final hits = <String, int>{};
  for (final line in await file.readAsLines()) {
    final ip = line.split(' ').first;
    hits.update(ip, (n) => n + 1, ifAbsent: () => 1);
  }
  final top = hits.entries.toList()..sort((a, b) => b.value.compareTo(a.value));
  for (final e in top.take(10)) {
    print('${e.value.toString().padLeft(7)} ${e.key}');
  }
}
SyntaxWhat it does
File(p).readAsString() / writeAsString(s)Whole file in or out (async; ...Sync versions exist)
File(p).openRead()Stream a large file instead of loading it
Directory(p).list()List a directory as a stream
await Process.run('systemctl', ['is-active', 'nginx'])Run a command; read exitCode and stdout
Platform.environment['HOME']Environment variable
jsonEncode(obj) / jsonDecode(text)JSON from dart:convert; classes need a toJson() method

Official documentation (checked 9 October 2026): Dart language tour · Dart: Patterns · Dart: Sound null safety · The dart command-line tool · Dart API reference · Dart changelog

Dart Cheat Sheet at a glance

Dart Cheat Sheet – short answer
In short: A compact Dart 3.13 reference covering the dart tool, null safety, collections, classes, records and patterns, errors, async code and dart:io.
Dart Cheat Sheet – what this guide covers
Dart Cheat Sheet: what this guide covers.

Related guides: Kotlin Cheat Sheet: Syntax, Null Safety and Collections · Swift Cheat Sheet: Syntax, Optionals, Protocols and async · TypeScript Cheat Sheet: Types, Generics and tsconfig.

Reading a lot of our guides? Go ad-free with srvScripts Pro for $6 a month. It also pays for new guides. Cancel any time.

Share this guide

Free website test

Is your website set up right?

Check SSL, security headers, redirects, robots.txt, sitemap, llms.txt and security.txt in one test. It takes about 30 seconds.