Everything here applies to programming in general, written in Dart. If you already know another language, this will get you up to speed with Dart syntax. If you are completely new, start here.

For the full language reference, see the official Dart documentation.

Variables

Every program needs to store data. Variables give that data a name so you can use it later. Dart has four core types.

dart
String name = 'Mitch';
int age = 25;
double price = 9.99;
bool isActive = true;

You don't always need to write the type. Dart can figure it out with var. Use final when a value should only be set once, and constwhen it's known before the app even runs.

dart
var city = 'Toronto';      // type inferred as String
final id = 12345;          // set once at runtime
const pi = 3.14159;        // set at compile time

Operators

Operators let you do math, compare values, and combine conditions. You will use these constantly.

Arithmetic

dart
10 + 3    // 13    add
10 - 3    // 7     subtract
10 * 3    // 30    multiply
10 / 3    // 3.33  divide
10 ~/ 3   // 3     integer divide
10 % 3    // 1     remainder

Comparison

These return true or false.

dart
5 == 5    // true   equal
5 != 3    // true   not equal
5 > 3     // true   greater than
5 < 3     // false  less than
5 >= 5    // true   greater or equal
5 <= 3    // false  less or equal

Logical

Combine multiple conditions together.

dart
true && false   // false  AND (both must be true)
true || false   // true   OR  (at least one true)
!true           // false  NOT (flip it)

Assignment

Shorthand for updating a value.

dart
int x = 10;
x += 5;    // x = 15
x -= 3;    // x = 12
x *= 2;    // x = 24
x ~/= 4;   // x = 6

Null Safety

In Dart, variables cannot be null by default. This prevents a whole class of bugs. If a value might not exist, you mark it with ? and Dart will force you to handle that case.

dart
String name = 'Mitch';   // cannot be null
String? nickname;         // can be null

nickname ?? 'fallback'    // use fallback if null
nickname?.length          // safe access, returns null if null
nickname!                 // assert not null (throws if null)

Prefer ?? and ?. over !. The bang operator (!) will crash your app if the value is actually null.

Conditionals

Your code needs to make decisions. Conditionals let you run different code depending on whether something is true or false.

if / else

dart
if (age >= 18) {
  print('Adult');
} else if (age >= 13) {
  print('Teen');
} else {
  print('Child');
}

Ternary

A compact one-liner for simple conditions.

dart
String status = age >= 18 ? 'Adult' : 'Minor';

Switch

When you are checking one value against multiple options, switch is cleaner than chaining if/else.

dart
switch (status) {
  case 'active':
    print('Active');
  case 'inactive':
    print('Inactive');
  default:
    print('Unknown');
}

Loops

When you need to do something more than once, use a loop. There are three common patterns.

for

Best when you know exactly how many times to repeat.

dart
for (int i = 0; i < 5; i++) {
  print(i);  // 0, 1, 2, 3, 4
}

for-in

Best for going through a list of items.

dart
List<String> names = ['Alice', 'Bob', 'Charlie'];

for (final name in names) {
  print(name);
}

while

Keeps going until a condition becomes false.

dart
int count = 0;

while (count < 3) {
  print(count);
  count++;
}

Functions

As your code grows, you will want to organize it into reusable pieces. A function takes input, does something, and optionally returns output.

dart
int add(int a, int b) {
  return a + b;
}

// Arrow syntax for single expressions
int multiply(int a, int b) => a * b;

Dart also supports named parameters wrapped in {}. Add required to make them mandatory, or give them a default value.

dart
void greet(String name, {String? title}) {
  print('${title ?? ""} $name');
}

void log(String message, {int level = 0}) {
  print('[$level] $message');
}

greet('Mitch', title: 'Mr.');
log('App started');

Classes

A class is a blueprint for creating objects. It groups related data (properties) and behavior (methods) together. Almost everything in Dart is an object.

dart
class User {
  final String name;
  final int age;

  User({required this.name, required this.age});

  String greet() => 'Hi, I am $name';
}

final user = User(name: 'Mitch', age: 25);
print(user.greet());

You can extend a class to build on top of it. The child class inherits everything and can override specific behavior.

dart
class Admin extends User {
  final String role;

  Admin({required super.name, required super.age, required this.role});

  @override
  String greet() => 'Hi, I am $name ($role)';
}

Collections

Most apps work with groups of data. Dart gives you three built-in collection types.

List

Ordered and allows duplicates. This is the one you will use most.

dart
List<String> fruits = ['apple', 'banana', 'cherry'];
fruits.add('date');
fruits.remove('banana');
String first = fruits[0];

Map

Stores data as key-value pairs. Look up values by their key.

dart
Map<String, int> scores = {
  'math': 95,
  'science': 88,
};
scores['english'] = 92;
int? mathScore = scores['math'];

Set

Like a list, but every value must be unique.

dart
Set<int> ids = {1, 2, 3};
ids.add(2);  // ignored, already exists

Common Operations

These work on any collection.

dart
fruits.where((f) => f.startsWith('a'));   // filter
fruits.map((f) => f.toUpperCase());       // transform
fruits.contains('apple');                  // check
fruits.length;                             // count

Enums

An enum defines a fixed set of named values. Use them whenever a variable should only be one of a few specific options. You will see enums everywhere in Flutter (alignment, colors, status types).

dart
enum Status { active, inactive, banned }

Status userStatus = Status.active;

if (userStatus == Status.active) {
  print('User is active');
}

// Switch on all cases
switch (userStatus) {
  case Status.active:
    print('Active');
  case Status.inactive:
    print('Inactive');
  case Status.banned:
    print('Banned');
}

Async / Await

Almost every app needs to wait for something. An API call, a database read, a timer. In Dart, these operations return a Future, which is a value that will arrive later.

dart
Future<String> fetchUsername() async {
  await Future.delayed(Duration(seconds: 2));
  return 'Mitch';
}

Mark the function async, then use await to pause until the result is ready. Always wrap await calls in try/catch for anything that can fail, like network requests.

dart
void loadUser() async {
  try {
    final name = await fetchUsername();
    print(name);
  } catch (e) {
    print('Error: $e');
  }
}