Skip to main content
A constant variable in Dart is an immutable reference whose value cannot be reassigned after its initial assignment. Dart enforces immutability through two distinct keywords: final for runtime evaluation and const for compile-time evaluation.

The final Keyword

A final variable can be set only once. Its value is determined at runtime, meaning it can be initialized using the result of a function call, a constructor, or any expression evaluated during program execution. Once initialized, the reference cannot point to a different object.
final String language = 'Dart';
final DateTime initializationTime = DateTime.now(); // Valid: Evaluated at runtime

// language = 'Flutter'; // ERROR: The final variable 'language' can only be set once.

The const Keyword

A const variable is a strict compile-time constant. Its value must be entirely known, fixed, and evaluated during compilation. All const variables are implicitly final.
const double pi = 3.14159;
const int maxRetries = 5;
const int total = maxRetries * 2; // Valid: Math operations on constants are compile-time constants

// const DateTime time = DateTime.now(); // ERROR: Method invocation is not a constant expression.

Class-Level Constants

The application of final and const differs within class structures. Instance variables can be final (initialized via constructors), but they cannot be const. To define a compile-time constant associated with a class, you must use the static const modifiers.
class NetworkConfig {
  final String baseUrl; // Instance-level runtime constant
  
  static const int timeoutMilliseconds = 5000; // Class-level compile-time constant

  NetworkConfig(this.baseUrl);
}

Deep vs. Shallow Immutability

The choice between final and const dictates the depth of immutability for collections and objects.
  • final provides shallow immutability: It prevents the variable from being reassigned to a new memory address, but the internal state of the referenced object can still be mutated.
  • const provides deep, transitive immutability: It freezes the entire object graph. Neither the reference nor the internal state of the object can be altered.
// final: Reference is immutable, but the object is mutable
final List<int> finalList = [1, 2, 3];
finalList.add(4); // Valid: Modifies the internal state of the list
// finalList = [5, 6]; // ERROR: Cannot reassign a final variable

// const: Both reference and object are deeply immutable
const List<int> constList = [1, 2, 3];
// constList.add(4); // RUNTIME ERROR: Cannot add to an unmodifiable list
// constList = [5, 6]; // ERROR: Cannot reassign a const variable
Tired of Poor Dart Skills? Fix That With Deep Grasping!Learn More