Skip to content

Glossary

Flutter’s vocabulary spans several layers at once: the Dart language itself (null safety, records, patterns, class modifiers) that every other layer is written in; the three trees (widget, element, render) that explain almost everything about performance; state management (setState, InheritedWidget, Riverpod, BLoC) built directly on top of that element tree; navigation (Navigator, go_router) and platform channels for reaching outside Dart entirely; the constraints-based layout algorithm and the paint/composite/raster pipeline underneath every pixel; and the tooling and production concerns (testing, builds, crash reporting) that turn a widget tree into a shipped app. When a lesson uses a term you’re unsure about, or unsure whether it still holds for Flutter 3.47.5 / Dart 3.13, look it up here — every definition below is sourced from a lesson that proved it with a real flutter analyze/flutter test run or a real, quoted SDK source/doc, not from memory.

TermMeaningLesson
AnimatedOpacity / FadeTransitionImplicit animation wrappers around the same RenderOpacity/layer mechanism proven for the plain Opacity widget — they add ticker-driven scheduling and automatic disposal, not an exemption from paying for a real compositing layer on every non-zero alpha frame during the fade.Render Pipeline
AnimatedSwitcherCross-fades between two widgets when its child changes; whether it animates at all is decided by the child’s key — same key means “same widget updated in place,” no transition; a different key means “different widget,” and the switch animates.Animations
AnimationControllerDrives an explicit animation: vsync: this (needs a TickerProviderStateMixin), .value walks 0→1 over duration — proven directly with tester.pump(Duration) landing on exact intermediate values (0.50 at the halfway point with Curves.linear). Forgetting controller.dispose() throws a real, debug-mode-only assert: "was disposed with an active Ticker", from SingleTickerProviderStateMixin.dispose() in the installed Flutter 3.47.5 SDK.Animations
analysis_options.yaml (strict-casts / strict-inference / strict-raw-types)Three analyzer language options — off by default, not part of any lint package — that catch implicit dynamic leaking into typed code. Each has a distinct, real diagnostic: strict-casts gives invalid_assignment on an implicit dynamic → int narrowing; strict-raw-types gives strict_raw_type on a bare List; strict-inference gives inference_failure_on_collection_literal on an uninferred []. This course’s own probe runs with all three enabled.Project & Tooling
async / awaitasync makes a function return a Future<T>; await unwraps it and lets errors surface as normal, try/catch-able exceptions — proven directly against a rejected Future. You rarely await inside build; hand the Future to a FutureBuilder instead.Async in Dart
AsyncNotifier / AsyncValue.whenRiverpod’s async-state provider: build() returns a Future<T>, and ref.watch exposes an AsyncValue<T> you branch on with .when(data:, error:, loading:). Riverpod 3 gives every provider an automatic retry policy (ProviderContainer.defaultRetry, exponential backoff, capped retries) — a thrown error stays AsyncLoading(error: ..., retrying: true), not AsyncError, for as long as retries are in flight, which is a real, proven trap for a widget test expecting an immediate error state.Provider & Riverpod
.autoDisposeA Riverpod provider modifier that disposes provider state once its last listener unsubscribes, instead of caching it for the app’s whole lifetime — the default for a family/parameterized provider to avoid leaking one cached instance per parameter value forever.Provider & Riverpod
AutomaticKeepAliveClientMixinOpts a specific list item’s State out of the normal “dispose once scrolled off-screen” laziness — proven with a real round trip: scroll 8000px away and back, and the keep-alive item’s State is the same instance (same id), while a plain State item is a genuinely new one. Costs the memory laziness normally buys; use only for state expensive to rebuild.Slivers & Scrolling
TermMeaningLesson
BackgroundIsolateBinaryMessengerLets a platform channel call run from a background isolate (inside compute()/Isolate.run) instead of only the root isolate — needs ensureInitialized(token) first, with token a RootIsolateToken obtained on the root isolate via ServicesBinding.rootIsolateToken before spawning. Skipping it throws: the instance is “invalid until ensureInitialized is executed,” per the installed 3.47.5 SDK’s own doc comment.Platform Channels
base (class modifier)Forbids implements outside the declaring library while still allowing extends — real invalid_use_of_type_outside_library error: “can’t be implemented outside of its library because it’s a base class.” Guarantees every instance genuinely is the real type via inheritance, never a lookalike built to match the interface shape.Classes & Mixins
BLoC / BlocA pattern enforcing strict one-direction data flow: the UI sends events in, a Bloc<Event, State> emits states out, the UI rebuilds from those states — never mutating state directly. flutter_bloc (9.1.1) ships both Bloc (explicit Event classes) and the simpler Cubit.BLoC & Patterns
BlocBuilder / buildWhenBlocBuilder<B, S> rebuilds on every new state by default; buildWhen: (previous, current) => ... narrows that — proven with a build counter: four Increment events that keep the state’s runtimeType the same produce zero rebuilds, and only the fifth event (a genuine type change) triggers one. Same role as InheritedModel’s aspects or Riverpod’s .select().BLoC & Patterns
BlocListenerRuns a one-shot side effect (navigation, a SnackBar) in response to a new state, without itself rebuilding any widget — proven to fire exactly once, with the exact triggering state value, across five events.BLoC & Patterns
blocTestbloc_test (10.0.0)‘s helper: builds the bloc, drives it with act, and asserts the exact ordered list of emitted states with expect: () => [...] — no widget involved. seed: starts from a specific state without replaying the events that would normally reach it. Requires the state class to extend Equatable (below), or value-equal states compare unequal and every assertion fails.BLoC & Patterns
BuildContextNot a bag of globals — it is the Element at that position in the tree (proven by spying createElement). This identity is what lets .of(context) search upward for an ancestor; using a context that sits above the ancestor you’re looking for (e.g. Scaffold.of(context) in the same build that creates the Scaffold) throws a real, named error — Builder is the standard fix, introducing a genuinely descendant context.Build & BuildContext
build / rebuild / dirtysetState (or an ancestor’s rebuild) marks an element dirty; on the next frame Flutter calls build again on every dirty element. build must stay pure and fast — no side effects, no controller creation, no network calls — because it can run every frame of an animation, not just once.setState & Lifecycle
TermMeaningLesson
cacheWidth / cacheHeightImage’s decode-time resize hint, in physical pixels: decoding a large source image at its full resolution just to display it at thumbnail size wastes memory and decode time, so passing the actual display size here caps what the image decoder allocates.Rebuilds & Performance
catchError vs. .then(onValue, onError:)Genuinely different, proven directly: onError on .then only catches an error from the future being chained onto, not one thrown inside onValue itself; .catchError(...) chained after .then() catches errors from either. Mixing them up is a real, silent error-swallowing bug.Async in Dart
ChangeNotifierProviderProvider’s binding of InheritedWidget + ChangeNotifier: notifyListeners() triggers a rebuild of the underlying InheritedWidget; context.watch<T>() is dependOnInheritedWidgetOfExactType with nicer syntax, context.read<T>() is the no-dependency lookup.InheritedWidget
class modifiers (sealed / final / base / interface / mixin class)Five Dart 3.0 modifiers restricting how a class can be used outside the library that declares it — see each modifier’s own entry. All four of sealed/base/interface/final share the same analyzer error code, invalid_use_of_type_outside_library — only the message text differs; grep CI output on the code, not the message.Classes & Mixins
Clip / Clip.antiAliasWithSaveLayerThe clip-behavior enum every clipping widget takes: Clip.none (free, the default for most), Clip.hardEdge (fast, jagged edges), Clip.antiAlias (ClipRRect’s own default — smooth, possible bleeding-edge artifacts), and Clip.antiAliasWithSaveLayer — the one mode that genuinely forces an offscreen Canvas.saveLayer buffer, “very slow” per dart:ui’s own source. Reach for it only when Clip.antiAlias’s artifact is visible and unacceptable.Render Pipeline
ColorScheme.fromSeedDerives a Material 3 app’s whole palette from a single seed Color — proven directly: Theme.of(context).colorScheme.primary in a running widget matches the exact ColorScheme.fromSeed(seedColor: ...) the theme was built with, byte-for-byte. Reading colors from Theme.of(context).colorScheme instead of hardcoding a Color is what makes dark mode and rebranding a one-line seedColor swap.App Scaffolding
code generation (@riverpod, build_runner, .g.dart)riverpod_generator/riverpod_annotation (4.0.7) write the provider boilerplate (.autoDispose, correct typing, ref wiring) from an annotated function or Notifier/AsyncNotifier class via part 'x.g.dart' — run with dart run build_runner build. This course’s harness doesn’t run build_runner, so a lesson using codegen ships the real generated .g.dart content as its own file.Provider & Riverpod
compute()Flutter’s wrapper for running a pure function on a background isolate. Reading the installed Flutter 3.47.5 SDK source directly disproves the common claim that it adds “isolate-pool management” over Isolate.run — on native, compute(fn, arg) is, literally, Isolate.run(() => fn(arg)) plus a debug label. On web it is a completely different function: await null; then callback(message) on the same thread — no isolate at all, confirmed by api.flutter.dev: “On web platforms this will run callback on the current eventloop.” A closure passed to compute() that captures a native handle (a ReceivePort, a BuildContext) throws a real ArgumentError: Illegal argument in isolate message: object is unsendable.Isolates & compute()
const canonicalizationA const widget/record/value expression is a single canonicalized object — identical(const (1,2), const (1,2)) is true, proven directly for both records and widgets. Flutter’s element-update path short-circuits on identical(oldWidget, newWidget), so a const child is never diffed or rebuilt while its non-const sibling rebuilds on every parent rebuild — this is strictly stronger than a manual memoization check, and free.Widgets and the Tree
ConnectionStateThe four-value enum an AsyncSnapshot carries: none (only for a literal null future/stream), waiting (subscribed, no result yet), active (StreamBuilder only — at least one event arrived, stream still open), done (future completed, or stream closed). FutureBuilder only ever produces waiting/done in practice — there’s no “active” state for a one-shot value.Futures & Streams in the UI
ConstrainedBox / UnconstrainedBox / OverflowBoxConstrainedBox adds extra min/max bounds on top of the incoming constraint; UnconstrainedBox lets its child ignore the incoming constraint and size to its own natural size (can overflow visibly, deliberately); OverflowBox genuinely breaks the down-flow rule, imposing a different constraint range on its child than what it itself received.Constraints & Layout
constraints (tight / loose / unbounded)Tight: min equals max, the child must be exactly that size (SizedBox). Loose: min is 0, the child may be anything up to max (Center). Unbounded: max is infinity, “be as big as you want” — a plain Column gives its non-flex children unbounded main-axis height, which is exactly what crashes a bare ListView placed there (below).Constraints & Layout
context.go vs context.push vs Navigator.pushcontext.go(path) replaces the current location (whatever go_router’s route table says that location’s stack should be — no back-stack between siblings); context.push(path) adds an entry on top, tracked by go_router as an ImperativeRouteMatch; raw Navigator.of(context).push(...) grows the same underlying Flutter stack but go_router’s own notion of “current location” never sees it — proven directly: after an imperative push, GoRouter’s currentConfiguration.uri is still the old path.Declarative Routing
covariantMarks a subclass override parameter as accepting a more specific type than its supertype’s signature declares, trading a compile-time guarantee for a runtime TypeError if the actual call passes the wrong subtype — used on didUpdateWidget(covariant MyWidget oldWidget) throughout this course.Classes & Mixins
CubitThe simpler half of flutter_bloc: no Event classes, just methods that call emit(newState) directly. Start here; reach for full Bloc (explicit events) only when a documented, loggable list of every possible input earns back the extra ceremony.BLoC & Patterns
Curve / CurvesReshapes linear animation time into natural motion (Curves.easeInOut, Curves.elasticOut, …); both TweenAnimationBuilder and an AnimationController-driven CurvedAnimation take one. Still fully testable via tester.pump(Duration) — assert against Curves.easeInOut.transform(0.5) rather than the raw linear value.Animations
CustomScrollViewComposes multiple sliver types (SliverAppBar, SliverToBoxAdapter, SliverGrid, SliverList) into one continuous scroll — proven directly: each sliver stays independently lazy even inside the composed view (13 of 1000 SliverList rows built on one measured run).Slivers & Scrolling
TermMeaningLesson
dart fix --dry-run / dart fix --applyApplies the analyzer’s own registered auto-fixes. --dry-run shows what would change without touching anything — proven with real output for use_full_hex_values_for_flutter_colors. Not every lint is auto-fixable: avoid_unnecessary_containers is a real, live diagnostic that dart fix --dry-run reports zero proposed fixes for, since removing a Container while re-parenting its child is a structural edit outside the fix registry.Project & Tooling
dart:ffiThe lower-level mechanism for calling a native C library directly (no Kotlin/Swift glue) — quoting dart.dev’s C-interop docs: “Dart… apps… can use dart:ffi… to call native C APIs, and to read, write, allocate, and deallocate native memory.” Different tool than platform channels: channels talk to a platform SDK through native glue you write; dart:ffi talks straight to a C ABI.Platform Channels
dart:io vs. web (kIsWeb, conditional import)A common but wrong assumption: flutter build web fails outright on import 'dart:io'. Proven false — dart:io’s classes exist as real, type-checkable stubs on the web compiler (confirmed from the installed SDK’s io_patch.dart), so a build with Platform.isIOS/File.readAsString() wired into main() succeeds, even with --wasm; the bug ships silently through flutter analyze and both build targets and only surfaces as a real UnsupportedError the first time a user’s browser actually runs that code path. kIsWeb (a compile-time bool) or a conditional import (import 'io_impl.dart' if (dart.library.js_interop) 'web_impl.dart';) are the real guards.Project & Tooling
--dart-define / --dart-define-from-filePasses a compile-time constant your code reads with String.fromEnvironment('KEY', defaultValue: ...) — proven directly: run flutter test --dart-define=API_URL=... and the constant reads exactly that value at compile time, not a runtime environment lookup. --dart-define-from-file=config.json passes a whole file of key/value pairs at once, for a flavor needing many values.Build & Release
definite assignment analysisThe analyzer’s proof that a non-nullable local is assigned on every code path before it’s read. A non-final local missing a path gets not_assigned_potentially_non_nullable_local_variable; a final local with the same gap gets a different, real diagnostic — read_potentially_unassigned_final — both proven with real flutter analyze output.Null Safety
didChangeDependenciesRuns right after initState, and again whenever an inherited dependency this State reads actually changes — the safe place to read InheritedWidget/Provider/Theme.of data that setup depends on (initState itself can’t reliably read inherited widgets).setState & Lifecycle
didUpdateWidgetCalled when the parent rebuilds and hands this State a new widget config of the same type/key — proven to run before the build it triggers, via a real logged order. covariant widens the parameter type from the supertype signature to the concrete widget type.setState & Lifecycle
disposeCalled once Flutter confirms an element was not reinserted elsewhere after deactivate — clean up controllers, cancel subscriptions here. Forgetting it is the classic Flutter memory leak, proven concretely for a leaked AnimationController’s Ticker.setState & Lifecycle
dependOnInheritedWidgetOfExactType vs. getInheritedWidgetOfExactType vs. findAncestorWidgetOfExactTypeOnly dependOnInheritedWidgetOfExactType registers a dependency and auto-rebuilds the caller on update — proven with a build-count test: after an ancestor InheritedWidget update, the dependOn reader’s build count moves from 1→2, while the get/findAncestor readers stay at 1. getInheritedWidgetOfExactType is the same O(1) cached lookup with no subscription (a one-time read); findAncestorWidgetOfExactType walks the widget tree directly (O(depth), works for any Widget, not just InheritedWidget).InheritedWidget
DevToolsThe browser-based suite for inspecting a running app — widget inspector, performance/timeline view, memory view, network view. This course’s environment has no device to attach it to, so every DevTools claim in this course is docs-cited, not screenshotted.Project & Tooling
TermMeaningLesson
Element / element treeThe living instance of a widget at a tree position — persists across rebuilds, holds State, decides whether a new widget updates it in place (update/didUpdateWidget) or tears it down (unmount + fresh createElement). BuildContext is the element (proven by spying its identity). Middle of the three trees, between the cheap widget tree and the expensive render tree.Widgets and the Tree
Equatablepackage:equatable (3.0.0) gives a class value-equality (==/hashCode) from a declared props list instead of Dart’s default identity equality — required for blocTest’s expect: () => [...] to compare emitted states by value; without it, two separately-constructed equal-looking states are unequal and every assertion fails.BLoC & Patterns
EventChannelWhere MethodChannel is one call/one reply, EventChannel delivers a stream of native events (sensor data, connectivity) — maps to a Dart Stream via receiveBroadcastStream(). flutter_test’s setMockStreamHandler(channel, MockStreamHandler.inline(onListen: ...)) mocks it, proven to deliver events in order then close.Platform Channels
exhaustivenessThe analyzer’s proof that a switch over a sealed class or enum handles every possible case, at compile time — proven directly by deleting one case and getting a real non_exhaustive_switch_expression/non_exhaustive_switch_statement diagnostic. This is what makes sealed + switch sound: the analyzer can enumerate every subtype only because no other library can add one.Dart Language Tour
Expanded vs. FlexibleBoth split a Row/Column’s remaining space by flex factor, but hand the child a different constraint: Expanded (FlexFit.tight) forces the child to fill its full share regardless of its natural size — proven: a 50px-wide child stretched to 300px. Flexible (FlexFit.loose, the default) only bounds the child at its share, letting it keep its own natural size if smaller — proven: the same 50px child stays 50px.Core Layout Widgets
extension typeA Dart 3.3 zero-cost compile-time wrapper — dart.dev: “extension types are static-only and compiled away at run time”. extension type UserId(String value) { ... } exposes only what it explicitly declares; calling a real String member on it is a genuine undefined_method compile error, even though id is String is still true at runtime (there’s no wrapper object to be anything else). implements a supertype of the representation type to inherit members for free.Dart Language Tour
TermMeaningLesson
.familyA Riverpod provider modifier that parameterizes a provider by an argument, creating one cached instance per distinct parameter value — always pair with .autoDispose unless every possible parameter value’s state should genuinely be cached forever.Provider & Riverpod
federated pluginMost first-party Flutter plugins today split into an app-facing package, a platform-interface package, and one implementation package per platform — quoting docs.flutter.dev directly: “splitting the API of a plugin into a platform interface, independent platform implementations… and an app-facing interface.” You depend on the app-facing package; the right platform implementation resolves automatically.Platform Channels
final (class modifier)Forbids both extends and implements outside the declaring library — real error: “can’t be extended outside of its library because it’s a final class.” The strictest of the four non-sealed modifiers: outside its library the type can only be constructed and used, never subtyped by either mechanism.Classes & Mixins
flavors / schemesAndroid flavors / iOS schemes let one codebase produce dev/staging/prod builds with different config (API endpoints, app IDs, icons) without branching code — paired with --dart-define to inject the per-environment values, e.g. flutter build apk --flavor prod --dart-define=API_URL=....Build & Release
flutter analyze / flutter_lints vs. very_good_analysisflutter analyze runs the analyzer over the configured lint set. flutter_lints (6.0.0, the default) layers a small, low-friction set on top of package:lints/recommended.yaml — proven to genuinely not include the general prefer_const_constructors (only the narrower ..._in_immutables variant), unlike very_good_analysis (11.0.0, 237 lines of rules), which ships it by default alongside a much stricter overall baseline.Project & Tooling
flutter doctorThe first command to run when anything’s off — diagnoses the SDK, every platform’s device toolchain, and IDE plugins, naming the specific missing piece (an unaccepted Android license, a missing Xcode component) rather than a generic failure. Real output on this course’s Mac: Flutter (Channel stable, 3.47.5, ...), Android toolchain (SDK 35.0.0), Xcode 26.2.Project & Tooling
FlutterError.onErrorCatches errors the Flutter framework itself raises (build/layout/paint) — the first of the two channels needed for production crash reporting; runZonedGuarded (below) catches the other half, uncaught async errors. Together they’re the pairing this course proves catches “two different halves of Flutter’s error surface.”Production Concerns
frame budgetTo hit 60fps you have ~16.6ms per frame across build→layout→paint→composite→raster; at 120Hz (many modern phones) that halves to ~8.3ms. Jank is a frame that misses the budget — proven throughout the render-pipeline lesson to come from real, measurable costs (an allocated Opacity layer, an un-boundaried repaint), not a vague concern.Render Pipeline
FutureA value that will exist later — the result of an async operation, unwrapped with await. Future.wait([...]) runs several concurrently, resolving once all do, in input order not completion order; eagerError: true completes as soon as the first one fails instead of waiting for every future to settle (proven with real timing: default ~20ms wall-clock vs. eagerError: true’s under 30ms).Async in Dart
FutureBuilderTurns a Future into a synchronously-readable AsyncSnapshot your build reads via connectionState → hasError → data, in that order. The single most common bug: creating the Future inside build — proven directly, this re-triggers the work and resets the snapshot to waiting on every unrelated rebuild; create it once (initState/late final) instead. snapshot.hasError (a caught error from the source) and a throw inside your own builder callback are proven to be genuinely different failure modes — only the second crashes the build.Futures & Streams in the UI
FVM (Flutter Version Management)The community-standard tool for pinning a specific Flutter SDK version per project (.fvmrc), independent of whatever version happens to be on PATH — not part of the SDK itself, a separate CLI managing multiple cached installs. The standard answer to “why does this build differently on my machine vs. CI.”Project & Tooling
TermMeaningLesson
GlobalKeyIdentifies a widget across the entire app, reachable from anywhere with no ancestor/descendant relationship required — the standard tool for reaching a FormState from outside the Form. A GlobalKey used on two widgets simultaneously throws a real, proven crash: “Multiple widgets used the same GlobalKey… A GlobalKey can only be specified on one widget at a time.” Powerful but expensive; prefer ValueKey/UniqueKey unless cross-tree access is genuinely needed.Keys
golden testA snapshot test comparing rendered pixels against a checked-in reference .png via matchesGoldenFile(...) — powerful for design systems, brittle across platforms/font versions; regenerate deliberately with flutter test --update-goldens. This course’s harness cannot carry a binary reference asset through its fence system, so this was proven honestly in scratch, not the shared probe.Testing
go_routerThe official declarative routing package built on Navigator 2.0’s Router API — this course pins 18.0.1 (18.0.2 is current on pub.dev; the pin is a lockfile snapshot). context.go(path) sets the location and recomputes the stack from the route table; a pasted deep-link URL reconstructs the same screen on web.Declarative Routing
go_router_builderGenerates a typed GoRouteData subclass per route from a @TypedGoRoute annotation (current: 4.5.0) — turns a hand-typed, stringly-keyed state.pathParameters['id']! runtime lookup into a real constructor field checked at compile time.Declarative Routing
GoRouteA single route entry in a GoRouter(routes: [...]) config: a path (supporting typed path parameters like :id) mapped to a builder. Route order matters — a more specific literal path (/pets/new) must be listed before a parameterized pattern that would otherwise match it first (/pets/:id).Declarative Routing
TermMeaningLesson
HeroFlies a widget between two routes when both sides use the same tag — proven both ways with a real two-screen Navigator.push.Animations
hot reload vs. hot restartHot reload (r) injects changed source into the running app and rebuilds the widget tree — State is preserved, sub-second. Hot restart (R) discards all app state and restarts from main(). Hot reload re-runs build but not initState or main, and can’t apply new const evaluations or class/enum shape changes — when a change doesn’t seem to take, hot restart is the answer.Project & Tooling
TermMeaningLesson
ImpellerFlutter’s renderer, replacing Skia’s runtime shader compilation with shaders and pipeline state objects (PSOs) precompiled at build time — quoting docs.flutter.dev/perf/impeller directly: “It builds all pipeline state objects upfront. The engine controls caching and caches explicitly.” This removes the classic “first run of a new animation stutters” jank. Status as of Flutter 3.47: the only supported renderer on iOS (no Skia fallback); default on modern (Vulkan-capable) Android since 3.27; default on macOS/Windows/Linux since 3.47.Render Pipeline
InheritedModelRebuilds dependents by aspect, not by the whole value changing — MediaQuery is actually built on it, so a widget reading only MediaQuery.sizeOf(context) rebuilds on size changes but not on an unrelated aspect like orientation-independent padding.InheritedWidget
InheritedWidgetFlutter’s built-in answer to prop-drilling: place one high in the tree, and any descendant reads it directly via context.dependOnInheritedWidgetOfExactType<T>() (usually wrapped in a static of(context)), no matter how deep, with automatic rebuild-on-update. Theme, MediaQuery, Navigator, and Provider are all built on it — proven with a real dependent-vs-non-dependent build-count test: only registered dependents rebuild when updateShouldNotify returns true.InheritedWidget
initStateRuns once, at element creation — the place for one-time setup (subscriptions, controller creation), never side effects that belong in build. Can’t reliably read inherited widgets yet (use didChangeDependencies for that); a late field left unassigned past initState throws a real LateInitializationError.setState & Lifecycle
integration_testBundled with the SDK (not a separate pub.dev dependency), runs the actual compiled app on a real device/emulator via IntegrationTestWidgetsFlutterBinding.ensureInitialized(), then the same tester.tap/pump/expect API as a widget test — against the real running app. This course’s environment has no device to run one against, so this entry is docs-cited (docs.flutter.dev’s integration-testing guide), not demonstrated.Testing
interface (class modifier)Forbids extends outside the declaring library while allowing implements — real error: “can’t be extended outside of its library because it’s an interface class.” The fix is exactly what the modifier is for: implement it instead of extending it, which compiles cleanly.Classes & Mixins
IntrinsicHeightForces a widget to size itself to its child’s “natural” height by running a real, extra measurement pass first (a dry layout to discover the intrinsic size, then the real layout) — proven to cost genuinely more than a plain layout, not just a style choice.Constraints & Layout
Isolate.run / Isolate.spawnIsolate.run (Dart 2.19+) spawns an isolate, runs a closure, returns the result, and shuts the isolate down — all in one call; this is the exact primitive Flutter’s compute() wraps on native (proven equal from SDK source). Isolate.spawn + SendPort/ReceivePort is for a long-lived worker isolate communicated with repeatedly, rather than a fresh isolate per call.Async in Dart
TermMeaningLesson
JIT vs. AOTJIT (Just-In-Time, used in debug) compiles Dart as it runs, which is what makes hot reload possible. AOT (Ahead-Of-Time, used in profile and release) compiles to native machine code before shipping — fast startup, predictable performance, no hot reload. Tree-shaking (unused code and unreferenced icon glyphs stripped) happens in AOT builds.Build & Release
TermMeaningLesson
keyTells Flutter “this element’s identity is X, not just its position” — without one, Flutter matches by type+position and a reordered list of stateful widgets keeps the wrong State attached to the wrong row (proven with a real checkbox test: a check “stays” on position 0 after a swap instead of following its label). Needed for lists of stateful widgets whose order/membership can change; rarely needed for stateless lists. See ValueKey, UniqueKey, GlobalKey, PageStorageKey.Keys
kIsWebA compile-time bool, true only on the web target — the real guard for branching dart:io-touching code away from a web build, since dart:io itself compiles (as stubs) but throws UnsupportedError at runtime on web rather than failing to build.Project & Tooling
kReleaseModeA compile-time bool flag from package:flutter/foundation.dart, true only in a release build — used internally by compute()’s own source to pick a shorter debug label ('compute' in release vs. the full callback toString() in debug), and generally the standard guard for stripping debug-only diagnostics/asserts from what ships.Isolates & compute()
TermMeaningLesson
l10n / gen-l10nFlutter’s official localization pipeline: .arb files + l10n.yaml, with generate: true under flutter: in pubspec.yaml and flutter_localizations (an SDK dependency: sdk: flutter, not pub.dev) added. flutter gen-l10n writes a typed app_localizations.dart plus one per-locale class — run for real against this course’s Flutter 3.47.5 SDK, producing genuine generated output.App Scaffolding
latePromises “this will be non-null by the time anyone reads it” without an initializer at declaration — useful for values set in initState. Reading it before assignment throws a real LateInitializationError. A misused late is a ! in disguise: it trades a compile-time guarantee for a runtime one, so use it sparingly.Dart Language Tour
LayoutBuilder vs. MediaQuery.ofBoth let a widget react to size, but with a genuinely different rebuild scope — proven directly: MediaQuery.of(context) (or .sizeOf) rebuilds whenever the ambient MediaQueryData changes anywhere in the app (screen rotation, text-scale change), while LayoutBuilder rebuilds only when its own incoming constraints change, which is scoped to wherever it sits in the tree, not the whole app.Build & BuildContext
layer / layer treeThe output of the paint phase’s compositing step — not every render object gets its own layer; wrapping a subtree in RepaintBoundary is what allocates one. debugDumpLayerTree() is a real, inspectable dump of the live layer tree (TransformLayer → OpacityLayer → PictureLayer), not a description of it — even a plain Center(child: Text(...)) already has an OpacityLayer from route-transition machinery before any app code touches Opacity.Render Pipeline
TermMeaningLesson
material_ui / cupertino_ui splitContributions to package:flutter/material.dart and cupertino.dart inside the core SDK were frozen starting in Flutter 3.44 (quoted directly from docs.flutter.dev’s breaking-changes notes) — new Material/Cupertino work now goes into the standalone, independently-versioned material_ui/cupertino_ui pub.dev packages (both past 1.0 as of 3.47). package:flutter/material.dart still works, still ships with every install, and is not yet formally deprecated as of 3.47 — just frozen. dart fix --apply --code=migrate_design_widgets is the official automated migration when ready.App Scaffolding
MaterialApp.routerThe MaterialApp constructor variant for declarative (Navigator 2.0) routing — takes a routerConfig: (a GoRouter instance in this course) instead of home:/routes:, letting the router (not MaterialApp itself) own the whole route stack.App Scaffolding
MediaQuery / SafeAreaMediaQuery.of(context) exposes ambient screen data (size, padding, text scale, orientation) — built on InheritedModel, so .sizeOf(context) alone scopes rebuilds to size changes specifically. SafeArea reads MediaQuery’s padding to avoid notches/system bars automatically.App Scaffolding
MethodChannelA typed, asynchronous message pipe to native code: invokeMethod('name') returns a Future that completes with the native reply, serialized by a MethodCodec. With no native implementation registered, it throws the real, exact MissingPluginException text — flutter_test ships a mock messenger (setMockMethodCallHandler) that round-trips through the real codec, so a mocked test proves real (de)serialization, not just a stub.Platform Channels
mixin classA class usable as both class Foo and with Foo (a mixin) — cannot declare a non-trivial generative constructor, since a mixin’s fields get grafted onto whatever class applies it, where a constructor wouldn’t make sense. Real error: mixin_class_declares_non_trivial_generative_constructor.Classes & Mixins
mocktail (when / verify / registerFallbackValue)mocktail (1.0.5) substitutes a fake collaborator into a widget under test: when(() => repo.fetch()).thenAnswer((_) async => data) stubs a call, verify(() => repo.save(any())).called(1) asserts exactly how it was invoked. registerFallbackValue(SomeFake()) exists because any() needs a real, non-null instance of a custom type internally under sound null safety — a Fake (never actually called, only its type identity matters) is the standard answer when the real class isn’t trivially constructible; forgetting it throws a real, named error.Testing
mountedA real, non-nullable getter on State, true until dispose() runs. Guards a setState after an await — an unguarded post-await setState on a disposed widget throws the real, exact setState() called after dispose() error; if (!mounted) return; before the setState turns the crash into a harmless no-op, proven directly.setState & Lifecycle
TermMeaningLesson
NavigationBar vs. NavigationRailAdaptive Material navigation: NavigationBar (bottom tabs) for narrow widths, NavigationRail (a side rail) for wide ones — proven at two widths with a real widget test, the standard pattern for one screen adapting to phone vs. tablet/desktop.App Scaffolding
Navigator / route stackThe imperative (Navigator 1.0) API: push/pop/pushReplacement/pushNamedAndRemoveUntil manage a stack of routes directly. Navigator.of(context) walks up the tree for the nearest Navigator ancestor and throws a real, named error if there isn’t one — the same “wrong scope” failure shape as Scaffold.of(). rootNavigator: true explicitly targets the outermost Navigator instead of a nested one.Navigator & Routes
Navigator 2.0 (Router / RouterDelegate / RouteInformationParser)The declarative routing system underneath go_router: Router is the dispatcher listening for routing info (deep link, browser URL); RouteInformationParser turns that raw info into typed app state; RouterDelegate builds the actual Navigator/Page list from that state and reports pops back. go_router is a RouterDelegate/RouteInformationParser pair written once by the package, so you configure GoRoutes instead of hand-rolling the delegate.Navigator & Routes
null-safety operators (?. / ?? / ??= / !)?. — access only if non-null, else the whole expression is null. ?? — fallback when the left side is null. ??= — assign only if currently null. ! — asserts non-null, throwing at runtime if wrong; the one operator worth genuine caution, proven with a real runtime crash when the assertion is false.Null Safety
TermMeaningLesson
Opacity (layer cost)The widget’s own doc comment says values 0/1 use “a fast path” — reading RenderOpacity’s actual source shows the real, more precise rule: alwaysNeedsCompositing => child != null && _alpha > 0, true for any non-zero alpha including 255 (opacity 1.0). Proven directly by inspecting the live layer tree: only opacity: 0.0 genuinely omits the widget’s own compositing layer; 1.0 still allocates a real OpacityLayer, just one that composites trivially cheaply.Render Pipeline
TermMeaningLesson
PageStorageKeyPreserves scroll position across a scrollable being torn down and rebuilt from scratch (e.g. switching away from a tab that doesn’t keep children alive, then back) — read through the ambient PageStorage/PageStorageBucket, proven directly to restore the exact prior offset where an un-keyed rebuild would reset to zero.Keys
pattern matching (switch expression, guard, destructuring)Dart 3.0 patterns generalize destructuring beyond final (a, b) = pair to match on a value’s shape — object patterns (Circle(:final radius)), list patterns with a rest element, map patterns via if (json case {...}), and relational (Circle(radius: > 10)) or when guards. A switch expression over a sealed type or enum is analyzer-checked for exhaustiveness (see that entry) with no default needed.Dart Language Tour
PigeonGenerates a typed Dart API plus matching native (Kotlin, Swift) interfaces from one Dart definition file (current: 29.0.4) — a rename or type change fails to compile everywhere it’s used, instead of failing silently at a stringly-typed MethodChannel boundary. Run once (dart run pigeon --input ...) as a dev command; only the generated .g.dart/.g.kt/.g.swift output ships with the app.Platform Channels
PlatformException / MissingPluginExceptionPlatformException is a real, structured error a native handler throws deliberately (code, message) that surfaces to Dart as a catchable exception. MissingPluginException is what you get with no native implementation registered at all for a channel — its exact toString() text ('MissingPluginException($message)') is proven live and is the literal message every real “plugin not found” bug report contains.Platform Channels
PopScopeReplaces the deprecated WillPopScope for intercepting the back gesture/button — per docs.flutter.dev’s predictive-back guide, it’s what “supports predictive back gestures,” which WillPopScope does not.Navigator & Routes
predictive back / PredictiveBackPageTransitionsBuilderSince Flutter 3.38, the default page transition on Android is PredictiveBackPageTransitionsBuilder (the real class name — a course typo once wrote it without the “s” after “Transitions”; that spelling doesn’t exist in the SDK). Follows the user’s back gesture, previewing the destination underneath, automatically via MaterialPageRoute. The OS-level preview additionally needs android:enableOnBackInvokedCallback="true" in the manifest.Navigator & Routes
Provider (package)Wraps hand-written InheritedWidget boilerplate in a clean API, typically paired with ChangeNotifier: a model calls notifyListeners(), ChangeNotifierProvider places it in the tree, and context.watch<T>()/context.read<T>() read it with (or without) a rebuild subscription.Provider & Riverpod
ProviderScopeThe widget that creates and exposes Riverpod’s ProviderContainer — not optional: every ref.watch/ref.read needs it somewhere above, and skipping it throws a real, proven StateError: "Bad state: No ProviderScope found" the instant a ConsumerWidget tries to read a provider. Goes once, at the app root, wrapping runApp().Provider & Riverpod
pubspec.yamlThe project manifest: dependencies: (shipped), dev_dependencies: (build/test-only, e.g. flutter_lints), environment: sdk: (the Dart SDK constraint, ^3.13.0 for this course’s Flutter 3.47), and flutter: assets:/fonts: (bundled resources — a missing entry here is the classic “asset not found” bug).Project & Tooling
TermMeaningLesson
recordA Dart 3.0 anonymous, immutable, structurally-typed aggregate — (double, double) or ({String name, int age}) — for multiple return values with zero boilerplate and no declared class. Compares structurally with == always; const records are additionally canonicalized (identical), proven directly, exactly like const widgets. A typedef can name a record shape; positional fields are read with .$1/.$2.Dart Language Tour
redirect / refreshListenableredirect runs before a go_router route builds and can send the user elsewhere (return a path, or null to proceed) — the idiomatic place for auth guards. On its own it only re-evaluates when navigation happens; refreshListenable (any Listenable, typically a ChangeNotifier) closes that gap, making the router re-run redirect whenever the listenable notifies, with zero navigation call of its own — proven directly: an external notifyListeners() alone, no go()/push(), moves the app from a login screen to home.Declarative Routing
ref.watch / ref.read / ref.listenRiverpod’s three ways to interact with a provider from inside another provider or a widget: ref.watch subscribes and rebuilds on change; ref.read reads once, no subscription (typically inside a callback); ref.listen runs a side effect on change without itself causing a rebuild.Provider & Riverpod
RenderFlex overflowedThe real, exact error text when a Row/Column is given more content than its available space — Row/Column never shrink children to fit; the reported pixel count is computed, not vague, and matches the actual overflow math (sum of children − available space), proven directly: two 300px boxes in a 400px-wide Row report “overflowed by 200 pixels”. Expanded/Flexible (or a scrollable) are the real fixes.Constraints & Layout
RenderObject / render treeThe third of the three trees — does the actual layout, painting, and hit-testing. Expensive; Flutter reuses these aggressively rather than recreating them, unlike the cheap, constantly-rebuilt widget tree. RenderFlex, RenderParagraph, RenderOpacity are all concrete RenderObjects whose real, live state debugDumpRenderTree() prints.Widgets and the Tree
RepaintBoundaryGives a subtree its own compositing layer, isolating its repaints from unrelated siblings that would otherwise share one canvas — proven with a real paint-counter test: without a boundary, an unrelated static sibling’s paint count climbs in lockstep with an animating one (1→2 for zero actual change); with the boundary, the static sibling’s count stays flat at 1.Render Pipeline
runZonedGuardedThe only reliable way to catch an error thrown from a callback nobody awaits (a Timer, a fire-and-forget Future, a stream listener) — proven directly: a plain try/catch around the code that scheduled the callback genuinely never sees the later error, while a zone’s error handler set up via runZonedGuarded does. This is exactly why production main() wraps runApp() in one, paired with FlutterError.onError for the framework’s own half of the error surface.Async in Dart
TermMeaningLesson
ScaffoldMessengerOwns SnackBar display, decoupled from any one Scaffold — reached the same way Scaffold.of() is, and subject to the same wrong-scope failure if the context used sits above the Scaffold/ScaffoldMessenger it’s meant to target.App Scaffolding
Scaffold.of() (wrong-scope crash)Because .of(context) searches upward, calling Scaffold.of(context) inside the same build that constructs the Scaffold uses a context that sits above it, not below — throws the real, named error “Scaffold.of() called with a context that does not contain a Scaffold.” Builder (introducing a genuinely descendant context) is the standard fix, proven to eliminate the crash. Theme.of/Navigator.of fail identically for the identical reason.Build & BuildContext
scrollCacheExtentThe current API for how far ahead (in pixels, or a viewport-relative multiplier) Flutter pre-builds list items just outside the visible viewport — replaces the deprecated cacheExtent: double parameter (flagged by flutter analyze on this SDK). Proven to directly control build count: the default cache built 11/1000 items on a measured run; ScrollCacheExtent.pixels(1000) built 26.Slivers & Scrolling
sealed (class modifier)Closed for both extends and implements outside the declaring library — every subtype must live in the same library, which is exactly what makes switch exhaustiveness checking over it sound (the analyzer can enumerate every case). Real error: “can’t be extended, implemented, or mixed in outside of its library because it’s a sealed class.” The standard shape for a BLoC event/state union.Classes & Mixins
.select()A Riverpod provider read that rebuilds only when a specific derived value changes, not the whole provider state — the Riverpod equivalent of InheritedModel’s aspects or BLoC’s buildWhen.Provider & Riverpod
SemanticsThe accessibility layer read alongside the render tree — every RenderObject that’s interactive or informational can attach a SemanticsNode (visible directly in a real debugDumpRenderTree() dump, e.g. semantics node: SemanticsNode#4 for a plain Text); a widget hidden via Opacity(opacity: 0.0) alone can still be interactable without IgnorePointer/alwaysIncludeSemantics handled explicitly.Render Pipeline
setStateDoes one small thing: runs the callback (mutate fields inside it), then marks this widget’s element dirty for the next frame — not synchronous, not “redraw the screen.” Calling it while something is already building is allowed only for a descendant of the currently-building widget (parents build before children, so the framework can guarantee it’ll still be visited); reaching sideways or upward is refused.setState & Lifecycle
Sliver / SliverList / SliverAppBarA sliver is a scrollable region that lazily negotiates its visible extent with the viewport, rather than occupying a fixed box like a normal widget. ListView wraps a single sliver; CustomScrollView composes several (SliverAppBar for a collapsing header, SliverList/SliverGrid for lazy content, SliverToBoxAdapter to drop a plain widget in).Slivers & Scrolling
SliverFillRemainingInside a CustomScrollView, claims whatever viewport space is left after the other slivers — the sliver equivalent of Expanded inside a Column; hasScrollBody: false for content that shouldn’t itself scroll (an empty-state message, a bottom-anchored button).Slivers & Scrolling
StatefulShellRoute.indexedStackGives each branch of a bottom-navigation shell its own nested Navigator, keeping all branches alive simultaneously in an IndexedStack — proven directly: push a detail screen in tab A, switch to tab B and back, and the detail screen is still there. A plain ShellRoute shares one Navigator across branches instead — switching tabs doesn’t push/pop anything, it just swaps which top-level route is active, so a per-branch back-stack is lost.Declarative Routing
StatefulWidget / StateStatefulWidget stays immutable like any widget; its mutable data lives in a separate State object held by the persistent element — proven directly: a parent rebuild with the same key/type keeps the exact same State instance (same fields), while a key or type change creates a fresh one from scratch.Stateless vs. Stateful
StateNotifier / StateProvider (legacy)Riverpod’s pre-3.0 mutable-state primitives — the migration guide marks them legacy in Riverpod 3, superseded by Notifier/AsyncNotifier (which this course uses throughout). Still present for migration compatibility, not the recommended starting point for new code.Provider & Riverpod
StatelessWidgetUI that is a pure function of its constructor inputs — no mutable data of its own, build is all there is. Use for anything that doesn’t change over time on its own.Stateless vs. Stateful
TermMeaningLesson
testWidgets variantvariant: someTestVariant runs the same test body once per value in a TestVariant — proven with a real ValueVariant<String>({'en','th','ja'}): one testWidgets call, three separately-reported test runs. TargetPlatformVariant.all() is the built-in variant for running one widget test across every TargetPlatform without hand-writing a loop.Testing
Ticker / TickerProviderA Ticker fires a callback once per animation frame; SingleTickerProviderStateMixin/TickerProviderStateMixin supply the vsync: an AnimationController needs. An active Ticker left undisposed throws a real, debug-mode-only assert on element removal — the concrete cost controller.dispose() exists to avoid.Animations
Timer.run (event-queue task)A bare Future(() {}) is secretly a Timer.run-based event-queue task, not a microtask — proven directly with real ordering: scheduleMicrotask/await continuations are true microtasks that fully drain first, before any Timer-based task runs, regardless of write order.Async in Dart
TransferableTypedDataHands off raw bytes between isolates without copying — ownership transfers instead (the sender’s copy becomes unusable; materialize() on the sender throws after transfer), confirmed by api.dart.dev: “can be moved between isolates, so sending it… will only take constant time.” Measured on this Mac at 10MB, the win over a plain compute() copy is small (fixed isolate-spawn overhead dominates at this size) — the real win shows up at much larger payloads or repeated isolate hops.Isolates & compute()
the three treesWidget tree (immutable description, rebuilt constantly, cheap), Element tree (the living, persistent instance — holds State, decides update-in-place vs. tear-down), Render tree (RenderObjects that actually lay out and paint — expensive, reused aggressively). Same type + no key at a tree position reuses the element (createElement runs once, didUpdateWidget on every rebuild, proven with a spy); a different key at the same position tears down and remounts (a fresh createElement).Widgets and the Tree
TermMeaningLesson
unawaited_futuresThe lint catching a fire-and-forget async call (no await, no stored Future) — proven not included in this course’s default flutter_lints/flutter.yaml (it’s in the stricter template only). An error inside an un-awaited Future becomes uncaught, visible only to runZonedGuarded, never a surrounding try/catch. unawaited(fn()) from dart:async is the real, no-op-at-runtime way to mark a fire-and-forget call as deliberate.Async in Dart
UniqueKeyForces Flutter to treat a widget as a completely new identity on demand, discarding the old element/State on purpose — proven directly: reassigning UniqueKey() on a rebuild stamps a fresh State (a new instance id), while a plain rebuild with no key change reuses the same State. Useful for “reset this form/field to blank” without a dedicated reset method.Keys
use_build_context_synchronouslyThe real analyzer lint firing when context (or anything derived from it) is used after an await inside an event handler, without a mounted guard in between — the widget may have been unmounted while the awaited work was pending, making that later context use unsafe.Build & BuildContext
TermMeaningLesson
ValueKeyIdentifies an element by a data value (an id, a string) rather than position — the standard fix for the reorder-loses-state bug: proven directly, ValueKey(label) makes a checkbox’s checked state follow its label across a list swap, where no key left it stuck at the old position.Keys
ValueNotifier / ValueListenableBuilderA narrower alternative to a naive “lift state up” setState: ValueNotifier<T> holds a value outside the widget-rebuild path, and only ValueListenableBuilder’s own builder rebuilds when it changes — proven directly with a build-counter test: a plain lifted setState reruns a non-listening sibling’s build every single time (1→4 across three updates), while the equivalent ValueListenableBuilder sibling never moves off 1.Stateless vs. Stateful
TermMeaningLesson
WillPopScope (removed)The pre-PopScope way to intercept the back gesture — deprecated, per its own doc-comment annotation quoted directly from the installed 3.47.5 SDK source. PopScope (above) is the real, current replacement, additionally required for predictive-back gesture compatibility.Navigator & Routes
Widget treeThe immutable configuration you write in every build method — rebuilt constantly, thrown away, cheap. createElement() is the one method every widget has that actually produces something durable (an Element). Composition, not inheritance: you wrap a widget in Padding/Center, never subclass it to add spacing — the widget tree is the stylesheet, there is no separate layout language.Widgets and the Tree
TermMeaningLesson
--obfuscate --split-debug-infoReal flutter build apk --release --obfuscate --split-debug-info=<dir> obfuscates identifiers in the shipped binary and writes the real, un-obfuscated symbol mapping to <dir> separately, needed to later symbolize a real crash’s obfuscated stack trace — proven with a real Android build on this Mac; a real, surfaced warning in that exact output notes the generated ELF library still contains unobfuscated DWARF debugging info unless --strip is also passed. --obfuscate alone, without the matching --split-debug-info output kept, is proven not enough to get readable crash reports later.Build & Release
--wasm (flutter build web --wasm)Compiles to WebAssembly instead of dart2js JS — real, reproducible numbers from this course’s default counter app: main.dart.js (dart2js) ~1.8MB vs. wasm output (main.dart.wasm + main.dart.mjs) ~1.4MB total, genuinely smaller for this app (not a general rule). Real browser catch, quoted from docs.flutter.dev: reliable support needs WasmGC, which as of this course’s SDK means Chromium/Chrome/Edge 119+ only — Safari and Firefox both have open compatibility bugs despite announced support, and Chrome on iOS (WebKit-based) doesn’t support WasmGC at all. Also requires specific Cross-Origin-Embedder-Policy/Cross-Origin-Opener-Policy response headers from whatever serves the build.Build & Release