Build beautiful, natively compiled apps for mobile, web, and desktop from a single codebase.
Flutter is Google's open-source UI toolkit for crafting natively compiled, beautiful applications across mobile, web, and desktop from a single Dart codebase.
iOS & Android apps with pixel-perfect native performance using a single codebase.
Compile to JavaScript and run in any modern browser with full fidelity.
Windows, macOS, and Linux native apps — all from the same project.
Smart TVs, automotive dashboards, and embedded displays via Flutter Embedder API.
See changes instantly without losing app state — drastically speeds up development.
Material 3 & Cupertino widgets out of the box, fully customisable and composable.
Flutter uses Dart — a fast, type-safe, object-oriented language optimized for client-side development.
Variables are non-nullable by default. The type system eliminates null-reference exceptions at compile time.
JIT compilation for fast dev cycles (hot reload). AOT for release builds — native speed performance.
First-class async support with Futures, Streams, and async/await syntax. No callback hell.
Optional type annotations with full type inference. Generics, mixins, extension methods all supported.
// Null safety: non-nullable by default String name = 'Flutter'; int version = 3; double rating = 4.9; bool isAwesome = true; // Nullable with ? String? nickname; // can be null // Type inference with var / final / const var message = 'Hello'; // inferred String final pi = 3.14159; // immutable at runtime const maxItems = 100; // compile-time constant // Collections List<String> fruits = ['apple', 'banana', 'mango']; Map<String, int> scores = {'Alice': 95, 'Bob': 87}; Set<int> unique = {1, 2, 3}; // String interpolation print('Hello, $name! Version ${version + 1}');
// Named & optional parameters String greet(String name, {String greeting = 'Hello'}) { return '$greeting, $name!'; } // Arrow functions int square(int n) => n * n; // Class with constructor class Person { final String name; final int age; // Constructor shorthand Person({required this.name, required this.age}); // Named constructor Person.anonymous() : name = 'Unknown', age = 0; // Getter bool get isAdult => age >= 18; // toString override @override String toString() => 'Person(name: $name, age: $age)'; } // Mixins mixin Flyable { void fly() => print('Flying!'); } class SuperHero extends Person with Flyable { SuperHero(String name) : super(name: name, age: 30); }
// Future — single async value Future<String> fetchUser(int id) async { await Future.delayed(Duration(seconds: 2)); return 'User $id'; } void main() async { final user = await fetchUser(42); print(user); // Error handling try { final data = await riskyOperation(); } catch (e) { print('Error: $e'); } } // Stream — async sequence of values Stream<int> countdown(int n) async* { for (int i = n; i >= 0; i--) { yield i; await Future.delayed(Duration(seconds: 1)); } } // Listen to stream countdown(5).listen((n) => print('$n...'));
Set up Flutter in minutes and create your first cross-platform app.
Download from flutter.dev/docs/get-started/install. Extract to a location like ~/flutter. Supports Windows, macOS, and Linux.
Add export PATH="$PATH:~/flutter/bin" to your shell profile (.bashrc, .zshrc). Reload shell.
Run flutter doctor to check all dependencies. It guides you to install Android SDK, Xcode, Chrome, etc.
Use VS Code with the Flutter extension, or Android Studio with the Flutter & Dart plugins for the best DX.
Run flutter create my_app. This scaffolds a complete project with pubspec.yaml, lib/, test/, etc.
Open a simulator or connect a device. Run flutter run to build and launch. Press r for hot reload!
# Check Flutter installation flutter doctor # Create new project flutter create my_awesome_app cd my_awesome_app # Get dependencies flutter pub get # Run on connected device/simulator flutter run # Build release APK for Android flutter build apk --release # Build for iOS flutter build ios --release # Build for web flutter build web # Add a package flutter pub add http
my_app/ ├── lib/ # Your Dart code lives here │ ├── main.dart # App entry point │ ├── screens/ # Screen widgets │ ├── widgets/ # Reusable widgets │ ├── models/ # Data models │ ├── services/ # API / DB services │ └── providers/ # State management ├── test/ # Unit & widget tests ├── android/ # Android-specific files ├── ios/ # iOS-specific files ├── web/ # Web-specific files ├── assets/ # Images, fonts, JSON └── pubspec.yaml # Dependencies & metadata
In Flutter, everything is a widget. From buttons to padding to the entire app — it's all composable widget trees.
// StatelessWidget: immutable, no internal state class GreetingCard extends StatelessWidget { const GreetingCard({ super.key, required this.name, }); final String name; @override Widget build(BuildContext context) { return Card( child: Padding( padding: const EdgeInsets.all(16), child: Text( 'Hello, $name!', style: const TextStyle(fontSize: 24), ), ), ); } }
// StatefulWidget: has mutable internal state class Counter extends StatefulWidget { const Counter({super.key}); @override State<Counter> createState() => _CounterState(); } class _CounterState extends State<Counter> { int _count = 0; @override Widget build(BuildContext context) { return Column( children: [ Text('Count: $_count', style: TextStyle(fontSize: 32)), ElevatedButton( onPressed: () => setState(() => _count++), child: const Text('Increment'), ), ], ); } }
Arrange children vertically, horizontally, layered, or in a scrollable list/grid.
Control size, color, decoration, padding, and alignment.
Pre-built Material Design 3 components following Google's design spec.
Collect user input with validation, decorations, and controllers.
Various button types with ripple effects, icons, and custom styles.
Display images from assets, network, or memory. Built-in fade-in effects.
Choosing the right state management approach is crucial. Flutter offers many options — from simple setState to full-blown architectures.
| Approach | Best For | Learning Curve | Boilerplate | Reactive |
|---|---|---|---|---|
| setState | Local widget state | ⭐ Low | ⭐ Minimal | Partial |
| InheritedWidget | Simple prop passing | ⭐⭐ Medium | ⭐⭐ Some | ✓ Yes |
| Provider | Small-medium apps | ⭐ Low | ⭐ Minimal | ✓ Yes |
| Riverpod | Medium-large apps | ⭐⭐ Medium | ⭐⭐ Some | ✓ Yes |
| BLoC | Large / enterprise | ⭐⭐⭐ High | ⭐⭐⭐ High | ✓ Yes |
| GetX | Rapid prototyping | ⭐ Low | ⭐ Minimal | ✓ Yes |
| MobX | Reactive patterns | ⭐⭐ Medium | ⭐⭐ Some | ✓ Yes |
// 1. Define a ChangeNotifier model class CartModel extends ChangeNotifier { final List<String> _items = []; List<String> get items => List.unmodifiable(_items); void add(String item) { _items.add(item); notifyListeners(); // rebuilds listening widgets } void remove(String item) { _items.remove(item); notifyListeners(); } } // 2. Provide it at the top of the tree void main() => runApp( ChangeNotifierProvider( create: (_) => CartModel(), child: const MyApp(), ), ); // 3. Consume with Consumer or context.watch class CartButton extends StatelessWidget { @override Widget build(BuildContext context) { final cart = context.watch<CartModel>(); return Badge( label: Text('${cart.items.length}'), child: IconButton( icon: const Icon(Icons.shopping_cart), onPressed: () {}, ), ); } }
import 'package:flutter_riverpod/flutter_riverpod.dart'; // Define a provider final counterProvider = StateNotifierProvider<CounterNotifier, int>( (ref) => CounterNotifier(), ); class CounterNotifier extends StateNotifier<int> { CounterNotifier() : super(0); void increment() => state++; void decrement() => state--; } // Wrap app with ProviderScope void main() => runApp(ProviderScope(child: MyApp())); // Use ConsumerWidget class CounterScreen extends ConsumerWidget { @override Widget build(BuildContext ctx, WidgetRef ref) { final count = ref.watch(counterProvider); return Scaffold( body: Center(child: Text('$count', style: TextStyle(fontSize:48))), floatingActionButton: FloatingActionButton( onPressed: () => ref.read(counterProvider.notifier).increment(), child: const Icon(Icons.add), ), ); } }
Flutter's layout is based on constraints flowing down and sizes bubbling up. Master it to build any UI imaginable.
Column( mainAxisAlignment: MainAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.start, children: [ Text('Title', style: TextStyle(fontSize: 24)), const SizedBox(height: 8), Row( children: [ Expanded(child: Text('Left')), // takes available width Flexible(child: Text('Right')), // flexible but won't force size ], ), Spacer(), // fills remaining space ElevatedButton(onPressed: (){}, child: Text('OK')), ], )
// Overlapping widgets with Stack Stack( children: [ Image.network('https://...', fit: BoxFit.cover), Positioned( bottom: 16, left: 16, child: Text('Caption', style: TextStyle(color: Colors.white)), ), Positioned(top: 8, right: 8, child: Icon(Icons.favorite)), ], ) // Responsive with LayoutBuilder LayoutBuilder( builder: (context, constraints) { if (constraints.maxWidth > 600) { return WideLayout(); // tablet/desktop } return NarrowLayout(); // phone }, ) // Adaptive sizing with MediaQuery final screenWidth = MediaQuery.of(context).size.width; final isTablet = screenWidth > 768;
Flutter makes async operations first-class with FutureBuilder, StreamBuilder, and the http / dio packages.
import 'dart:convert'; import 'package:http/http.dart' as http; // Data model class Post { final int id; final String title; final String body; const Post({required this.id, required this.title, required this.body}); factory Post.fromJson(Map<String, dynamic> json) => Post( id: json['id'] as int, title: json['title'] as String, body: json['body'] as String, ); } // Fetch from API Future<List<Post>> fetchPosts() async { final response = await http.get( Uri.parse('https://jsonplaceholder.typicode.com/posts'), ); if (response.statusCode == 200) { final data = jsonDecode(response.body) as List; return data.map((json) => Post.fromJson(json)).toList(); } throw Exception('Failed to load posts'); }
class PostsList extends StatelessWidget { @override Widget build(BuildContext context) { return FutureBuilder<List<Post>>( future: fetchPosts(), builder: (context, snapshot) { // Loading state if (snapshot.connectionState == ConnectionState.waiting) { return const Center(child: CircularProgressIndicator()); } // Error state if (snapshot.hasError) { return Center(child: Text('Error: ${snapshot.error}')); } // Data state final posts = snapshot.data!; return ListView.builder( itemCount: posts.length, itemBuilder: (ctx, i) => ListTile( title: Text(posts[i].title), subtitle: Text(posts[i].body), ), ); }, ); } }
Complete, copy-ready Flutter code samples you can drop into your project.
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 MainScreen(), ); } } class MainScreen extends StatefulWidget { const MainScreen({super.key}); @override State<MainScreen> createState() => _MainScreenState(); } class _MainScreenState extends State<MainScreen> { int _selectedIndex = 0; static const _screens = [ HomeTab(), SearchTab(), ProfileTab(), ]; @override Widget build(BuildContext context) { return Scaffold( body: IndexedStack( // preserves tab state index: _selectedIndex, children: _screens, ), bottomNavigationBar: NavigationBar( selectedIndex: _selectedIndex, onDestinationSelected: (i) => setState(() => _selectedIndex = i), destinations: const [ NavigationDestination(icon: Icon(Icons.home), label: 'Home'), NavigationDestination(icon: Icon(Icons.search), label: 'Search'), NavigationDestination(icon: Icon(Icons.person), label: 'Profile'), ], ), ); } }
class AnimatedHeartButton extends StatefulWidget { const AnimatedHeartButton({super.key}); @override State<AnimatedHeartButton> createState() => _AnimatedHeartButtonState(); } class _AnimatedHeartButtonState extends State<AnimatedHeartButton> with SingleTickerProviderStateMixin { late AnimationController _controller; late Animation<double> _scaleAnim; bool _liked = false; @override void initState() { super.initState(); _controller = AnimationController( vsync: this, duration: const Duration(milliseconds: 200), ); _scaleAnim = Tween(begin: 1.0, end: 1.4).chain( CurveTween(curve: Curves.elasticOut), ).animate(_controller); } void _onTap() { setState(() => _liked = !_liked); _controller.forward().then((_) => _controller.reverse()); } @override Widget build(BuildContext context) { return GestureDetector( onTap: _onTap, child: ScaleTransition( scale: _scaleAnim, child: Icon( _liked ? Icons.favorite : Icons.favorite_border, color: _liked ? Colors.red : Colors.grey, size: 32, ), ), ); } @override void dispose() { _controller.dispose(); super.dispose(); } }
class WaveWidget extends StatefulWidget { ... } class WavePainter extends CustomPainter { final double animValue; WavePainter(this.animValue); @override void paint(Canvas canvas, Size size) { final paint = Paint() ..color = Colors.blue.withOpacity(0.5) ..style = PaintingStyle.fill; final path = Path(); path.moveTo(0, size.height * 0.5); for (double x = 0; x <= size.width; x++) { final y = size.height * 0.5 + math.sin((x / size.width * 2 * math.pi) + animValue) * 30; path.lineTo(x, y); } path.lineTo(size.width, size.height); path.lineTo(0, size.height); path.close(); canvas.drawPath(path, paint); } @override bool shouldRepaint(WavePainter old) => old.animValue != animValue; }
Write clean, performant, and maintainable Flutter apps by following these proven guidelines.
const when possible. Flutter skips rebuilding const widgets even when the parent rebuilds — massive performance win.
ValueKey with a stable identifier.Consumer / Selector with Provider to narrow rebuild scope.ListView.builder for long lists — it lazily builds only visible items. Avoid ListView(children: [...]) with many items.cacheWidth/cacheHeight on Image.network. Use cached_network_image package for disk caching.
required parameters instead of nullable optionals. This makes API contracts explicit.! throws at runtime. Always verify with ??, ?., or guard clauses.Future should have error handling. Use try/catch with async/await. Implement proper error states in your UI.
ThemeData and access via Theme.of(context).AnimationController, TextEditingController, ScrollController, StreamSubscription in dispose().Semantics. Add meaningful labels for screen readers. Test with TalkBack (Android) and VoiceOver (iOS).
testWidgets() to render widgets in a test harness. Verify widget trees, tap events, text content.integration_test package for full app flows on real devices/emulators.matchesGoldenFile() to catch unintended visual regressions.
^1.0.0) for stability. Run flutter pub outdated regularly and update dependencies in a dedicated PR.
HTTP requests, interceptors, auth headers, file upload/download.
Manage app state predictably and efficiently.
Local persistence for preferences, structured data, and offline support.
Declarative routing with deep linking, shell routes, guards.
Efficient image caching, SVG rendering, image manipulation.
Lottie animations, skeleton loading, beautiful charts and graphs.
How does Flutter stack up against React Native, Xamarin, and native development?
| Feature | Flutter | React Native | Xamarin | Native |
|---|---|---|---|---|
| Language | Dart | JavaScript / TypeScript | C# / .NET | Swift / Kotlin |
| Rendering | Own engine (Skia/Impeller) | Native UI bridge | Native UI bridge | Native |
| Performance | Excellent | Good | Good | Best |
| UI Consistency | Pixel-perfect | Platform-varies | Platform-varies | Platform-native |
| Hot Reload | ✓ Yes | ✓ Yes | ✗ Limited | ✗ No |
| Desktop Support | ✓ Stable | ✓ Experimental | ✓ Yes | Platform-specific |
| Web Support | ✓ Yes | ✓ Yes | ✗ No | ✗ No |
| Package Ecosystem | Large (pub.dev) | Very Large (npm) | Medium | Platform-rich |
| Learning Curve | Medium (Dart) | Low (JS) | Medium (C#) | High (per platform) |
| Company Backing | Meta | Microsoft | Apple / Google |
Initial stable release. Mobile (iOS & Android) only. Introduced Dart 2 and the material widget library.
Web & desktop in stable channel. Null safety. New Navigator 2.0 API. Over 200 new APIs.
macOS & Linux apps stable. Impeller renderer preview. Material 3 support. Casual games toolkit.
Impeller as default on iOS. Dart 3 with records, patterns & sealed classes. Improved Wasm support for web.