Kaisel: Reimagining Flutter Routing with Dart 3 Sealed Classes and Pattern Matching

Kaisel leverages Dart 3 sealed classes and pattern matching to build type-safe Flutter routing without code generation.
Kaisel is a new Flutter routing library that embraces the "Routes as Values" philosophy, using Dart 3's sealed classes, pattern matching, and records to create a type-safe navigation system without code generation. By modeling routes as algebraic data types, it offers compile-time safety and composability while eliminating the toolchain overhead of alternatives like go_router and auto_route.
Introduction: The Persistent Problem of Flutter Routing
In the Flutter ecosystem, routing has always been a topic that developers have a love-hate relationship with. From the original Navigator 1.0 with its stack-based imperative navigation, to the later introduction of Navigator 2.0's declarative API, and then to widely-used third-party solutions like go_router and auto_route, Flutter's navigation system has undergone multiple evolutions yet has never converged on a unified paradigm that is both simple and type-safe.
Navigator 1.0 was Flutter's original routing solution, based on the classic stack model where developers manage pages through push and pop operations. While this imperative API is intuitive, it falls short when handling complex scenarios such as browser forward/back navigation and deep link restoration. In 2020, the Flutter team introduced Navigator 2.0 with declarative APIs including Router, RouteInformationParser, and RouterDelegate, attempting to synchronize routing state with application state. However, Navigator 2.0 has been widely criticized for its overly complex abstraction layers and verbose boilerplate code — it's even been jokingly called "one of the most difficult APIs in Flutter's history" by the community. This directly fueled the rise of community simplification solutions like go_router.
Recently, an open-source project called Kaisel appeared on Hacker News with a rather novel concept — "Routes as Values". It's a routing library built specifically for Flutter that natively leverages Dart 3 language features. Although the project is still in its early stages in terms of popularity, its design philosophy is worth exploring in depth.
Kaisel's Core Philosophy: Routes as Values
From String Routes to Value-Typed Routes
Traditional Flutter routing solutions mostly rely on strings to identify pages, for example:
Navigator.pushNamed(context, '/user/profile');
The drawbacks of this approach are obvious: strings are weakly typed, spelling errors cannot be caught at compile time, and parameter passing often requires opaque transmission through the arguments field without type constraints.
Kaisel's core proposition is to model routes themselves as values. In other words, every route is a concrete object that the type system can understand, rather than a magic string. When routes become first-class values, developers can pass, compare, match, and compose routes just like ordinary objects, while enjoying compile-time type checking.
Why Dart 3 Is the Critical Foundation
The project deliberately emphasizes "Dart 3 Native" — and this isn't marketing fluff. Dart 3 introduced a series of heavyweight language features that provide the ideal linguistic foundation for the "Routes as Values" philosophy:
- Sealed Classes: All possible routes can be defined as a closed type hierarchy, and the compiler can ensure that route handling is exhaustive.
Sealed classes are a core type system feature introduced in Dart 3.0, inspired by Kotlin's sealed class and Rust's enum. A sealed class can only be extended within the same library file, which means the compiler knows precisely all possible subclasses of that type. This means that when developers use switch statements to pattern match against a sealed class, the compiler can perform exhaustiveness checking — if a subclass's handling branch is missing, the compiler will throw an error directly. In the routing context, this guarantees that every possible navigation target is properly handled, eliminating the risk of missing routes.
- Pattern Matching and switch expressions: Allow developers to dispatch different route types with concise, elegant syntax.
Dart 3's pattern matching goes far beyond simple type checks. It supports destructuring patterns, guard clauses, logical pattern combinations, and more — allowing developers to match types and extract field values simultaneously within a single switch expression. Switch expressions (as distinct from switch statements) are expressions with return values that can be directly assigned to variables or used in Widget construction. This allows route dispatching code to be written in a form similar to match expressions in functional languages — both compact and safe, avoiding the verbosity and omission risks of traditional if-else chains.
- Records: Provide lightweight, structured data carriers for route parameter passing without needing to define a separate class for each route.
Records are anonymous structured data types introduced in Dart 3, similar to tuples in other languages but more powerful — they support mixed use of named and positional fields. In route parameter passing scenarios, the value of Records lies in this: developers don't need to define a dedicated class for each route parameter combination; they can simply use a record type like (String id, int page) to express structured parameters while maintaining full type checking. Records have value semantics, are immutable, and automatically have equality comparison — these characteristics make them ideal carriers for route parameters.
Together, these features make it possible to express a type-safe routing system in pure Dart without relying on heavy code generation.
Kaisel vs. go_router and auto_route
Differences from go_router
go_router is currently the officially recommended community solution for Flutter. While powerful, it still centers around URL/path strings, deep linking configuration is relatively cumbersome, and type safety requires the additional go_router_builder package with code generation to achieve.
Kaisel builds type safety into its design from the ground up, theoretically eliminating the code generation step and thereby reducing build times and project complexity. For small-to-medium projects or teams sensitive to build speed, this is an attractive differentiator.
Advantages over auto_route
auto_route relies heavily on annotations and code generators — developers need to write annotations and run build_runner to get a type-safe navigation experience. By embracing Dart 3's native language capabilities, Kaisel attempts to break free from code generation dependency without sacrificing type safety. This "zero-generation" approach represents a trend in the Dart ecosystem in recent years — replacing external toolchains with stronger language features.
Code generation is a widely-used engineering practice in the Dart/Flutter ecosystem, with build_runner and source_gen as its core tools. From json_serializable's JSON serialization, to freezed's immutable data classes, to auto_route's type-safe routing, many popular libraries depend on code generation to compensate for limitations in language expressiveness. However, code generation comes with significant engineering costs: increased build times (build_runner can take tens of seconds in large projects), version management headaches with generated files, and additional overhead for IDE indexing and hot reload. As Dart 3 introduces sealed classes, pattern matching, records, and macros (still under development), the community is exploring "zero-generation" alternatives, and Kaisel is representative of this trend.
The Value of the Technical Philosophy and Real-World Challenges
A Design Direction Worth Affirming
Treating routes as values essentially brings functional programming and Algebraic Data Type (ADT) thinking into the Flutter navigation domain. This design offers several tangible benefits:
- Compile-time safety: Incorrect route navigations are caught during code writing rather than crashing at runtime.
- Testability: Routes as pure data objects are naturally easy to unit test.
- Composability: Routes can be flexibly passed and transformed, providing clearer expression for complex navigation logic.
Algebraic Data Types are a cornerstone concept of functional programming, divided into product types (like structs/classes) and sum types (like enums/union types). In the routing context, all possible route destinations form a sum type — the application can only be in one route state at any given moment. Dart 3's sealed class is essentially an implementation of sum types. This modeling approach originates from Elm's "Model-Update-View" architecture, where Elm defines all pages as variants of a custom type, and route transitions become pattern matching in pure functions. Similar concepts also appear in Swift's Composable Architecture and Rust's Yew framework. Kaisel brings this mature functional design pattern into the Flutter ecosystem.
Challenges to Watch
As a project still in its early stages, Kaisel faces challenges that shouldn't be overlooked:
- Ecosystem maturity:
go_routeris backed by the Flutter official team, with comprehensive documentation, examples, and community support. New libraries need time to prove their stability. - Deep linking and web support: In real-world projects, routing needs to handle complex scenarios like browser URLs and system deep links — these are the litmus test for whether a routing library is mature.
Deep linking refers to the ability to navigate directly to a specific page within an application from outside the app (such as browser URLs, system notifications, or jumps from other apps). In Flutter, deep linking involves multiple layers of complexity: Android's Intent Filters and App Links verification, iOS Universal Links configuration, web browser URL synchronization with forward/back button response, and route stack restoration during cold starts. A mature routing library also needs to handle redirects (such as redirecting unauthenticated users to a login page and then returning to the target page), route guards, and URL synchronization with nested navigators. These requirements are the key challenges in testing whether the "Routes as Values" philosophy can progress from theoretical elegance to engineering practicality.
- Learning curve: While "Routes as Values" is elegant, developers accustomed to imperative navigation will need a certain mindset shift.
Conclusion
Kaisel is an interesting exploration of the Flutter routing paradigm. It astutely seizes the new opportunities brought by Dart 3's language evolution, attempting to build a type-safe, code-generation-free routing system using modern language features like sealed classes, pattern matching, and records.
Although the project is still in its infancy and community response awaits the test of time, the "Routes as Values" concept itself reflects the Dart/Flutter ecosystem's progression toward stronger type safety and more functional design philosophies. For developers interested in Flutter architecture evolution or functional routing design, Kaisel is undoubtedly a project worth keeping an eye on.
Related articles

Flock License Plate Surveillance Network: Is Long Island Becoming an Open-Air Prison?
Deep analysis of Flock Safety's dense ALPR camera deployment on Long Island, examining how indiscriminate surveillance threatens civil privacy and how to balance public safety with personal freedom.

Deep Dive into OpenAI's Astra Model: Technical Highlights vs. Overhyped Marketing
Deep analysis of OpenAI's Astra model: real technical capabilities vs. overhyped marketing. Community insights on evaluating AI models rationally.

AI-Assisted Analysis Costs Drop 10x: The Tipping Point for Data Analytics Democratization
AI-assisted data analysis costs drop 10x: the technical logic and industry impact. From Text-to-SQL to compute cost declines, analyzing democratization trends, analyst role shifts, and deployment risks.