Flutter Widgets Explained: Stateless vs Stateful (With Lifecycle & Interview Q&A)

If you don’t understand Stateless vs Stateful, you don’t understand Flutter.

Everything in Flutter is a widget — your text, your button, your layout box, even empty padding. But widgets are not all equal. The single most important distinction in Flutter, the one that appears in every beginner interview and underlies every UI decision you’ll make, is this: does this widget need to change after it’s built? The answer determines whether you use a StatelessWidget or a StatefulWidget — and getting it wrong leads to bugs, unnecessary rebuilds, and code that’s hard to reason about.

This article explains the difference visually, walks through the full StatefulWidget lifecycle, and gives you clean answers to the six interview questions every entry-level Flutter developer gets asked.


Table of Contents


1. What Is “State”?

Before comparing the two widget types, you need a precise definition. State is any data that can change during the lifetime of a widget — a counter value, whether a checkbox is ticked, text typed into a field, or whether a dropdown is open. When state changes, Flutter knows it needs to repaint that part of the screen.

The clearest mental model:

Analogy Widget type Why
🖼️ A printed photo StatelessWidget Designed once, never changes after printing
📺 A live TV screen StatefulWidget Updates its display in real time based on what’s happening

2. StatelessWidget — The Immutable Widget

A StatelessWidget is immutable. Once built, its properties are final and cannot change from within. It will only rebuild if its parent widget changes and passes it new data. There is no internal memory between renders.

Characteristic Detail
Core method Overrides build() — describes the UI
Internal data that changes None
Performance Lightweight — Flutter doesn’t need to track any changing state
Rebuild trigger Only when parent rebuilds and passes new props
Built-in examples Text, Icon, Image, Container with fixed content

Here’s the minimal, correct pattern:

Notice name is final. It’s passed in from the parent and never touched again. The build() method always produces the same output for the same input — this predictability is what makes stateless widgets fast and easy to test.


3. StatefulWidget — The Widget That Can Change

A StatefulWidget can change its appearance over time in response to user actions, animations, timers, or incoming data. To do this, it uses a companion State class that holds the mutable data separately from the widget’s own class.

💡 Why two classes?
All Flutter widgets are immutable — that’s a hard rule of the framework. So mutable data cannot live on the widget itself. Flutter’s solution is to split responsibilities: the widget class holds configuration (immutable), and the State class holds data that can change. Flutter can then re-create the widget class freely without losing your state.
Characteristic Detail
Core method on widget createState() — returns the companion State object
Core method on State build() — describes the UI using current state data
Rebuild trigger Calling setState() inside the State class
Classes needed 2 — the widget class + the State class
Built-in examples Checkbox, TextField, Slider, Form

Here’s the minimal, correctly structured example — every line has a purpose:

Every time the button is tapped: _increment() fires → setState() runs → _count is updated → build() runs again → the screen shows the new number. This cycle is the heartbeat of every interactive Flutter UI.


4. Visual: How the Two Structures Compare


5. The StatefulWidget Lifecycle (In Full)

The State object goes through a defined sequence of lifecycle methods. Understanding this sequence is critical for initializing data correctly, avoiding memory leaks, and knowing when Flutter is about to rebuild your widget.

Lifecycle method Called when Typical use
initState() Once, when State object is created Initialize TextEditingController, fetch data, start animations
didChangeDependencies() After initState and when inherited deps change Access Theme.of(context) or MediaQuery.of(context) safely
build() On first render and every setState() call Describe the UI — keep it pure and fast, no side effects
didUpdateWidget() Parent rebuilds with new config React to changed props from parent (compare oldWidget to widget)
deactivate() Widget removed from tree temporarily Rarely overridden directly by beginners
dispose() Widget permanently removed from tree Always dispose controllers, subscriptions, timers here

Here’s what proper initState and dispose usage looks like in a real screen:


6. Side-by-Side Comparison

