the architecture · utopia_hooks

The Flutter community spent eight years arguing about state management. We shipped instead.

Battle-tested architecture that just makes sense — and a natural fit for the AI era. Everything below earns the right to that headline.

easy & productive

Simple things stay simple.

state/counter_state.dart10 lines
1// the whole state of a counter screen
2CounterState useCounterState() {
3 final count = useState(0);
4
5 return CounterState(
6 count: count.value,
7 increment: () => count.value++,
8 decrement: () => count.value--,
9 );
10}
1 function·1 hook
state/orders_screen_state.dart17 lines
1// paginated + debounced search + pull-to-refresh
2OrdersScreenState useOrdersScreenState() {
3 final searchState = useFieldState();
4 final query = useDebounced(searchState.value,
5 duration: const Duration(milliseconds: 300));
6
7 final ordersState = usePaginatedComputedState<Order, int>(
8 initialCursor: 1,
9 (page) => api.orders(query, page: page),
10 keys: [query],
11 );
12
13 return OrdersScreenState(
14 search: searchState,
15 orders: ordersState,
16 );
17}
1 function·3 hooks·paginated · searchable · refreshable

Both read top to bottom. The hard one is barely longer than the easy one.

same shape carriesform submissionrealtime streamsbackground syncmulti-step flows
flexible & powerful

Composable by construction.

utopia_hooks is designed around a single idea: state logic should be ordinary code — extractable, testable, and usable anywhere without framework ceremony.

Pull business logic out once, drop it into ten screens. Every hook is a plain Dart function — import and call.

lib/hooks/use_customer_deals.dartcomposable hook
1// declare once — reuse everywhere
2CustomerDealsState useCustomerDeals(String id) {
3 final customer = useCustomer(id);
4 final deals = useAutoComputedState(
5 () => fetchDeals(id),
6 keys: [id],
7 );
8
9 return CustomerDealsState(
10 customer: customer,
11 deals: deals.valueOrNull,
12 );
13}
Docs
battle-tested & familiar

You already know how to write it.

utopia_hooks is a direct descendant of React Hooks — the most widely-adopted UI-state pattern on earth. If your team knows React, the mental model transfers on day one.

the pattern
0M+
GitHub repos depend on React
0 yrs
Hooks in production since 2019
#0
web frontend state pattern
0 yrs
shipping utopia_hooks at Utopia
our production record
0M+
installs on the flagship app running it
4,400
Dart files in the largest utopia_hooks codebase
0
tagged releases in the utopia-flutter monorepo
the AI era

Built for the agents that ship it.

We didn't design utopia_hooks for agents. It just inherits the shape of the code they trained on most — and in 2026, that pays off on every PR.

  • token-efficient

    Token-efficient

    Low-ceremony code means less context burned per file. Agents do more with the same budget.

  • familiar-priors

    A corpus the models know

    Hooks read like the React corpus the models trained on — orders of magnitude more of it than any Flutter dialect. Familiar priors, fewer hallucinations.

  • skills-ready

    Opinionated & skills-ready

    Published Claude Code skills teach agents the exact patterns — Page · State · View, end to end.

~/app — claude

add search to the orders list

Wiring the search state and field.

Skill(utopia-hooks)

paginated search — keys · debounce

Update(state/orders_screen_state.dart)

+2 lines (useFieldState · keys)

Update(view/orders_screen_view.dart)

+1 widget (search field)

done — one file pair, no codegen

~/app — claude

migrate OrdersCubit to hooks

Converting Cubit to a state hook.

Skill(utopia-hooks-migrate-bloc)

Cubit → State hook · events → callbacks

Write(state/orders_screen_state.dart)

one hook replaces the Cubit

Update(orders_screen.dart)

BlocProvider removed

done — cubit deleted, tests green

Explore the open-source packages and agent skills below.

open source · 23 packages · 4 skills

Our production stack,
open-sourced.

The tooling we wish Flutter shipped with - built because we care, hardened on our apps, and kept in the open.

~/utopia

State was three files and five classes. One hook ends that.

