ZetCode

Dart control flow

last modified October 18, 2026

In this article we talk about the flow control in Dart. We define several keywords that enable us to control the flow of a Dart program.

When a Dart program is run, the code is executed from top to bottom. The flow of the program can be altered with various keywords, including if / else, for, while, and switch.

The control flow structures can be used to execute code conditionally or multiple times.

Dart if & else

The if statement specifies the conditional execution of a block. If the expression evaluates to true, the block is executed. If the else statement is present and the if expression evaluates to false, the block following else is executed. The condition must be a bool; Dart has no implicit conversion of numbers or strings to booleans.

There can be multiple if/else statements.

Dart if/else examples

The following examples demonstrate conditional execution of blocks with if/else.

main.dart
void main() {
  final value = 4;

  if (value > 0) {
    print('The number is positive');
  }
}

In the example we have a simple condition; if the value variable is positive, the message "The number is positive" is printed to the console. Otherwise, nothing is printed. The message is printed since value 4 is positive.

$ dart main.dart
The number is positive
main.dart
void main() {
  final value = -4;

  if (value > 0) {
    print('The number is positive');
  } else {
    print('The number is negative');
  }
}

Now we have added the second branch. The else statement specifies the block that is executed if the if condition fails. For the value -4, the message "The number is negative" is printed.

$ dart main.dart
The number is negative
main.dart
import 'dart:math';

void main() {
  const max = 10;
  final value = Random().nextInt(max) - 5;

  print('value: $value');

  if (value > 0) {
    print('The number is positive');
  } else if (value == 0) {
    print('The number is zero');
  } else {
    print('The number is negative');
  }
}

In this example, we add an additional branch with else if. We generate random integers from -5 to 4. With the help of the if and else statements we print a message for all three options. Because the number is random, the output differs from run to run.

$ dart main.dart
value: -3
The number is negative

Dart ternary and null-aware operators

For simple choices between two values, we can use the conditional (?:) operator. The ?? operator chooses the right operand when the left one is null.

main.dart
void main() {
  final age = 20;
  final String? name = null;

  final status = age >= 18 ? 'adult' : 'minor';
  print(status);

  print(name ?? 'anonymous');
}

The conditional expression yields a value, so it can be used where an if statement cannot, for instance in an initializer.

$ dart main.dart
adult
anonymous

Dart if-case

Since Dart 3, an if statement can contain a case clause with a pattern. The block is executed when the value matches the pattern, and the pattern can bind variables.

main.dart
void main() {
  final data = {'name': 'John Doe', 'age': 34};

  if (data case {'name': String name, 'age': int age}) {
    print('$name is $age years old');
  }

  final pair = [1, 2];

  if (pair case [int a, int b]) {
    print('sum: ${a + b}');
  }
}

The first pattern is a map pattern; it matches only if the map has a name string and an age integer. The second is a list pattern that matches a list of exactly two integers. The variables name, age, a, and b are available inside the corresponding blocks.

$ dart main.dart
John Doe is 34 years old
sum: 3

Dart switch statement

The switch statement is a selection control flow statement. It creates multiple branches in a simpler way than using the combination of if / else statements.

The switch keyword is used to test a value from the variable or the expression against a group of values. The values are presented with the case keyword. If the values match, the statement following the case is executed. There is an optional default clause. It is executed if no other match is found.

In Dart 3 and later, a non-empty case body does not fall through to the next case, so the break statement is optional. An empty case still falls through, which allows us to group several values.

main.dart
void main() {
  final dayOfWeek = DateTime.now().weekday;

  switch (dayOfWeek) {
    case DateTime.sunday:
      print('dies Solis');

    case DateTime.monday:
      print('dies Lunae');

    case DateTime.tuesday:
      print('dies Martis');

    case DateTime.wednesday:
      print('dies Mercurii');

    case DateTime.thursday:
      print('dies Jovis');

    case DateTime.friday:
      print('dies Veneris');

    case DateTime.saturday:
      print('dies Saturni');
  }
}

The example determines the current day of the week and prints its Latin equivalent.

switch (dayOfWeek) {
...
}

In the round brackets, the switch keyword takes a value from an expression, which is going to be tested. The body of the statement is placed inside a pair of curly brackets. In the body, we can place multiple case options.

case DateTime.sunday:
  print('dies Solis');

With the case clause, we test the value of the matching expression. If it is equal to DateTime.sunday, we print the Latin dies Solis.

$ dart main.dart
dies Solis

Empty cases can be grouped, and a case can match several values with the logical-or pattern ||. The default clause handles all the remaining values.

main.dart
void main() {
  final day = DateTime.saturday;

  switch (day) {
    case DateTime.saturday:
    case DateTime.sunday:
      print('weekend');
    case DateTime.monday || DateTime.friday:
      print('start or end of the work week');
    default:
      print('weekday');
  }
}

Saturday and Sunday are grouped by two consecutive cases; Monday and Friday share one case via the || pattern.

$ dart main.dart
weekend

Dart switch expression

