Skip to main content
dynamic is a special type annotation in Dart that explicitly disables static type checking for a variable, deferring all type resolution and member access validation to runtime. By assigning the dynamic type, you instruct the Dart analyzer to assume the variable supports any method or property, effectively opting it out of Dart’s sound static type system.

Core Mechanics

When a variable is declared as dynamic, the compiler permits reassignment to values of any type and allows the invocation of any method or property without compile-time errors. If the invoked member does not exist on the object’s actual runtime type, the Dart Virtual Machine (VM) throws a NoSuchMethodError during execution.
dynamic variable = 'Hello'; // Initially holds a String
variable = 42;              // Reassignment to an int is permitted

// The compiler allows this because static checking is disabled.
// However, it throws a NoSuchMethodError at runtime because 
// the int type does not have a 'substring' method.
variable.substring(1); 

Type System Relationships

To understand dynamic, it must be contrasted with other foundational type concepts in Dart:

dynamic vs. Object

Object (or Object?) is the root of the Dart class hierarchy. Both dynamic and Object can hold any value, but they interact with the compiler differently:
  • Object: Enforces static type checking. You can only invoke methods defined on the Object class (e.g., toString(), hashCode). To use type-specific methods, you must perform a safe cast (using as or is).
  • dynamic: Bypasses static type checking entirely. The compiler allows any method call without casting.
Object obj = 'Dart';
// obj.length; // COMPILE ERROR: The getter 'length' isn't defined for the class 'Object'.

dynamic dyn = 'Dart';
print(dyn.length); // COMPILES AND RUNS: Outputs 4.

dynamic vs. var

var is a keyword used for variable declaration that triggers type inference, whereas dynamic is an actual type.
  • If you initialize a variable using var, the compiler permanently locks the variable to the inferred type.
  • If you initialize a variable using dynamic, its type remains mutable at runtime.
var inferredString = 'Dart';
// inferredString = 10; // COMPILE ERROR: A value of type 'int' can't be assigned to a variable of type 'String'.

dynamic dynamicVariable = 'Dart';
dynamicVariable = 10;   // COMPILES AND RUNS.

Implicit dynamic

Dart will implicitly assign the dynamic type in specific scenarios where type information is absent and cannot be inferred: 1. Uninitialized var declarations: If a variable is declared with var but not initialized, Dart cannot infer its type and defaults to dynamic.
var uninitialized; // Implicitly typed as dynamic
uninitialized = 10;
uninitialized = 'String';
2. Omitted Generic Type Arguments: When instantiating a generic class (like collections) without specifying the type parameter, Dart defaults the type argument to dynamic.
List list = [1, 'two', 3.0]; // Implicitly List<dynamic>

Nullability

In Dart’s sound null safety system, dynamic is inherently nullable. It behaves equivalently to a nullable type (like String?), meaning a dynamic variable can hold a null value without requiring a ? suffix.
dynamic value = null; // Valid
Tired of Poor Dart Skills? Fix That With Deep Grasping!Learn More