Feature StatelessWidget StatefulWidget
Can change over time? ❌ No ✅ Yes
Core method build() createState() + build()
Classes needed 1 2 — widget + State
Rebuild trigger Parent rebuild only setState() or parent rebuild
Performance overhead Lower — no state tracking Slightly higher — framework manages State object
Lifecycle hooks ❌ None initState, dispose, didUpdateWidget
Best for Text, icons, layout containers, static cards Forms, counters, toggles, animations, async data
Data mutability All fields are final State class can have mutable (non-final) fields

7. When to Use Which

The cleanest rule: start with Stateless, upgrade to Stateful only when needed. Using a StatefulWidget when you don’t need it is wasteful. Trying to use a StatelessWidget when you need state is a runtime logic error.

Situation Widget choice Reason
Displaying a user’s name from a profile object ✅ Stateless Data is passed in and doesn’t change inside the widget
Building a Row / Column layout structure ✅ Stateless Pure layout — no data changes inside it
A card showing a fixed product title and price ✅ Stateless Content comes from outside, never changes inside
A text field the user can type into ✅ Stateful Needs a TextEditingController and lifecycle management
A checkbox or toggle switch ✅ Stateful Checked/unchecked state lives inside the widget
A screen that loads API data on open ✅ Stateful Needs initState to trigger the fetch and setState to update UI
An animation that plays when the widget appears ✅ Stateful Needs an AnimationController with proper dispose()

8. Top 6 Beginner Interview Questions (With Answers)

These are the questions that appear most consistently in entry-level Flutter interviews. Knowing these cold will make you stand out.

Q1: What is the difference between StatelessWidget and StatefulWidget?

Answer: A StatelessWidget is immutable — its properties are set once and it never changes after being built. A StatefulWidget maintains a companion State object that can hold mutable data and trigger a UI rebuild by calling setState() whenever that data changes.

Q2: What does setState() do exactly?

Answer: It notifies the Flutter framework that the internal state of a widget has changed. Flutter then marks the widget as “dirty” and schedules a call to build(), which re-renders the widget with the updated data. Without calling setState(), your variables can change but the UI won’t update.

Q3: Why does a StatefulWidget need two classes?

Answer: All Flutter widgets must be immutable — that’s a framework-level constraint. So mutable data cannot live on the widget class itself. Flutter solves this by separating responsibilities: the widget class holds immutable configuration, and the State class holds mutable data. This allows Flutter to freely re-create the widget class (e.g. when a parent rebuilds) without destroying the State object or losing the data inside it.

Q4: What is initState() used for?

Answer: It’s called exactly once when the State object is first created, before the first build(). It’s the correct place to initialize TextEditingControllers, start animations, subscribe to streams, or trigger a one-time data fetch. It runs too early to safely call context-dependent APIs — use didChangeDependencies() for those.

Q5: What happens if you forget to call dispose()?

Answer: Resources like TextEditingController, AnimationController, and stream subscriptions won’t be released when the widget is removed from the tree. This causes memory leaks — those objects keep consuming memory and CPU even after the screen they belonged to is long gone. In a large app, this compounds over time and degrades performance.

Q6: Can a StatelessWidget be a child of a StatefulWidget?

Answer: Yes, and this is the standard pattern in production Flutter apps. A stateful parent manages changing data and owns the setState() calls. It passes the current values down to stateless child widgets that simply display them. This keeps logic centralized and child widgets lightweight and easy to test.

Ready to Apply This?

The best way to cement these concepts is to build something real. Our two-part series puts exactly this knowledge to work — Part 1 uses both widget types to build a notes app UI, and Part 2 adds persistence with proper lifecycle management:

Article What you’ll practice
Notes App Part 1: Project Setup & Core UI Building with both widget types, navigation, setState in practice
Notes App Part 2: Local Persistence & Polish initState for loading data, dispose for cleanup, async patterns
Show 11 Comments

11 Comments

Leave a Reply