A switch expression produces a value. Its cases use the => arrow and are separated by commas. The compiler checks that all possible values are covered, so for an enum or sealed class no default is needed.

main.dart
enum Level { low, medium, high }

String describe(Level level) => switch (level) {
      Level.low => 'Low priority',
      Level.medium => 'Medium priority',
      Level.high => 'High priority',
    };

String size(int n) => switch (n) {
      < 0 => 'negative',
      0 => 'zero',
      > 0 && < 10 => 'small',
      _ => 'large',
    };

void main() {
  print(describe(Level.medium));

  for (final n in [-3, 0, 5, 50]) {
    print('$n is ${size(n)}');
  }
}

The describe function covers every enum value, so the switch is exhaustive. In size, we use relational and logical patterns; the underscore _ matches anything else.

$ dart main.dart
Medium priority
-3 is negative
0 is zero
5 is small
50 is large

Dart while loop

The while statement is a control flow statement that allows code to be executed repeatedly based on a given boolean condition.

This is the general form of the while loop:

while (expression) {
  statement;
}

The while keyword executes the statements inside the block enclosed by the curly brackets. The statements are executed each time the expression is evaluated to true.

main.dart
void main() {
  var i = 0;
  var sum = 0;

  while (i < 10) {
    i++;
    sum += i;
  }

  print(sum);
}

In the code example, we calculate the sum of the values from 1 to 10. The while loop has three parts: initialization, testing, and updating. Each execution of the statement is called a cycle.

var i = 0;

We initiate the i variable. It is used as a counter.

while (i < 10) {
  ...
}

The expression inside the round brackets following the while keyword is the second phase: the testing. The statements in the body are executed until the expression is evaluated to false.

i++;

This is the last, third phase of the while loop: the updating. We increment the counter. Note that improper handling of the while loops may lead to endless cycles.

$ dart main.dart
55

Dart do-while loop

The do-while loop tests its condition after the body, so the body is always executed at least once.

main.dart
void main() {
  var n = 10;

  do {
    print('n = $n');
    n++;
  } while (n < 10);
}

Although the condition n < 10 is false from the start, the body runs once.

$ dart main.dart
n = 10

Dart classic for loop

The classic for loop was taken from the C programming language. A for loop has also three phases: initialization, condition and code block execution, and incrementation.

main.dart
void main() {
  var sum = 0;

  for (var i = 0; i < 10; i++) {
    sum += i;
  }

  print(sum);
}

In this example, we sum values 0..9 and print the result to the console.

for (var i = 0; i < 10; i++) {
  sum += i;
}

In the first phase, we initiate the counter i to zero. This phase is done only once. Next comes the condition i < 10. If the condition is met, the statement inside the for block is executed.

In the third phase the counter is increased. Now we repeat the phases 2 and 3 until the condition is not met and the for loop is left. In our case, when the counter i is equal to 10, the for loop stops executing.

$ dart main.dart
45

Dart for-in loop

The for-in form enables us to loop over an iterable easily. It is similar to the forEach function.

main.dart
void main() {
  final words = ['sky', 'load', 'cup', 'tea', 'rock', 'plate'];

  for (final word in words) {
    print(word);
  }
}

In the example, we define a list of words. With for-in we loop over the list and print all words.

$ dart main.dart
sky
load
cup
tea
rock
plate

Dart break and continue

The break statement terminates the execution of a loop created by while or for. The continue statement skips the rest of the current cycle and starts the next one.

main.dart
import 'dart:math';

void main() {
  const max = 30;
  final rnd = Random(7);

  while (true) {
    final value = rnd.nextInt(max);
    print(value);

    if (value == 22) {
      break;
    }
  }
}

We define an endless while loop. We use the break statement to get out of this loop. We choose a random value from 0 to 29 and print it. If the value equals 22, we finish the loop. The generator is seeded with 7 to make the output reproducible.

$ dart main.dart
10
17
8
9
6
8
22
main.dart
void main() {
  for (var i = 1; i <= 10; i++) {
    if (i.isEven) {
      continue;
    }

    print(i);
  }
}

In this example, we print the odd numbers up to 10. When the number is even, continue skips the print call.

$ dart main.dart
1
3
5
7
9

Dart labels

A label lets break and continue target an outer loop.

main.dart
void main() {
  outer:
  for (var i = 1; i <= 3; i++) {
    for (var j = 1; j <= 3; j++) {
      if (j == 3) continue outer;
      if (i == 3) break outer;
      print('i=$i, j=$j');
    }
  }
}

When j reaches 3, continue outer goes on with the next cycle of the outer loop. When i is 3, break outer leaves both loops.

$ dart main.dart
i=1, j=1
i=1, j=2
i=2, j=1
i=2, j=2

Source

Dart loops ยท Dart branches

In this article we have covered control flow in Dart.

Author

My name is Jan Bodnar, and I am a passionate programmer with extensive programming experience. I have been writing programming articles since 2007. To date, I have authored over 1,400 articles and 8 e-books. I possess more than ten years of experience in teaching programming.

List all Dart tutorials.