◉RORK LABJP
●GPT-6.1 SOL — Added to Rork's model menu (09-29) with Low, Medium and High effort; included on Pro and Max●SONNET 5.5 — Claude Sonnet 5.5 is selectable: strong at UI design and faster than Sonnet 5 (09-28)●SDK 58 — Beta since 09/15 with no stable date yet; running projects in Expo Go has required login since 09/03●WIDGET — A write-up traces an iOS widget that renders black only in production builds●OBSERVE — EAS Observe now records native crashes too (SDK 57.0.21 or later, 10/07)●NEW — My App Open Ad Only Showed When the App…●GPT-6.1 SOL — Added to Rork's model menu (09-29) with Low, Medium and High effort; included on Pro and Max●SONNET 5.5 — Claude Sonnet 5.5 is selectable: strong at UI design and faster than Sonnet 5 (09-28)●SDK 58 — Beta since 09/15 with no stable date yet; running projects in Expo Go has required login since 09/03●WIDGET — A write-up traces an iOS widget that renders black only in production builds●OBSERVE — EAS Observe now records native crashes too (SDK 57.0.21 or later, 10/07)●NEW — My App Open Ad Only Showed When the App…
Articles/Dev Tools
⬡ Dev Tools/2026-03-27Advanced

Advanced Navigation Patterns in Rork Max — Nested Structures, Custom Transitions, Auth Flows, and Shared Element Transitions

An advanced Rork Max navigation guide grounded in apps I have run solo since 2013. Beyond nested Expo Router structures, auth flow branching, and shared element transitions, it covers six production pitfalls and their fixes with working code.

Rork Max236navigationExpo Router6React Navigationscreen transitionsdeep linkingauth flowanimation

✦ Premium Article

I'm Masaki Hirokawa, an artist and indie app developer. I've been running iOS and Android apps solo since 2013 — mostly quiet, everyday utilities like wallpaper, calming-tone, and intention-style apps — which have reached around 50 million cumulative downloads. In apps people open every single day, whether the screen transitions feel right under your thumb matters more for retention than any flashy feature. I spend time on navigation because it's the place where users quietly slip away, and I've learned that the hard way more than once.

Setup and context — Why Navigation Design Matters

The quality of a mobile app is fundamentally shaped by its navigation architecture. No matter how polished your UI components are, a poorly structured navigation system will undermine the entire user experience.

When building apps with Rork Max, the foundation is Expo Router and React Navigation. For simple apps, the default configuration works fine, but once your app grows beyond 20 screens, maintainability deteriorates rapidly without a solid understanding of navigation design patterns.

We'll work through nested structure design, custom screen transitions, auth flow branching, shared element transitions, and performance optimization. Rather than just listing features, I'll center the discussion on the pitfalls I've hit in production apps and how I got around them.

This guide assumes familiarity with Rork Max basics and Expo Router fundamentals. For an introduction to Expo Router, see Expo Router and Rork Navigation Design Guide.

Mastering Expo Router's File-Based Routing

Expo Router uses file-system-based routing where the file structure inside the app/ directory directly maps to the route structure. A deep understanding of this system is the first step toward advanced navigation design.

Route Groups and Layout Hierarchy

In large-scale apps, organizing screens into logical groups is essential. Expo Router's "route groups" (directories wrapped in parentheses) let you structure screens without affecting the URL path.

// app/ directory structure design example
// app/
// ├── (auth)/           ← Pre-authentication screen group
// │   ├── _layout.tsx   ← Stack Navigator (no header)
// │   ├── login.tsx
// │   ├── register.tsx
// │   └── forgot-password.tsx
// ├── (tabs)/           ← Main tab group
// │   ├── _layout.tsx   ← Tab Navigator
// │   ├── home/
// │   │   ├── _layout.tsx  ← Stack Navigator (nested within tab)
// │   │   ├── index.tsx
// │   │   └── [id].tsx     ← Dynamic route
// │   ├── search.tsx
// │   ├── notifications.tsx
// │   └── profile/
// │       ├── _layout.tsx
// │       ├── index.tsx
// │       └── settings.tsx
// ├── (modals)/         ← Modal screen group
// │   ├── _layout.tsx   ← Stack Navigator (presentation: modal)
// │   ├── create-post.tsx
// │   └── image-viewer.tsx
// └── _layout.tsx       ← Root layout (auth check)
 
