Dart Language Basics

Dart is the language Flutter apps are written in. It's a modern, type-safe, object-oriented language developed by Google, designed to compile efficiently to native machine code (for fast release builds) as well as to JavaScript (for the web). A defining trait of Dart is that everything is an object — even numbers, booleans, and functions are objects with methods, which makes the language feel remarkably consistent. If you've used TypeScript, Java, Kotlin, or Swift, most of Dart's syntax will feel immediately familiar.

Declaring Variables: var, Explicit Types, final, and const

Dart gives you a few ways to declare a variable, and choosing the right one communicates intent to anyone reading your code (including future you).

// var: type is inferred from the assigned value
var counter = 0;
var appName = 'My Flutter App';

// Explicit type: you state the type up front
String name = 'Alice';
int age = 28;

// final: can only be set once, but at RUNTIME
final String userId = fetchCurrentUserId();

// const: a COMPILE-TIME constant, known before the app even runs
const double pi = 3.14159;

final and const both prevent reassignment, but they are not interchangeable — the difference is about when the value becomes fixed.

KeywordValue fixed atTypical use
finalRuntime — once, the first time it's assignedA value that depends on something computed while the app is running, e.g. the result of a function call, a widget's constructor parameter, the current time
constCompile time — must be knowable before the app runsFixed literal values: mathematical constants, fixed padding/sizes, and (importantly in Flutter) widgets that never change, since const widgets can be reused instead of rebuilt
Note: Every const value is also implicitly final (it's only ever assigned once), but not every final value qualifies as const — a const must be computable at compile time, so const userId = fetchCurrentUserId(); would fail to compile.

Core Built-In Types

Dart ships with a small set of built-in types that cover almost everything you'll need day to day:

TypeExampleNotes
intint age = 28;Whole numbers
doubledouble price = 9.99;Decimal (floating-point) numbers
StringString name = 'Alice';Text, single or double quotes both work
boolbool isActive = true;true / false
ListList<String> names = ['A', 'B'];An ordered, indexable collection (like an array)
MapMap<String, int> ages = {'Alice': 28};Key-value pairs
SetSet<String> tags = {'a', 'b'};An unordered collection of unique values
List<String> fruits = ['apple', 'banana', 'cherry'];
Map<String, int> stock = {'apple': 10, 'banana': 5};
Set<String> uniqueTags = {'sale', 'new'};

print(fruits[0]);       // apple
print(stock['apple']);   // 10

Null Safety: Dart's Defining Modern Feature

Since Dart 2.12, the language has sound null safety built in, and it's one of the most important things to understand early. By default, a type like String can never hold null — the compiler guarantees it. If you want a variable that is allowed to be null, you must explicitly mark the type as nullable by adding a ? after it.

String name = 'Alice';   // non-nullable: can NEVER be null
name = null;              // COMPILE ERROR: A value of type 'Null' can't be
                     // assigned to a variable of type 'String'

String? nickname;         // nullable: allowed to be null, defaults to null
nickname = null;         // fine — the '?' makes this legal
nickname = 'Al';          // also fine

This matters enormously in real apps: a function that returns String (not String?) is a guarantee, checked by the compiler at every call site, that you will never have to defensively check for null before using the result. Bugs that plague other languages ("null reference exception") are caught before your app ever runs.

Null-Aware Operators

When you do work with nullable types, Dart gives you three operators to handle them concisely:

OperatorMeaning
??"If null, use this default instead" — provides a fallback value
?."Safe navigation" — calls a method/property only if the object isn't null, otherwise evaluates to null instead of throwing
!"Trust me" — asserts to the compiler that a nullable value is definitely not null right now (throws at runtime if you're wrong)
String? nickname;

// ?? provides a default when the left side is null
String displayName = nickname ?? 'Anonymous';
print(displayName);  // Anonymous

// ?. calls .toUpperCase() only if nickname isn't null
print(nickname?.toUpperCase());  // null (no crash)

nickname = 'Al';
print(nickname?.toUpperCase());  // AL

// ! asserts "I know this is not null" -- use carefully
String forced = nickname!;
print(forced.length);  // 2
Note: Reach for ! sparingly — it turns off the compiler's safety net for that one expression. If you're wrong and the value actually is null, your app crashes at runtime with a clear error instead of the compiler catching it beforehand. Prefer ?? or an explicit null check when you can.

String Interpolation

Building strings out of variables is extremely common, and Dart makes it clean with the $ syntax — no manual concatenation needed.

String name = 'Alice';
int price = 20;
int quantity = 3;

// Simple variable: just $name
print('Hello, $name!');  // Hello, Alice!

// An expression needs curly braces: ${...}
print('Total: ${price * quantity}');  // Total: 60

Basic Control Flow

If you've written JavaScript, Java, or C#, Dart's control flow will look almost identical — worth a quick look at the syntax rather than a deep explanation.

int score = 85;

if (score >= 90) {
  print('Grade: A');
} else if (score >= 80) {
  print('Grade: B');
} else {
  print('Grade: C or below');
}

// Classic for loop
for (int i = 0; i < 3; i++) {
  print('Count: $i');
}

// for-in loop over a collection
for (final fruit in ['apple', 'banana']) {
  print(fruit);
}

// while loop
int attempts = 0;
while (attempts < 3) {
  attempts++;
}
Next steps: With variables, types, and null safety down, move on to Dart: Functions & Classes to learn how Dart organizes behavior and data.