In Dart, a late
variable is one that you declare now but plan to fill in later. Instead of giving it a value right away, you’re saying, “I’ll set this up before I use it.” This is helpful when you want to delay the work of creating a value until the moment you actually need it.
Think of it like an empty water bottle that you keep on the table. You’re not pouring water in it yet, but you’re making it clear: “I’ll definitely fill this before drinking.” Dart trusts that you’ll give it a value before using it — and you will.
Using late
helps you avoid making a variable nullable (?
) just because you want to set it up later. It lets your code stay neat and clear while still giving you flexibility on when to initialize values.
Why Use late
?
You might choose to use late
when you know a variable will get a value, just not right away. Instead of using null
or adding a ?
to make it nullable, late
lets you delay the setup but still treat the variable like it always has a value.
Here are some good times to use late
:
- Initialize later: Sometimes you don’t have the value yet — maybe it comes from a function, a setup method, or user input.
- Avoid nullable types: You don’t want to deal with
null
checks.late
tells Dart, “Trust me, it won’t be null when I use it.” - Lazy setup: For big or expensive objects, you can delay creating them until they’re really needed — saving time and memory.
It’s a clean way to write safer code without forcing early initialization or null handling.
Declaring a late
Variable
To declare a late
variable, just use the late
keyword before the type and name of the variable. This tells Dart that the variable will be assigned a value later — not right now.
Syntax:
late String message;
In this example, message
is a String
that hasn’t been given a value yet. You promise Dart that it will get a value before you use it.
Here’s an example:
late String greeting;
void setupGreeting() {
greeting = "Hello, world!";
}
void main() {
setupGreeting();
print(greeting); // Outputs: Hello, world!
}
Here, the variable greeting
is declared at the top but only gets a value inside the setupGreeting()
function. It’s safe to use because it’s set before printing.
Assigning a Value to a late
Variable
Once you’ve declared a late
variable, you can assign its value later—anywhere in your code, before it’s used. This is helpful when the value isn’t known at the time of declaration or needs to come from a setup function or constructor.
You can assign the value in a function, a constructor, or at any point before the variable is used.
late int age;
void setAge() {
age = 12;
}
void main() {
setAge();
print('Age is $age'); // Outputs: Age is 12
}
Here’s an example of assigning a late
variable inside a constructor:
class User {
late String name;
User(String inputName) {
name = inputName;
}
}
void main() {
var user = User('Samantha');
print('User name: ${user.name}'); // Outputs: User name: Samantha
}
In both cases, the late
variable is assigned before it’s used, which keeps things safe and simple.
Using late
in a Class
The late
keyword is especially useful in classes when you want to declare fields that will be initialized later, such as in a constructor or setup method. This allows you to avoid making the fields nullable while still keeping flexibility in when they are set.
You can declare class fields with late
to tell Dart:
“This will be assigned later — don’t worry!”
class AppConfig {
late String apiUrl;
late int port;
void setup() {
apiUrl = 'https://example.com';
port = 8080;
}
}
void main() {
var config = AppConfig();
config.setup();
print('API URL: ${config.apiUrl}');
print('Port: ${config.port}');
}
In this example, the apiUrl
and port
fields are declared with late
, and their values are set later inside the setup()
method. This keeps your class clean and your code safe from using uninitialized variables.
Late with final
You can combine late
with final
to create a variable that is only assigned once, but not immediately. This is useful when you know the value will never change, but you want to set it later — like inside a constructor or the first time it’s needed.
class User {
late final String username;
User(String name) {
username = name;
}
}
void main() {
var user = User('Samantha');
print(user.username); // Output: Samantha
}
In this example, username
is a late final
variable. It’s set once in the constructor and can’t be changed after that.
Here’s yet another example:
String getGreeting() {
print('Generating greeting...');
return 'Good morning!';
}
late final String todayGreeting = getGreeting();
void main() {
print(todayGreeting); // Prints: Generating greeting... Good morning!
}
Here, the value is only created when it’s used the first time. After that, it stays the same.
Using late
with Getters
You can use late
with custom getters to perform lazy initialization — meaning the value is only computed when it’s actually needed. This is great for values that take time to calculate or depend on other data being ready first.
class Circle {
final double radius;
Circle(this.radius);
late final double area = _calculateArea();
double _calculateArea() {
print('Calculating area...');
return 3.14 * radius * radius;
}
}
void main() {
var circle = Circle(5);
print(circle.area); // Prints: Calculating area... 78.5
print(circle.area); // Prints: 78.5 (no recalculation)
}
In this example, the area
is marked as late final
, so it’s only calculated once when accessed. The method _calculateArea()
is called lazily — only when area
is first used.
This way, you delay the work until it’s really needed, and avoid doing it more than once.
Conclusion
The late
keyword in Dart is a powerful tool that helps you write cleaner code by allowing you to delay initialization while still using non-nullable types. It’s perfect when you know a variable will definitely be given a value before it’s used—just not right away. Whether you’re working in a class, a function, or a Flutter widget, late
lets you set things up just in time. Try using it when you’re sure a variable will be ready later—it helps keep your code tidy and clear.