An variable is a name we use to store and manipulate data within our program.
Once we have our environment ready, the next logical step is to learn how to store and manipulate data.
Dart is a statically typed language. This means that, unlike JavaScript (where a variable can be a number today and text tomorrow), in Dart once a variable is defined as text, it will always be text.
This, which may seem like a restriction at first, allows us to detect errors before running the application.
Variable Declaration
In Dart we have two main ways to declare variables: indicating the type explicitly or letting the language infer it (type inference).
Explicit Typing
It’s the classic form. We indicate the data type in front of the variable name.
String name = "Luis";
int age = 30;
double height = 1.75;
bool isOwner = true;
Type Inference with var
Dart is smart. If you assign an initial value to a variable, it already knows what type it is. For this we use the keyword var.
var city = "Madrid"; // Dart infers it's a String
// city = 10; // ❌ Error: You can't assign an 'int' to a 'String' variable
Even if we use var, the variable still has a fixed type. It’s not the same as dynamic (a special type that disables type checking and which we should avoid whenever possible).
Immutability: final and const
In modern development, and especially in Flutter, we prefer that things do not change (immutability) unless strictly necessary. For this we have final and const.
Both prevent a variable’s value from being modified after assignment, but they have a crucial difference:
final
It is defined at runtime. That is, the value is assigned when the program passes that line, and it doesn’t change afterward.
final currentDate = DateTime.now(); // ✅ Correct, it's calculated at execution
const
It is defined at compile time. The value must be known before the program starts. It is a value “set in stone”.
const pi = 3.1416; // ✅ Correct, it's a fixed value
// const date = DateTime.now(); // ❌ Error: DateTime.now() is not known at compile time
As a practical rule, use const for fixed values (configurations, static texts, styles) and final for values you get from a database or calculations but won’t modify later.
Null Safety
One of the most important features of modern Dart is Null Safety.
Historically, the most common error in programming has been trying to use a variable that was empty (null), causing the dreaded “Null Pointer Exception”. Dart solves this by design.
Non-nullable Variables by Default
In Dart, by default, a variable cannot contain null.
int age;
// print(age); // ❌ Error: The variable must be initialized before use.
age = null; // ❌ Error: The value 'null' cannot be assigned to a type 'int'.
This guarantees that if we receive an int, we have a 100% safe number.
Nullable Variables with ?
But what if we really need a variable to possibly have no value? (For example, a user who maybe hasn’t filled in their second surname).
We use the question mark ? after the type.
String? secondSurname;
secondSurname = null; // ✅ Now it's valid
Null Safety Operators
Working with variables that can be null requires care. Dart offers us three very convenient operators to handle this elegantly.
Assertion Operator !
It’s the “trust me” mode. We tell Dart: “I know this variable looks nullable, but I assure you it currently has data”.
String? possibleName = "Ana";
// print(possibleName.length); // ⚠️ Dart complains because it could be null
print(possibleName!.length); // ✅ We force access (Dangerous if you're wrong)
Use it only when you are 100% sure. If you’re wrong and it’s null, the App will crash.
Conditional Access ?.
It’s the safe way. “If the variable has data, access the property. If it’s null, return null (and don’t explode)”.
String? name;
print(name?.length); // Prints: null (no error)
Null Coalescing Operator ??
This operator is very useful. It’s used to provide a default value if the variable is null.
String? username; // Is null
String nameToShow = username ?? "Guest";
print(nameToShow); // Prints: "Guest"
This is super useful in Flutter for displaying texts when data from an API hasn’t arrived yet.
Complete Example
Let’s see an example that combines everything above:
void main() {
// Inference and mutable variables
var title = "Dart Course";
// Constant (compile time)
const version = 3.0;
// Variable that can be null
String? author;
// Assign value later
// author = "Luis";
// Using ?? for default value
print("Author: ${author ?? 'Anonymous'}"); // Shows: Author: Anonymous
}