The Complete Dart & Flutter Guide
Master Dart — Google's client-optimized language powering Flutter for building natively compiled apps across mobile, web, and desktop from a single codebase.
Why Learn Dart?
Dart was created by Google and unveiled in 2011. It was designed as a structured, flexible language for the modern web. Today, Dart is best known as the language behind Flutter — Google's UI toolkit that allows building beautiful, natively compiled applications from a single Dart codebase.
Dart features sound null safety, a strong type system, async/await for asynchronous programming, and compiles to native ARM code for mobile, native x64 for desktop, and JavaScript for web. Flutter apps built with Dart achieve near-native performance.
Dart is used by Google Pay, eBay Motors, and thousands of apps on the App Store and Google Play — all from a single Dart codebase.
Quick start: Install Flutter SDK which includes Dart. Run flutter create my_app to get started.
1. Dart Basics & Variables
Variables, Types, and Control Flow
Dart is statically typed with type inference via var. It supports final (runtime constant) and const (compile-time constant). All types are non-nullable by default with sound null safety.
void main() {
// Type inference
var name = 'Flutter Dev'; // String
var age = 25; // int
var height = 5.9; // double
var isActive = true; // bool
// Explicit types
String language = 'Dart';
int year = 2024;
// Constants
final pi = 3.14159; // runtime constant
const appName = 'MyFlutterApp'; // compile-time constant
// String interpolation
print('Hello, $name! You are $age years old.');
print('2 + 2 = ${2 + 2}');
// Null safety — nullable types use ?
String? nullableStr = null;
print(nullableStr?.toUpperCase() ?? 'no value');
// Control flow
for (var i = 1; i <= 5; i++) {
if (i % 2 == 0) {
print('$i is even');
} else {
print('$i is odd');
}
}
var fruits = ['apple', 'banana', 'mango'];
for (var fruit in fruits) {
print(fruit);
}
}2. Collections & Null Safety
Lists, Maps, Sets, and Null Safety
Dart collections are generic and type-safe. The spread operator and collection-if/for in collection literals make building lists expressive and clean.
void main() {
// List
List<String> colors = ['red', 'green', 'blue'];
colors.add('yellow');
colors.removeAt(0);
print(colors.length);
// Functional methods
var numbers = [1, 2, 3, 4, 5, 6];
var evens = numbers.where((n) => n.isEven).toList();
var doubled = numbers.map((n) => n * 2).toList();
var sum = numbers.reduce((a, b) => a + b);
print('Evens: $evens, Sum: $sum');
// Map (key-value pairs)
Map<String, int> scores = {'Alice': 95, 'Bob': 82, 'Carol': 88};
scores['Dave'] = 91;
scores.forEach((name, score) => print('$name: $score'));
// Spread operator
var list1 = [1, 2, 3];
var list2 = [4, 5, 6];
var combined = [...list1, ...list2]; // [1,2,3,4,5,6]
// Collection-if
var showExtras = true;
var items = ['a', 'b', if (showExtras) 'c', 'd'];
// Null safety patterns
String? maybeNull = null;
String safe = maybeNull ?? 'default'; // null coalescing
String? upper = maybeNull?.toUpperCase(); // null-aware call
String forced = maybeNull!; // null assertion (throws if null)
}3. Classes & Inheritance
Dart OOP Features
Dart supports classes, constructors (named, factory), getters/setters, inheritance, abstract classes, and mixins. Named constructors are common for creating objects from different sources.
abstract class Shape {
String get name;
double get area;
void describe() => print('$name with area ${area.toStringAsFixed(2)}');
}
class Circle extends Shape {
final double radius;
Circle(this.radius);
@override
String get name => 'Circle';
@override
double get area => 3.14159 * radius * radius;
}
class Rectangle extends Shape {
final double width, height;
Rectangle(this.width, this.height);
// Named constructor
Rectangle.square(double side) : width = side, height = side;
@override
String get name => 'Rectangle';
@override
double get area => width * height;
}
// Mixin
mixin Colorable {
String color = 'transparent';
void setColor(String c) => color = c;
void printColor() => print('Color: $color');
}
class ColoredCircle extends Circle with Colorable {
ColoredCircle(super.radius);
}
void main() {
var shapes = <Shape>[
Circle(5),
Rectangle(10, 4),
Rectangle.square(6),
];
for (var s in shapes) s.describe();
var cc = ColoredCircle(3);
cc.setColor('red');
cc.printColor();
}4. Async & Futures
Futures, async/await, and Streams
Dart's async model uses Futures for single async values and Streams for sequences of async values. The async/await syntax makes asynchronous code read like synchronous code.
import 'dart:async';
// Future — single async value
Future<String> fetchUsername(int id) async {
await Future.delayed(Duration(seconds: 1)); // simulate network
return 'user_$id';
}
// Chaining futures
Future<void> loadUserData() async {
try {
final username = await fetchUsername(42);
print('Loaded: $username');
// Multiple concurrent futures
final results = await Future.wait([
fetchUsername(1),
fetchUsername(2),
fetchUsername(3),
]);
print('All users: $results');
} catch (e) {
print('Error: $e');
}
}
// Stream — multiple async values over time
Stream<int> countUp(int max) async* {
for (var i = 1; i <= max; i++) {
await Future.delayed(Duration(milliseconds: 100));
yield i;
}
}
Future<void> main() async {
await loadUserData();
// Listen to a stream
await for (final value in countUp(5)) {
print('Tick: $value');
}
// StreamController
final controller = StreamController<String>();
controller.stream.listen((event) => print('Event: $event'));
controller.add('hello');
controller.add('world');
await controller.close();
}5. Flutter Widgets
Building UI with Flutter Widgets
In Flutter, everything is a widget. StatelessWidget renders fixed UI. StatefulWidget manages dynamic state. Widgets compose into a widget tree.
import 'package:flutter/material.dart';
void main() => runApp(const MyApp());
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
colorScheme: ColorScheme.fromSeed(seedColor: Colors.blue),
useMaterial3: true,
),
home: const CounterPage(),
);
}
}
class CounterPage extends StatefulWidget {
const CounterPage({super.key});
@override
State<CounterPage> createState() => _CounterPageState();
}
class _CounterPageState extends State<CounterPage> {
int _count = 0;
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('Counter')),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text('Count: $_count', style: Theme.of(context).textTheme.headlineMedium),
const SizedBox(height: 20),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
FloatingActionButton(
onPressed: () => setState(() => _count--),
child: const Icon(Icons.remove),
),
const SizedBox(width: 20),
FloatingActionButton(
onPressed: () => setState(() => _count++),
child: const Icon(Icons.add),
),
],
),
],
),
),
);
}
}6. State Management
Provider State Management
Provider is a popular Flutter state management solution. It uses ChangeNotifier to notify widgets of state changes, keeping UI in sync with your data model.
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
// ChangeNotifier model
class CartModel extends ChangeNotifier {
final List<String> _items = [];
List<String> get items => List.unmodifiable(_items);
int get itemCount => _items.length;
bool get isEmpty => _items.isEmpty;
void addItem(String item) {
_items.add(item);
notifyListeners(); // rebuild dependent widgets
}
void removeItem(String item) {
_items.remove(item);
notifyListeners();
}
void clear() {
_items.clear();
notifyListeners();
}
}
// Provide at root
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return ChangeNotifierProvider(
create: (_) => CartModel(),
child: MaterialApp(home: ShopPage()),
);
}
}
// Consume in widget
class CartBadge extends StatelessWidget {
@override
Widget build(BuildContext context) {
final cart = context.watch<CartModel>();
return Badge(
label: Text('${cart.itemCount}'),
child: const Icon(Icons.shopping_cart),
);
}
}Build Anything with Dart & Flutter!
Dart and Flutter give you the power to build beautiful, performant apps for every platform from a single codebase. The ecosystem is growing fast — now is the perfect time to start.