Migration to Flutter Guide
Discover our battle-tested 21-step framework for a smooth and successful migration to Flutter!
Home
Glossary

InheritedWidget in Flutter

What is InheritedWidget in Flutter?

InheritedWidget is a Flutter widget class that efficiently propagates data down the widget tree, allowing descendants to access it without passing the data explicitly through every constructor.

When an InheritedWidget is updated, Flutter uses updateShouldNotify to determine whether widgets that depend on it should be notified and potentially rebuilt. An unrelated ancestor rebuild does not, by itself, rebuild every dependent widget. However, a regular InheritedWidget tracks dependencies at the widget level rather than per individual field, so when it reports a change, all widgets depending on that InheritedWidget may rebuild.

This mechanism is used by Flutter APIs such as Theme and MediaQuery, and by higher-level packages such as provider. InheritedWidget is therefore a low-level Flutter mechanism for propagating values and tracking dependencies, rather than a competing alternative to those APIs.

Key facts at a glance

  • InheritedWidget is part of Flutter's core widgets library and requires no external package.
  • Descendants access it with context.dependOnInheritedWidgetOfExactType<T>(), typically exposed through a static of(context) method. This also registers the widget as a dependent.
  • When an InheritedWidget is updated, updateShouldNotify determines whether its dependents should be notified that the inherited data has changed and potentially rebuilt.
  • A dependent widget is not rebuilt merely because an unrelated ancestor rebuilds. However, a regular InheritedWidget does not track dependencies at the individual-field level: when updateShouldNotify reports a change, all widgets depending on that InheritedWidget may rebuild.
  • Theme.of(context) and MediaQuery.of(context) use the InheritedWidget mechanism under the hood to propagate values and track dependencies.
  • The provider package builds a higher-level API around this mechanism, reducing boilerplate and making dependency access and lifecycle management more convenient. InheritedWidget is therefore an underlying Flutter mechanism, not a competing alternative to provider.

How do I create and use an InheritedWidget in Flutter?

Define a class extending InheritedWidget, override updateShouldNotify, and add a static of method for descendants to call.

import 'package:flutter/material.dart';

class CartInfo extends InheritedWidget {
  const CartInfo({super.key, required this.itemCount, required super.child});

  final int itemCount;

  static CartInfo of(BuildContext context) {
    final CartInfo? result =
        context.dependOnInheritedWidgetOfExactType<CartInfo>();
    assert(result != null, 'No CartInfo found in context');
    return result!;
  }

  @override
  bool updateShouldNotify(CartInfo oldWidget) {
    return itemCount != oldWidget.itemCount;
  }
}

Any descendant can now call CartInfo.of(context).itemCount and will be notified when itemCount changes, rather than merely because an unrelated ancestor widget rebuilds.

InheritedWidget vs. the provider package

Raw InheritedWidgetprovider package
Boilerplate
You implement the inherited widget, typically including an of method and updateShouldNotifyReady-made providers and BuildContext extensions such as watch, read, and select
State changes
You define when dependents should be notified through updateShouldNotifyProviders can listen to objects such as ChangeNotifier and propagate their notifications
Multiple values
You can compose multiple InheritedWidgets, but the structure and access patterns are yours to designMultiProvider makes composing multiple providers more convenient
Selective dependencies
A regular InheritedWidget does not track dependencies per field; use separate inherited widgets or InheritedModel for finer-grained dependenciescontext.select can listen to a selected part of a provided value
Best for
Understanding Flutter's underlying mechanism and implementing framework/library-level abstractionsEveryday dependency injection and state management in application code

Verdict: provider is the practical choice for day-to-day application state, while understanding InheritedWidget gives you the foundation for understanding how Flutter propagates inherited data — and how APIs such as Theme, MediaQuery, and provider build on that mechanism.

Best practices

  1. Override updateShouldNotify precisely – return true only when the inherited data has changed in a way that should cause its dependents to rebuild.
  2. Provide a static of(context) method when appropriate – it gives descendants a familiar way to access the inherited data and register a dependency, following the same pattern used by APIs such as Theme.of(context) and MediaQuery.of(context).
  3. Use dependOnInheritedWidgetOfExactType when a widget should react to changes – unlike getInheritedWidgetOfExactType, it registers the widget as a dependent.
  4. Reach for provider for typical application state and dependency injection – writing custom inherited widgets for everyday app code adds boilerplate that higher-level APIs can handle for you.
  5. Prefer narrow dependencies when an API provides them – for example, use MediaQuery.sizeOf(context) when you only need the screen size instead of depending on the entire MediaQueryData.

Common mistakes

  • Calling getInheritedWidgetOfExactType instead of dependOnInheritedWidgetOfExactType. The former does not register a dependency, so the widget will not be notified when the inherited widget changes.
  • Treating InheritedWidget and provider as competing choices. provider builds on Flutter's inherited-widget mechanism; the real question is whether to write the boilerplate yourself or let the package handle it.
  • Implementing updateShouldNotify too broadly or too narrowly. Returning true for every update can cause unnecessary rebuilds, while returning false when relevant data has changed prevents dependents from updating.
  • Storing mutable state directly on the InheritedWidget. Inherited widgets are immutable, like all Flutter widgets. If the inherited data needs mutable state, expose a separate mutable object such as a ChangeNotifier and let an appropriate higher-level abstraction manage its notifications.
  • Looking up inherited data in initState. If a widget needs to react to changes, establish the dependency from build or didChangeDependencies rather than initState.

Learn more

Design system Flutter

Building a Design System in a Large Flutter App

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.