// app/_layout.tsx — Root layout implementation
import { Stack } from 'expo-router';
import { useAuth } from '@/hooks/useAuth';
 
export default function RootLayout() {
  return (
    <Stack screenOptions={{ headerShown: false }}>
      <Stack.Screen name="(auth)" />
      <Stack.Screen name="(tabs)" />
      <Stack.Screen
        name="(modals)"
        options={{
          presentation: 'modal',
          animation: 'slide_from_bottom',
        }}
      />
    </Stack>
  );
}

Three key benefits define this pattern. First, authentication screens, main screens, and modals are managed as independent groups. Second, each group has its own layout (Navigator), cleanly separating navigation responsibilities. Third, the parenthesized portions don't appear in URL paths, so deep links remain clean and natural.

Dynamic Routes and Catch-All Routes

For content-driven apps, dynamic route design is critical.

// app/(tabs)/home/[id].tsx — Dynamic route implementation
import { useLocalSearchParams, Stack } from 'expo-router';
import { useQuery } from '@tanstack/react-query';
 
export default function PostDetail() {
  const { id } = useLocalSearchParams<{ id: string }>();
 
  const { data: post, isLoading } = useQuery({
    queryKey: ['post', id],
    queryFn: () => fetchPost(id),
  });
 
  return (
    <>
      {/* Dynamically set the header title */}
      <Stack.Screen
        options={{
          title: post?.title ?? 'Loading...',
          headerBackTitle: 'Home',
        }}
      />
      {/* Screen content */}
    </>
  );
}
 
// app/[...missing].tsx — 404 catch-all
// Fallback for routes that don't exist
import { Link, Stack } from 'expo-router';
import { View, Text, StyleSheet } from 'react-native';
 
export default function NotFoundScreen() {
  return (
    <>
      <Stack.Screen options={{ title: 'Page Not Found' }} />
      <View style={styles.container}>
        <Text style={styles.title}>404</Text>
        <Text style={styles.message}>
          The page you're looking for doesn't exist.
        </Text>
        <Link href="/" style={styles.link}>
          Return to Home
        </Link>
      </View>
    </>
  );
}
✦

Thank you for reading this far.

Continue Reading

What follows includes implementation code, benchmarks, and practical content we hope you'll find useful. This site runs without ads — server and development costs are supported entirely by members like you. If it's been helpful, we'd be truly grateful for your support.

WHAT YOU'LL LEARN
✦Guaranteeing a root in the stack on deep-link entry cut navigation crashes from 18 to 2 per month
✦lazy / freezeOnBlur on tabs trimmed first paint of the wallpaper grid from 1,100ms to 480ms
✦Working code for six production patterns: double-push guard, focus-based tracking, whitelist state persistence, and more
Secure payment via Stripe · Cancel anytime
✦

Unlock This Article

Get full access to the rest of this article. Buy once, read anytime. This site is ad-free — your support goes directly toward keeping it running.

or
Unlock all articles with Membership →
Share

Thank You for Reading

Rork Lab is ad-free, supported entirely by members like you. We publish practical guides daily with implementation code, benchmarks, and production-ready patterns. If you've found it useful, we'd love to have you on board.

  • ✦Copy-paste ready implementation code
  • ✦New advanced guides published daily
  • ✦$5/mo or $10 for lifetime access
View Membership →

Related Articles

⬡ Dev Tools2026-07-18
The Generated Screen That Quietly Jams at AX5 and in German — Putting Layout Resilience Checks on Rork Max SwiftUI
A record of running every Rork Max generated SwiftUI screen through pseudolocalization and the largest text size to find exactly where it jams. Covers when to reach for ViewThatFits, ScaledMetric and layoutPriority, plus the snapshot checks that catch regressions every time you regenerate.
⬡ Dev Tools2026-05-17
Testing Rork Max SwiftUI Features on a Real Wallpaper App — What Worked, What Needed Fixes
I benchmarked Rork Max's SwiftUI generation against the production code of a wallpaper app I actually run. Here is what shipped as-is, what needed fixing, and what I ended up writing by hand — with working code and on-device measurements.
⬡ Dev Tools2026-05-16
Migrating Firebase CocoaPods to SPM in Rork Max Apps
Firebase Apple SDK's CocoaPods distribution ends in October 2026. Here's a detailed migration log from moving 4 Rork Max iOS apps to Swift Package Manager — including dSYM failures, module errors, and the Dropbox conflict copy problem you'll definitely hit.