Same screen, same behavior, far less code - and because the state logic is decoupled from Flutter, it stays background-safe and fully unit-testable in plain Dart.
4.7×shorter
1 / 3files
1 / 5classes
0deps added
bloc.dart · event.dart · screen.dart
1abstract class CounterEvent {}
2class Increment extends CounterEvent {}
3class Decrement extends CounterEvent {}
4
5class CounterBloc extends Bloc<CounterEvent, int> {
6 CounterBloc() : super(0) {
7 on<Increment>((e, emit) => emit(state + 1));
8 on<Decrement>((e, emit) => emit(state - 1));
9 }
10}
11
12class CounterScreen extends StatelessWidget {
13 Widget build(BuildContext ctx) => BlocProvider(
14 create: (_) => CounterBloc(),
15 child: BlocBuilder<CounterBloc, int>(...))
+ 32 more lines · BlocProvider, BlocBuilder, Equatable, freezed
3 files·5 classes·47 lines
vs
state.dart
1CounterState useCounterState() {
2 final count = useState(0);
3
4 return CounterState(
5 count: count.value,
6 increment: () => count.value++,
7 decrement: () => count.value--,
8 );
9}
10// 1 hook. Same behavior. Background-safe. Testable.
1 file·1 function·10 lines·★ Screen · State · View

One command scaffolds the app. Then it keeps agents honest.

utopia create scaffolds the app and its .claude/ layer; then describe, doctor and an MCP server give every agent and CI one structured, JSON-first view of the project.
1command to scaffold
5MCP tools
15doctor checks
JSONfirst, for agents
~/my_app ▸ Terminalscaffold → operate
1$ dart pub global activate utopia_cli
2 ✓ Activated utopia 0.2.x
3
4$ utopia create flutter_app my_app --org=io.utopiasoft
5 ✓ Screen · State · View app · .claude/ + AGENTS.md wired
6
7$ utopia doctor
8 ✓ 15 checks · {rule_id, file, line, fix} as JSON
9 → CI and agents reason over the same audit
10
11$ utopia mcp # register in Claude Code
12 ▸ describe · describe_routes · doctor · analyze_hooks ×2
13
14$ claude "add a tickets screen"
15 ▸ utopia describe → project as JSON
16 ▸ writes tickets_screen.dart + state + view
17 ▸ utopia hooks analyze → clean

An admin panel for your data. In Flutter, in your codebase.

Pick a delegate - Firebase, Supabase, Hasura, or GraphQL - and the common entry types ship out of the box; need a custom one? The interface is small.
4backends
8+typed entries
0admin UI to write
1Flutter codebase
products_page.dart1 - describe a table
1// a delegate + typed entries = full CRUD UI
2// one line below talks to Firestore
3
4CmsTablePage(
5 title: 'Products',
6 delegate: CmsFirebaseDelegate('products'),
7 entries: [
8 CmsTextEntry(key: 'name'),
9 CmsTextEntry(key: 'description', flex: 4),
10 CmsNumEntry(key: 'price'),
11 CmsBoolEntry(key: 'visible'),
12 ],
13)

Every agent writes production-grade Flutter the same way.

GitHub
A holistic Flutter architecture, not just a state library: every agent writes the same Screen · State · View, hooks and async patterns - production-grade, not best-guess.
15reference files
16non-negotiable rules
2enforcement hooks
4+agents supported
utopia-hooks/SKILL.md15 refs
name
utopia-hooks
Referencesread before writing
Screen · State · ViewCRITICAL
Hook catalogCRITICAL
Global shared stateCRITICAL
Async patternsHIGH
Paginated listsHIGH
App bootstrapHIGH
Error handlingHIGH
NavigationHIGH
Multi-page shellHIGH
Complex state examplesHIGH
Composable hooksHIGH
Flutter conventionsHIGH
TestingHIGH
DI & servicesMEDIUM
utopia_cli surfacesMEDIUM

Claude builds the admin panel. Not by hand.

GitHub
Claude builds the whole back-office - sortable tables, CRUD overlays, filters, per-row actions and media - in ~80 lines of config, not ~970 hand-rolled.
11reference files
7catalog primitives
4backends
8anti-pattern checks
utopia-cms/SKILL.md11 refs
name
utopia-cms
Referencesshell → table → delegate
Anti-patternsCRITICAL
CmsWidget shellCRITICAL
CmsTablePageCRITICAL
DelegatesCRITICAL
EntriesCRITICAL
FiltersHIGH
Table actionsHIGH
Management sectionsHIGH
ThemeMEDIUM
RelationshipsMEDIUM
MediaMEDIUM

Your .claude/ layer is a project. This skill ships it.

GitHub
A production-tested .claude/ layer in minutes - the agent roster, enforcement-hook contracts and skill-design rules already proven across Utopia repos.
10reference files
4agent roles
3slash commands
5workflow templates
utopia-ai-arch/SKILL.md10 refs
name
utopia-ai-arch
Referencesthe layer blueprint
Layer modelCRITICAL
Agent rosterCRITICAL
Skill designCRITICAL
Enforcement hooksCRITICAL
Evolution & driftCRITICAL
Slash commandsHIGH
Architecture docHIGH
CLAUDE.mdHIGH
Bootstrap procedureHIGH
settings.jsonMEDIUM

Migrate BLoC to utopia_hooks. One screen per commit.

GitHub
A 5-agent orchestration migrates a full BLoC/Cubit codebase one screen per commit, exit gate enforced automatically - always green, ~30% less code.
5sub-agents
2phases
7item exit gate
~30%less code
utopia-hooks-migrate-bloc/SKILL.md8 refs
name
migrate-bloc-to-utopia-hooks
Referencesstate → screen patterns
BLoC → hooks: stateCRITICAL
BLoC → hooks: widgetCRITICAL
pubspec migrationCRITICAL
Migration stepsHIGH
Global-state migrationHIGH
Screen migration flowHIGH
Complex Cubit patternsHIGH
Post-migration refactorHIGH
why not the usual?

Why we didn't just use BLoC.

BLoC was the right answer in 2018, and we genuinely respect it as the framework that brought discipline to Flutter state management. The architecture described on this page is simply what we reach for today — it fits the way our teams work, for the reasons laid out above. The structural comparison between the two approaches deserves its own careful treatment, so we wrote it up separately.

utopia_hooksflutter_hooksBLoC
Mental modelView = function(state)React primitives, no screen architectureevent → reducer → state machine
Files per screen1–2you invent the structure5–6 + codegen
Testing business logicpure Dart, no widget treewidget tree requiredbloc_test + mocks
Widget · global · backgroundthe same hook everywherewidget tree onlyseparate wiring per context
Agent fluencyReact-scale corpus, low ceremonyReact-scale corpus, primitives onlyniche, version-fragmented corpus

Simplified on purpose — each column deserves its own argument, so we wrote them: vs BLoC and vs flutter_hooks.

Read the full comparison
already on BLoC?

Migration is paved.

Our open-source Claude Code plugin converts BLoC codebases to utopia_hooks one Cubit at a time. The rewrite is mostly mechanical — the plugin handles roughly 80%, a senior dev finishes the rest. Codebases up to ~50 screens typically land inside two weeks.

talk to us

Audit your architecture.

Not sure whether your current state-management approach is holding you back? We'll take a look and tell you honestly what we see.

Start with the docs ↗