Building Multi-Screen Apps with RapidNative: A Practical Guide to Expo Router Navigation Patterns

RI

By Rishav

21st Sep 2026

Last updated: 21st Sep 2026

Building Multi-Screen Apps with RapidNative: A Practical Guide to Expo Router Navigation Patterns

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 hand holding a phone showing a mobile app interface with multiple screens 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 .tsx file inside app/ is a route. app/settings.tsx becomes /settings.
  • app/_layout.tsx wraps the routes below it — it's where you declare "these screens are a stack" or "these screens are a tab bar."
  • app/index.tsx is the home screen of whatever layout it sits under.
  • Folders in square brackets are dynamic routes: app/workout/[id].tsx matches /workout/abc123.
  • Folders in parentheses are route groups — they organize files without adding to the URL. app/(tabs)/home.tsx shows 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.

PatternExpo Router shapeWhen 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
ModalScreen with presentation: "modal"Focused tasks — compose, filter, sign-in — that overlay the current context
Dynamic route[id].tsx folderDetail views parameterized by an ID — a workout, a message, a listing
Group(auth)/, (tabs)/ foldersSplitting 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.

Multiple mobile app screens laid out on a wooden desk 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.

A developer writing code on a laptop with a phone nearby 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, not push). 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 href check. 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.

Start now

Ready to build your app?

Turn your idea into a production-ready React Native app in minutes.

Free tools to get you started

Questions

Frequently 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.