initState is a Flutter method on State that runs exactly once, immediately after a StatefulWidget's State object is created, used for one-time setup like creating controllers or starting a subscription.
It's part of the broader Widget Lifecycle in Flutter; this page focuses specifically on initState itself, including the async question that comes up constantly: initState's signature is void initState(), so it can never be marked async directly.
initState in Flutter runs exactly once per State object, before the first build().void initState() – it cannot return a Future, so it can never be marked async.super.initState()BuildContext.dependOnInheritedWidgetOfExactType should not be called from initState. If a dependency on an inherited widget is needed, didChangeDependencies() should be used instead, as it is called immediately after initState().setState in initState is usually unnecessary, because the framework will call build() after initState() completes.Not directly on initState itself. A common approach is to call a separate async method without awaiting it inside initState.
import 'package:flutter/material.dart';
class ProfileScreen extends StatefulWidget {
const ProfileScreen({super.key});
@override
State<ProfileScreen> createState() => _ProfileScreenState();
}
class _ProfileScreenState extends State<ProfileScreen> {
String? _name;
@override
void initState() {
super.initState();
_loadProfile();
}
Future<void> _loadProfile() async {
final name = await fetchUserName();
if (!mounted) return;
setState(() => _name = name);
}
@override
Widget build(BuildContext context) {
return Text(_name ?? 'Loading…');
}
}_loadProfile() is called without await from initState(). The method starts executing synchronously and continues asynchronously after reaching await. Once the operation completes, it checks mounted before calling setState.
It’s tempting to write void initState() async { … } directly and await inside it - and Dart's compiler won’t stop you, since a void function is allowed to be async. Flutter’s framework does, though: it checks whether initState() returns a Future and throws the error "State.initState() must be a void method without an async keyword" the moment the widget builds. That check only runs when assertions are enabled, so don't rely on it as a safety net in every build mode - treat "never mark initState async" as the rule regardless.
initState – never try to mark initState itself async.mounted before calling setState after an await – the State may be disposed while the asynchronous operation is in progress.Theme.of(context), in didChangeDependencies rather than initState – BuildContext.dependOnInheritedWidgetOfExactType should not be called from initState.initState synchronous and fast – create controllers, initialize fields, and start asynchronous work, but don't wait for its results there.initState – values derived from the widget's initial properties can be assigned once here, while values that need to react to later changes should be handled through the appropriate lifecycle methods.initState as async. Flutter's framework detects the returned Future when the widget first builds and throws a FlutterError - asynchronous work should be moved to a separate async method instead.initState. Since initState should not be declared async, asynchronous work started there cannot be awaited. Instead, call a separate async method without awaiting it.setState after an await without checking mounted. The State may have been disposed before the asynchronous operation completes, making the subsequent setState invalid.Theme.of(context) or similar inherited-widget lookups in initState. BuildContext.dependOnInheritedWidgetOfExactType should not be called from initState. Such dependencies should be obtained in didChangeDependencies, which is called immediately after initState.
Flutter is known for its seamless UI/UX features and robust design elements. It allowed us to deliver a unique customer experience in the “CA24 Mobile” banking app. This article shares some of the learnings and pain points behind implementing it in this large project.

In this article, we’re sharing LeanCode’s 24 practical Flutter and Dart patterns that help you write less boilerplate, make your code cleaner, and catch mistakes earlier. Apply these patterns and you'll find yourself coding faster, communicating more clearly with your teammates, and spending less time debugging issues that the compiler could have caught.

Flutter is loved by many for its simple and fast development of high-quality cross-platform apps. Let’s take a closer look if Flutter is a suitable solution in every case, i.e., when developing mobile, web, and desktop applications.