Skip to main content
A record is an anonymous, immutable, aggregate type in Dart that allows bundling multiple objects into a single value. Records are fixed-size, heterogeneous, and structurally typed, meaning their type signature is determined entirely by the types, order, and names of their fields rather than a formal class declaration.

Syntax and Initialization

Records are instantiated using a comma-separated list of expressions enclosed in parentheses. They support both positional and named fields. A record with exactly one positional field requires a trailing comma in its instantiation. Without the trailing comma, Dart evaluates the construct as a standard parenthesized expression rather than a record.
// Single-element positional record (requires trailing comma)
var singleRecord = ('Dart',);

// Parenthesized expression (NOT a record)
var notARecord = ('Dart'); 

// Positional fields
var positionalRecord = ('Dart', 3.0, true);

// Named fields
var namedRecord = (language: 'Dart', version: 3.0, isCompiled: true);

// Mixed fields
var mixedRecord = ('Dart', version: 3.0, isCompiled: true);

Type Annotations

A record’s type is a structural combination of its field types. Positional fields are enclosed in parentheses, while named fields are enclosed in curly braces {} within the parentheses. Just like instantiation, a single-element positional record type requires a trailing comma.
// Single-element positional type annotation (requires trailing comma)
(String,) singleType = ('Dart',);

// Positional type annotation
(String, double, bool) positionalType = ('Dart', 3.0, true);

// Named type annotation
({String language, double version}) namedType = (language: 'Dart', version: 3.0);

// Mixed type annotation
(String, bool, {double version}) mixedType = ('Dart', true, version: 3.0);

Field Access

Fields are accessed using dot notation. Named fields are accessed via their declared identifier. Positional fields are accessed using a $ prefix followed by their 1-based index. Positional indexes skip named fields.
var record = ('Dart', version: 3.0, true);

// Accessing positional fields (1-indexed)
String lang = record.$1;
bool compiled = record.$2; 

// Accessing named fields
double ver = record.version;

Structural Equality

Records implement structural equality. Two records are considered equal (==) if they have the exact same “shape” (the same set of positional field types and named fields) and their corresponding field values are equal. For named fields, the order of declaration does not affect the shape, type, or equality. For positional fields, order is strictly enforced.
var recordA = (x: 1, y: 2);
var recordB = (x: 1, y: 2);
var recordC = (y: 2, x: 1); 

print(recordA == recordB); // true
print(recordA == recordC); // true (order of named fields is irrelevant)

var posA = (1, 2);
var posB = (2, 1);

print(posA == posB); // false (order of positional fields dictates type and equality)

Destructuring

Records integrate directly with Dart’s pattern matching, allowing their fields to be unpacked into distinct local variables in a single statement.
var record = ('Dart', version: 3.0);

// Destructuring positional and named fields
var (lang, version: ver) = record;

print(lang); // 'Dart'
print(ver);  // 3.0
Tired of Poor Dart Skills? Fix That With Deep Grasping!Learn More