Building Multi-Screen Apps with RapidNative: A Practical Guide to Expo Router Navigation Patterns
By Rishav
21st Sep 2026
Last updated: 21st Sep 2026
Most first mobile apps are single-screen demos. Real ones are trees of screens — a tab bar you land on, a stack you push into when you tap a card, a modal that slides up from the bottom, a detail screen you deep-link into from a notification. The gap between "a screen" and "an app" is navigation, and navigation is where prompts most often fall apart.
This is a hands-on guide to building an expo router multi-screen app with RapidNative. We'll write a single prompt for a five-screen fitness tracker, walk through the actual file tree it generates, and cover the prompting patterns that reliably give you tabs, stacks, dynamic routes, and modals in the shapes you want. Along the way we'll cover the parts of Expo Router that make file-based routing feel obvious once it clicks.
A polished app is a tree of screens with clear rules for moving between them — Photo by William Hook on Unsplash
What "multi-screen" actually means in Expo Router
If you've written mobile navigation before, you probably reached for createStackNavigator and createBottomTabNavigator from React Navigation, wired routes into a config object, then imported that object at the app root. That still works — but every RapidNative project is scaffolded on Expo Router, which flips the model. Instead of registering routes in code, you are the router when you name a file.
The rules are small enough to memorize in a minute:
- Any
.tsxfile insideapp/is a route.app/settings.tsxbecomes/settings. app/_layout.tsxwraps the routes below it — it's where you declare "these screens are a stack" or "these screens are a tab bar."app/index.tsxis the home screen of whatever layout it sits under.- Folders in square brackets are dynamic routes:
app/workout/[id].tsxmatches/workout/abc123. - Folders in parentheses are route groups — they organize files without adding to the URL.
app/(tabs)/home.tsxshows as/home, not/tabs/home.
The consequence: your file tree is your navigation graph. There's no separate config to keep in sync, and — the reason this matters for AI-generated code — describing a screen tree in natural language maps almost one-to-one to a set of files.
The five navigation patterns you'll actually use
Every real app is a composition of five primitives. If you can name them, you can prompt for them.
| Pattern | Expo Router shape | When to use |
|---|---|---|
| Stack | _layout.tsx with <Stack /> | Drilling into a detail — list → item, product → checkout |
| Tabs | (tabs)/_layout.tsx with <Tabs /> | Top-level, peer sections that don't nest — Home / Search / Profile |
| Modal | Screen with presentation: "modal" | Focused tasks — compose, filter, sign-in — that overlay the current context |
| Dynamic route | [id].tsx folder | Detail views parameterized by an ID — a workout, a message, a listing |
| Group | (auth)/, (tabs)/ folders | Splitting flows (signed-in vs signed-out) without polluting URLs |
Everything else — drawers, bottom sheets, wizards, protected routes — is a composition of these five. A wizard is a stack with hidden headers. A drawer is another layout swap. A "protected" flow is a group with a guard in its _layout.tsx. Naming the primitives is what turns a fuzzy prompt into a predictable file tree.
Building the fitness tracker: one prompt, five screens
Let's build something real. The requirement:
A fitness tracker with a tab bar for Home, Workouts, and Profile. The Workouts tab shows a list of workout sessions. Tapping a session opens a detail screen with the exercises, sets, and reps. The Profile tab has a "Log a new workout" button that opens a modal for entering exercises. On first launch, show a two-screen onboarding flow before the tabs.
That's five real screens (three tabs, one detail, one modal) plus a two-screen onboarding flow — the kind of surface area a hand-coded app takes half a day to scaffold.
The prompt I gave to RapidNative was essentially the paragraph above, plus one line spelling out the navigation intent: "Use Expo Router with a tab bar for the main app, a stack for drilling into workout details, and a modal for logging a new workout. Wrap it all in an onboarding group that runs on first launch."
The naming discipline in that sentence is the whole trick. Every noun that will exist in the file tree — tab bar, stack, modal, onboarding group — is called out by the exact word Expo Router uses. That gives the AI unambiguous targets: it doesn't have to guess whether "log workout" is a screen or a modal, and it doesn't have to reinvent the layout hierarchy.
A single well-structured prompt produces a full multi-screen tree, not just a login page — Photo by Rami Al-zayat on Unsplash
Anatomy of what RapidNative generated
Here's the file structure that came back (paraphrased for clarity):
mobile/app/
├── _layout.tsx # Root layout — Stack with onboarding + (tabs)
├── (onboarding)/
│ ├── _layout.tsx # Stack, headerShown: false
│ ├── welcome.tsx # Screen 1
│ └── goals.tsx # Screen 2 → routes into (tabs)
├── (tabs)/
│ ├── _layout.tsx # <Tabs /> with three tabBarIcon entries
│ ├── index.tsx # Home
│ ├── workouts.tsx # Workouts list
│ └── profile.tsx # Profile
├── workout/
│ └── [id].tsx # Workout detail — dynamic route
└── log-workout.tsx # Modal screen
Six things are worth pausing on because they show up in every well-structured Expo Router app:
1. The root _layout.tsx is a Stack with three children. The tab bar is one of those children ((tabs)); the modal is another (log-workout); onboarding is the third ((onboarding)). This is the pattern the Expo Router docs call "root stack" — everything else nests underneath.
2. (onboarding) is a group, not a folder in the URL. After the user finishes goals selection, router.replace('/(tabs)') pushes them into the tab bar cleanly — no back gesture returns to the onboarding, because replace (unlike push) discards the current entry.
3. The tab bar's _layout.tsx uses <Tabs> from expo-router. Each tab gets an entry with a title and a tabBarIcon. Tab order in the file tree becomes visual order in the bar. Not accidental — file order is a stable, predictable rule.
4. workout/[id].tsx is where dynamic routing pays off. Tapping a session calls router.push('/workout/abc123'); inside the screen, useLocalSearchParams<{ id: string }>() gives you the id. No route registration, no type gymnastics.
5. log-workout.tsx is a plain file, elevated to a modal by one line in the root layout:
<Stack.Screen name="log-workout" options={{ presentation: 'modal' }} />
That single option triggers iOS to slide the screen up from the bottom, adds a swipe-down-to-dismiss gesture, and moves the header into a modal style. This is why modals in Expo Router feel native and not like React-Web sheets bolted on.
6. Types generate themselves. RapidNative writes strict TypeScript for every screen, and Expo Router's typed routes make router.push('/workout/[id]') an autocomplete instead of a stringly-typed guess.
The whole tree is under 300 lines of hand-authored code. That's the actual value proposition of a good AI mobile app builder: not eliminating code, but eliminating the shape-of-the-tree busywork that separates "an idea" from "a scaffold you can actually build on."
Five prompt techniques for multi-screen apps
The gap between a mediocre generation and a great one is almost always in the prompt. Here are the five techniques I lean on when I want an app to come out with the right shape.
1. Name the primitives. Say tab bar, not bottom navigation. Say modal, not popup. Say dynamic route if you know a screen is parameterized. Words that map to Expo Router concepts give the AI a fixed vocabulary. Words like popup, tray, or panel get interpreted three different ways.
2. State the top-level shape first, then drill in. "A tab bar with Home, Workouts, and Profile. Inside Workouts, a list that opens a detail screen. Inside Profile, a button that opens a modal." That paragraph structure — hierarchy first, screen details after — makes the layout tree unambiguous. A wall of screen descriptions with no hierarchy leaves the AI guessing.
3. Call out first-launch flows explicitly. Onboarding, permissions, sign-in — anything that runs before the tabs is a route group with different back-behavior. If you don't mention it, you'll get a "Get Started" button on the first tab instead.
4. Specify what should push vs replace. "After goals, take the user to Home and clear back history" is the difference between router.replace and router.push. Users hate a back gesture that returns them to a completed onboarding screen. Mention it once and it's baked in.
5. Describe what data flows between screens. "The Workouts list passes the session ID to the detail screen." One line, but it tells the AI to build a dynamic route ([id].tsx) instead of a hard-coded screen with a switch statement. Data flow shapes URL structure.
Precise vocabulary in prompts produces precise file trees — Photo by Markus Spiske on Unsplash
Iterating on navigation after the first generation
The first generation is a scaffold, not a finished app. What makes RapidNative useful past minute one is that navigation changes are also just prompts.
Adding a screen is a one-liner: "Add a Settings screen to the Profile tab that lets users toggle notifications and change units." You'll get a new file (profile/settings.tsx), an updated Profile screen with a row that pushes to it, and — because Expo Router types are generated — the router call will typecheck immediately.
Restructuring is where prompt discipline earns its keep. "Move Settings out of the Profile tab and make it accessible from a gear icon in the header of every tab" is a real refactor — it's now a Stack.Screen at the root, wired to a header button in each tab's screen options. Describe the intent ("gear icon in every header"), not the mechanism ("add a headerRight prop"). The AI will pick the mechanism.
Deep linking is a superpower most first apps skip because it's fiddly. Ask for it: "Support deep links so myapp://workout/abc123 opens the workout detail screen." You'll get the app.json scheme configured, the linking config wired up, and — because it's just Expo Router paths — the same URL structure works when you eventually publish the app to the App Store.
Testing multi-screen flows before you ship
There's a class of navigation bugs that only appear on-device: back-gesture behavior on iOS, the physical back button on Android, safe-area insets under a notch, tab bar overlap with the home indicator. You cannot see any of these in a web preview.
RapidNative gives you a QR code for every project. Scan it with Expo Go and the app runs on your real phone, live-reloading as you iterate. This is worth doing before every meaningful change to your navigation — modals in particular look great in the browser and reveal problems on the device (wrong presentation, no dismiss gesture, wrong header).
Two flow-level things I check on every multi-screen app:
- Every navigation destination should have a back-out story. Push into a detail, back gesture returns you. Open a modal, swipe down dismisses it. Complete onboarding, no back gesture returns you (that's
replace, notpush). If a screen has no way back, that's the bug. - Deep-link cold start. Open a deep link when the app is closed. If the app crashes or lands on the wrong screen, your initial route logic is missing a
hrefcheck. RapidNative-generated apps handle this by default, but any hand-edits can regress it.
Common navigation mistakes to avoid
- Too many tabs. Human short-term memory caps at four or five items. Five tabs is the ceiling; if you want six, one of them belongs in a "More" screen or a drawer.
- Modals for destinations. A modal is for a task the user finishes and dismisses. A profile screen is a destination — that belongs on a tab or in a stack, not behind a slide-up.
- Losing state on tab switch. Tab navigators preserve state by default in Expo Router, but a hand-rolled
Tabs.Screen unmountOnBlur={true}breaks this and users hate it. Trust the default. - Nesting stacks inside modals. It works, but Android's hardware back button gets ambiguous. If a modal has three screens, it's probably not a modal — it's a wizard.
People also ask
Is Expo Router replacing React Navigation? No — Expo Router is built on top of React Navigation. It's a file-based layer that generates the same navigators (stack, tabs, drawer) under the hood. If you know React Navigation concepts, everything you know still applies; only the way you declare routes changes.
Can I use Expo Router without Expo? Technically yes, but practically no — you'd give up EAS Build, Expo Go, over-the-air updates, and the module ecosystem. RapidNative uses the full Expo stack precisely because it collapses so much of the "make my app buildable" work into one system. See why AI code generation needs Expo, not bare React Native.
How many screens can a RapidNative project have?
There's no hard cap — real projects ship with 20+ screens. What matters is grouping: use (tabs), (auth), (onboarding) route groups to keep the tree navigable. A flat directory with 30 files gets hard to reason about; the same 30 files organized into three groups reads like an outline.
Do generated apps use TypeScript?
Yes, strict TypeScript with typed routes. router.push('/workout/[id]') autocompletes, and useLocalSearchParams gives you typed params without extra ceremony.
Wrap-up
Multi-screen apps are not intrinsically hard — they're mostly a naming discipline problem. Once you know the five primitives (stack, tabs, modal, dynamic route, group), you can describe any real app in a paragraph, and Expo Router's file-based routing means that paragraph maps almost mechanically onto a file tree.
The value of a prompt-based builder like RapidNative isn't skipping the code — the code is short. It's skipping the set-up: the tab bar wiring, the modal presentation options, the dynamic route boilerplate, the deep-link config, the type generation. That's the busywork that turns "I have an idea" into "I have a scaffold I can iterate on" — and it's the difference between shipping this weekend and shipping in a month.
Try it: pick an app idea, name its primitives in one paragraph, and start building free with 20 credits. If you have a whiteboard sketch instead of a paragraph, go straight from sketch to app.
Ready to build your app?
Turn your idea into a production-ready React Native app in minutes.
Free tools to get you started
Free AI PRD Generator
Generate a professional product requirements document in seconds. Describe your product idea and get a complete, structured PRD instantly.
Try it freeFree AI App Name Generator
Generate unique, brandable app name ideas with AI. Get creative name suggestions with taglines, brand colors, and monogram previews.
Try it freeFree AI App Icon Generator
Generate beautiful, professional app icons with AI. Describe your app and get multiple icon variations in different styles, ready for App Store and Google Play.
Try it freeFrequently asked questions
What is RapidNative?
RapidNative is an AI-powered mobile app builder. Describe the app you want in plain English and RapidNative generates real, production-ready React Native screens you can preview, edit, and publish to the App Store or Google Play.
Can I export the code?
Yes. RapidNative generates clean React Native and Expo code that you can export at any time. No lock-in, no proprietary format. Hand it to your developers or keep building inside RapidNative.
Is RapidNative free to use?
Yes. You can build apps on the free plan with no credit card required. Paid plans unlock unlimited AI generations, code export, and direct publishing to the App Store and Google Play.
Do I need to know how to code?
No. Most users build apps by describing what they want in plain English. Developers can drop into the code whenever they want more control, but coding is optional.
How long does it take to build an app?
Most users have a working first screen in under a minute. A full MVP usually takes a few hours instead of the weeks or months traditional development requires.