Skip to content

Dart Variables and Data Types — Complete Beginner's Guide

DodaTech Updated 2026-06-28 8 min read

In this tutorial, you will learn about Dart Variables and Data Types. We cover key concepts, practical examples, and best practices to help you master this topic.

Dart variables are named storage locations that hold values of a specific type, with sound null safety ensuring that non-nullable variables can never contain null at runtime.

What You Will Learn

  • Declaring variables with var, final, const, and explicit types
  • Dart's built-in types: int, double, String, bool, and Records
  • Sound null safety and nullable vs non-nullable types
  • Type inference and when to use explicit annotations
  • Collection literals: List, Set, Map
  • The difference between final and const

Why It Matters

Variables are the foundation of every program. Dart's variable system is designed to catch errors at compile time rather than runtime. Sound null safety eliminates a whole class of null reference exceptions that plague languages like Java and JavaScript. Understanding how var, final, and const work in Dart will help you write code that is both safe and idiomatic, following the conventions used by the Dart and Flutter teams.

Real-World Use

In the DodaTech Flutter app, all state variables use var for mutable state, configuration constants use const to enable compile-time evaluation, and API endpoint URLs use final since they are assigned once during initialization. This discipline prevents accidental mutations and makes the codebase predictable.

Learning Path

flowchart LR
  A[Dart Installation] --> B[Dart Variables\nYou are here]
  B --> C[Control Flow]
  style B fill:#f90,color:#fff

Declaring Variables

Dart offers several ways to declare variables, each with different guarantees:

void main() {
  // Type inference with var
  var name = 'Alice'; // inferred as String
  var age = 30; // inferred as int
  var height = 1.75; // inferred as double

  // Explicit type annotation
  String city = 'New York';
  int population = 8336817;
  double area = 783.8;

  // Dynamic type (use sparingly)
  dynamic flexible = 'Can be anything';
  flexible = 42; // OK, but no type checking

  print('$name is $age years old, lives in $city');
}

Output:

Alice is 30 years old, lives in New York

Use var when the type is obvious from the initial value. Use explicit types when the type is not obvious or when you want to ensure a specific type. Avoid dynamic unless you are writing generic code that truly cannot know the type at compile time.

Sound Null Safety

Dart enforces sound null safety at compile time. Variables are non-nullable by default and cannot contain null:

void main() {
  // Non-nullable: cannot be null
  String message = 'Hello';
  // message = null; // COMPILE ERROR

  // Nullable: can be null
  String? nullableMessage = null;
  nullableMessage = 'Now it has a value';

  // Accessing nullable values safely
  String result = nullableMessage ?? 'Default value';
  print(result);

  // Null-aware access
  String? upper = nullableMessage?.toUpperCase();
  print(upper); // Prints: NOW IT HAS A VALUE
}

Output:

Now it has a value
NOW IT HAS A VALUE

The ? suffix declares a nullable type. The ?? operator provides a default when the value is null. The ?. operator calls a method only if the value is not null. Dart's flow analysis automatically promotes nullable types to non-nullable after a null check:

void printLength(String? text) {
  if (text != null) {
    // text is promoted to String (non-nullable) here
    print(text.length);
  } else {
    print('Text is null');
  }
}

Final and Const

final and const create variables that cannot be reassigned. const variables are compile-time constants, while final variables are set once at runtime:

void main() {
  // final: set once, can be computed at runtime
  final currentTime = DateTime.now();
  // currentTime = DateTime.now(); // COMPILE ERROR

  // const: compile-time constant
  const pi = 3.14159;
  const greeting = 'Hello';
  const list = [1, 2, 3]; // Deeply immutable

  // const must be computable at compile time
  // const bad = DateTime.now(); // COMPILE ERROR

  print('$greeting, pi is $pi, time is $currentTime');
}

Output:

Hello, pi is 3.14159, time is 2026-06-28 ...

Use const for values that are known at compile time (mathematical constants, configuration strings, enum values). Use final for values that are assigned once but cannot be known at compile time (API responses, current date, user input).

Built-in Types

Dart provides several built-in types that cover common data needs:

void main() {
  // Numbers
  int integer = 42;
  double floating = 3.14;
  // Dart 3+ also supports Records

  // Strings
  String singleLine = 'Single quotes work';
  String multiLine = '''
Multiple
lines
supported''';
  String interpolated = 'Value: $integer, expression: ${integer + 1}';

  // Booleans
  bool isActive = true;
  bool isComplete = false;

  // Records (Dart 3+)
  var record = ('Alice', 30, true);
  print('${record.\$1} is ${record.\$2} years old');

  // Printing
  print(singleLine);
  print('Active: $isActive');
}

