Navigation
GoRouter, the bottom menu, where the app opens in debug vs production, and transitions.
Where does the app open? (debug vs production)
In debug (kasy run) the app may go back to the last screen you were on (e.g., /admin, /components). This is intentional: it helps with day-to-day work and hot restart (R), which restarts the app from scratch without losing context.
In production (a release build published to the store or the web) that behavior doesn't exist. The app doesn't "remember" the last screen between sessions.
| Situation | What happens |
|---|---|
| Native in production (closes and reopens) | Always starts at /. If logged in, goes to Home. If not, login or onboarding |
Web in production (yourdomain.com/) | Opens at the URL the user typed. Root / → Home (after auth). /settings → Settings |
Debug (kasy run, hot restart R) | May resume the last visited route, including internal screens like admin |
Summary: debug and production don't behave the same on the initial screen. If you ran kasy run --web, opened localhost:5555, and landed on admin, that doesn't mean the end user will see that when they open the app.
Web: the URL is the screen's address
On the published web, the address bar rules. Bookmarks, F5, and shared links work because every route has a URL (/premium, /admin/kanban, etc.). Protected routes (e.g., admin) still go through the auth redirect: whoever isn't an admin gets sent to Home.
Deep links
To open a specific screen in production:
- Web: use the direct URL (
https://yourapp.com/settings) - Push: send the
routefield in the notification payload (see Push) - Native (external link): configure universal links / app links on iOS and Android so the OS hands the URL to the app
How to test as production on your Mac
flutter run --release # native
flutter run --release -d chrome # web in releaseIn release, the app always cold-starts at / (native) or at the opened URL (web), just like the end user will see it.
Three navigation layers
| Layer | File | Usage |
|---|---|---|
| Global app | lib/router.dart | context.go('/premium'), context.push('/feedback') |
| Bottom tabs | lib/core/bottom_menu/ | Home, Wishlist, Notifications, Settings |
| Onboarding | onboarding_page.dart | Internal Navigator (feature_1 → paywall) |
Without BuildContext (notifiers)
ref.read(goRouterProvider).go('/signin');
ref.read(goRouterProvider).push('/premium');Changing animations for the whole app
One file controls the defaults:
lib/core/navigation/kasy_navigation_config.dart
class KasyNavigationConfig {
static KasyTransitionKind push = KasyTransitionKind.fade;
static const Duration duration = Duration(milliseconds: 250);
static const Curve curve = Curves.easeOutCubic;
}Available types: fade, fadeThrough, sharedAxisScaled, sharedAxisHorizontal, none.
Android, iOS, and web alike
Transitions are centralized. You won't end up with Zoom on Android and Cupertino on iOS by accident.
Last updated on 08/02/2026

