Dart Variables and Data Types — Complete Beginner's Guide
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
finalandconst
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
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?..Using
varwhen 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.Confusing
finalwithconst:finalis a runtime constant set once.constis a compile-time constant. You cannot useDateTime.now()as aconstvalue.Modifying a
constcollection:const list = [1, 2, 3];creates a deeply immutable list.list.add(4)throws an error. Usefinal list = <int>[];for mutable collections that cannot be reassigned.Using
varat the class level: Class-level fields cannot usevar. Use explicit types orfinalinstead.varis only valid for local variables.
Practice Questions
- What is the difference between
var,final, andconstin Dart? - How does sound null safety prevent null pointer exceptions at compile time?
- What is type promotion and when does it occur?
- How would you create a variable that can hold either an int or a String?
- Challenge: Write a Dart program that declares a
constmap of country codes to country names, creates afinalcurrent 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
constfor a list of five programming language names - Use
finalfor the current timestamp - Use
varfor 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
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