Output:

Alice is 30 years old
Single quotes work
Active: true

Records group multiple values without defining a class. Access fields by position: $1, $2, $3. Records support named fields too: var named = (name: 'Alice', age: 30); accessed as named.name.

Collection Literals

Dart supports three collection types with concise literal syntax:

void main() {
  // List (ordered, indexed)
  var fruits = ['apple', 'banana', 'cherry'];
  fruits.add('date');
  print('First fruit: ${fruits[0]}');
  print('All fruits: $fruits');

  // Set (unordered, unique)
  var unique = {1, 2, 3, 1, 2};
  print('Unique values: $unique'); // {1, 2, 3}

  // Map (key-value pairs)
  var scores = {
    'Alice': 95,
    'Bob': 87,
    'Charlie': 92,
  };
  scores['Diana'] = 88;
  print("Alice's score: ${scores['Alice']}");
}

Output:

First fruit: apple
All fruits: [apple, banana, cherry, date]
Unique values: {1, 2, 3}
Alice's score: 95

Lists use square brackets, sets use curly braces, and maps use curly braces with colons. All collections are generic and type-safe.

Type Inference Rules

Dart's type inference follows specific rules based on the declaration keyword:

void main() {
  var a = 42; // int
  // a = 'text'; // COMPILE ERROR: String can't be assigned to int

  dynamic b = 42; // dynamic
  b = 'text'; // OK

  final c = 42; // int
  // c = 43; // COMPILE ERROR: final can't be reassigned

  Object d = 42; // Object
  // d is known as Object, not int
  if (d is int) {
    print('d is an int: ${d.isEven}'); // promoted to int
  }
}

Output:

d is an int: true

The is keyword checks the runtime type and promotes the variable to that type within the branch. This pattern is called type promotion and is a key feature of Dart's type system.

Common Mistakes

  1. Assigning null to non-nullable variables: Dart 3 requires null safety. All variables are non-nullable by default. Use String? for nullable values and always handle the null case with ?? or ?..

  2. Using var when type inference is ambiguous: When the initial value does not clearly indicate the type, use an explicit annotation. For example, var data = getData(); leaves the type unclear.

  3. Confusing final with const: final is a runtime constant set once. const is a compile-time constant. You cannot use DateTime.now() as a const value.

  4. Modifying a const collection: const list = [1, 2, 3]; creates a deeply immutable list. list.add(4) throws an error. Use final list = <int>[]; for mutable collections that cannot be reassigned.

  5. Using var at the class level: Class-level fields cannot use var. Use explicit types or final instead. var is only valid for local variables.

Practice Questions

  1. What is the difference between var, final, and const in Dart?
  2. How does sound null safety prevent null pointer exceptions at compile time?
  3. What is type promotion and when does it occur?
  4. How would you create a variable that can hold either an int or a String?
  5. Challenge: Write a Dart program that declares a const map of country codes to country names, creates a final current time, asks the user for a country code, and prints the matching country name using null-aware operators.

Mini Project

Create a Dart program that demonstrates all variable types:

  • Use const for a list of five programming language names
  • Use final for the current timestamp
  • Use var for a mutable list of developer names
  • Use nullable types for optional fields (middle name, nickname)
  • Use records to group user information (name, age, isActive)
  • Print all values with proper formatting

FAQ

Can I use `var` for class fields?

No. Class fields must have explicit types or use final. Use var only for local variables inside functions and methods.

What happens if I assign null to a non-nullable `var`?

The compiler rejects it with a compile-time error. Example: var x = null; infers x as Null type, which can only hold null and is rarely useful.

How do I check if a nullable variable is null?

Use if (variable != null) for promotion, or variable ?? defaultValue for a default, or variable?.method() for conditional access.

What is the `late` keyword?

late defers initialization to a later time. Use it for non-nullable fields that cannot be initialized at declaration time but will be initialized before first use.

Can I change the type of a variable declared with `var`?

No. The type is fixed at declaration based on the initializer. var x = 5; creates an int that cannot later hold a string.

What is Next

Now that you understand Dart variables, learn how to control program flow. Proceed to Control Flow in Dart for conditionals, loops, and switch expressions. Then explore Functions in Dart to learn about parameters, return types, and anonymous functions.

Built by the developers of DodaTech

Doda Browser, DodaZIP & Durga Antivirus Pro