Skip to content
← writing

January 15, 2025 · 4 min read

Dart Basics: From Entry Point to Collections

A whirlwind tour of Dart's fundamentals — the entry point, variables, data types, control flow, and the core collections (List, Set, Map) you'll use in every program.

If you're coming to Dart from another language, most of it will feel familiar — but the details are worth getting right from day one. This is a whirlwind tour of the fundamentals: the entry point, variables, types, control flow, and the core collections you'll use in every program.

The entry point

Every Dart program starts at a top-level main function.

void main() {
  print('Hello, Dart');
}

// It can also take command-line arguments:
void main(List<String> args) {
  print('You passed ${args.length} args');
}

Variables

Use var to let Dart infer the type, or write the type explicitly. Use final for a value set once, and const for a compile-time constant.

var count = 3;          // inferred as int
int total = 10;         // explicit
final name = 'Ada';     // set once, at runtime
const pi = 3.14159;     // compile-time constant

late String greeting;   // initialized later, but before first use
greeting = 'Hi';

Rule of thumb: reach for final by default and only use var when the value genuinely changes.

Data types

The core built-in types:

int age = 30;
double price = 9.99;
num anything = 5;       // int or double
String title = 'Dart';
bool isReady = true;
List<int> scores = [1, 2, 3];
Map<String, int> ages = {'Ada': 36};
Object o = 'anything';  // the root type
dynamic d = 'no checks';// opts out of static checking — avoid

Strings support interpolation with $ and ${...}:

final user = 'Sam';
print('Welcome, $user — you have ${scores.length} scores');

Control flow

if / else if / else work as you'd expect, and there's a ternary for short cases.

if (age >= 18) {
  print('adult');
} else {
  print('minor');
}

final label = age >= 18 ? 'adult' : 'minor';

switch handles multi-way branches, and in modern Dart it can be an expression:

final tier = switch (score) {
  >= 90 => 'A',
  >= 80 => 'B',
  _ => 'C',
};

Lists

An ordered, growable collection.

final fruits = <String>['apple', 'banana'];
fruits.add('cherry');
print(fruits[0]);        // apple
print(fruits.length);    // 3
print(fruits.contains('banana')); // true

// Transform without a loop:
final upper = fruits.map((f) => f.toUpperCase()).toList();
final short = fruits.where((f) => f.length <= 5).toList();

Loops

Classic for, for-in, and while:

for (var i = 0; i < 3; i++) {
  print(i); // 0 1 2
}

for (final fruit in fruits) {
  print(fruit);
}

var n = 3;
while (n > 0) {
  n--;
}

Dart also has collection-for and collection-if for building lists inline:

final widgets = [
  const Header(),
  for (final f in fruits) Chip(label: f),
  if (isReady) const Footer(),
];

Sets

An unordered collection of unique values.

final tags = <String>{'dart', 'flutter'};
tags.add('dart');       // ignored — already present
print(tags.length);     // 2
print(tags.contains('flutter')); // true

final a = {1, 2, 3};
final b = {3, 4};
print(a.intersection(b)); // {3}
print(a.union(b));        // {1, 2, 3, 4}

Maps

Key–value pairs.

final capitals = <String, String>{
  'Iraq': 'Baghdad',
  'Japan': 'Tokyo',
};
capitals['Egypt'] = 'Cairo';
print(capitals['Japan']);           // Tokyo
print(capitals.containsKey('Iraq')); // true

for (final entry in capitals.entries) {
  print('${entry.key} -> ${entry.value}');
}

Functions

Functions are first-class. Use arrow syntax for one-liners, and named or optional parameters for clarity.

int add(int a, int b) => a + b;

String greet(String name, {String greeting = 'Hello'}) => '$greeting, $name';

greet('Ada');                 // Hello, Ada
greet('Ada', greeting: 'Hi'); // Hi, Ada

Where to go next

That's the toolkit for everyday Dart. Next, learn how these pieces come together in classes and objects — the foundation of Dart's object-oriented model — and lean into the type system: the more precise your types, the more the compiler helps you.