---
title: Expo App with React Navigation and Tamagui
description: Create an Expo app with React Navigation stack and tab navigators, the Tamagui provider, Jest, and React Native Testing Library using Better Fullstack.
translationStatus: pending
updated: 2026-10-06
category: React Native
tags:
  - expo
  - react-native
  - react-navigation
  - tamagui
keywords:
  - expo react navigation starter
  - expo tamagui starter
  - react native testing library setup
  - expo jest setup
  - react navigation tabs starter
---

Use this stack when you prefer React Navigation's component-based navigators to file-based routing, and want Tamagui and a component test harness in place before the first screen.

```npm
npm create better-fullstack@latest my-tamagui-app -- \
  --ecosystem react-native \
  --frontend native-bare \
  --mobile-navigation react-navigation \
  --mobile-ui tamagui \
  --mobile-storage none \
  --mobile-testing react-native-testing-library \
  --mobile-push none \
  --mobile-ota none \
  --mobile-deep-linking none \
  --mobile-libraries none
```

## What this creates

- An Expo app in `apps/native` registered through `index.js` with `registerRootComponent`.
- React Navigation with a native stack (`Main` and a modal `Modal` screen) and bottom tabs (`Home` and `Settings`).
- A `MobileUIProvider` that wraps the app in `TamaguiProvider` with the `@tamagui/config` v3 preset.
- Jest with the `jest-expo` preset and React Native Testing Library, plus one provider test.
- A Turborepo workspace with shared `config` and `env` packages. No backend, database, or auth.

## Generated shape

```txt
my-tamagui-app/
├── package.json
├── turbo.json
├── apps/native/
│   ├── index.js
│   ├── App.tsx
│   ├── app.json
│   ├── jest.config.js
│   ├── metro.config.js
│   ├── navigation/native-navigation.tsx
│   ├── components/
│   │   ├── container.tsx
│   │   ├── header-button.tsx
│   │   ├── mobile-ui-provider.tsx
│   │   └── tabbar-icon.tsx
│   ├── lib/
│   └── __tests__/mobile-ui-provider.test.tsx
└── packages/
    ├── config/
    └── env/
```

`app.json` derives the URL scheme, iOS bundle identifier, and Android package from the project name.

## Prerequisites

- Node.js and npm.
- Expo tooling, plus an iOS simulator, Android emulator, or physical device.

## Run and verify

```bash
cd my-tamagui-app
npm install
npm run dev:native
npm run test
```

`npm run dev:native` runs `expo start --clear` in `apps/native`. `npm run test` runs Jest in the native workspace.

## Representative snippets

`App.tsx` layers the gesture handler, safe area, Tamagui, and navigation providers:

```tsx
function AppShell() {
  return (
    <GestureHandlerRootView style={styles.container}>
      <SafeAreaProvider>
        <MobileUIProvider>
          <NavigationContainer>
            <StatusBar style="auto" />
            <RootNavigator />
          </NavigationContainer>
        </MobileUIProvider>
      </SafeAreaProvider>
    </GestureHandlerRootView>
  );
}
```

The navigators are typed with param lists, so `navigation.navigate` calls are checked against the declared routes:

```tsx
type RootStackParamList = {
  Main: undefined;
  Modal: undefined;
};

export function RootNavigator() {
  return (
    <Stack.Navigator>
      <Stack.Screen name="Main" component={Tabs} options={{ headerShown: false }} />
      <Stack.Screen name="Modal" component={ModalScreen} options={{ presentation: "modal" }} />
    </Stack.Navigator>
  );
}
```

The `Modal` route is registered, but no screen navigates to it yet. Add a button on `Home` that calls `navigation.navigate("Modal")` to open it.

## Using Tamagui in screens

The generated screens use React Native `View`, `Text`, and `StyleSheet`. Tamagui is available through the provider but no screen uses its components yet. Replace a screen's primitives with Tamagui components once you pick a design direction:

```tsx
import { Button, H2, YStack } from "tamagui";

function HomeScreen() {
  return (
    <YStack flex={1} justifyContent="center" gap="$3" padding="$4">
      <H2>Home</H2>
      <Button>Continue</Button>
    </YStack>
  );
}
```

## Testing

The generated test mocks `tamagui` and `@tamagui/config/v3`, renders `MobileUIProvider` with a child, and asserts the child text is visible:

```tsx
test("renders children inside the mobile provider", async () => {
  const screen = await render(
    <MobileUIProvider>
      <Text>Mobile ready</Text>
    </MobileUIProvider>,
  );

  expect(screen.getByText("Mobile ready")).toBeTruthy();
});
```

The mocks keep the test independent of Tamagui's runtime. Screen tests that render real Tamagui components need the actual provider instead of the mock.

## When to choose it

Choose React Navigation when you want navigators defined in code, typed param lists, and explicit screen registration. Choose `--mobile-navigation expo-router` for file-based routes; the [Expo Uniwind guide](/guides/react-native/expo-uniwind-native/) uses that path.

## Compatibility notes

- `--frontend native-bare` is the Expo variant without Uniwind or Unistyles, so it pairs with Tamagui or Gluestack UI. `native-uniwind` and `native-unistyles` tie to their matching `--mobile-ui` values.
- `--mobile-testing maestro` adds Maestro flows, and `maestro-react-native-testing-library` adds both.
- For a generated backend and auth, see [Expo App with Hono, tRPC, and Better Auth](/guides/react-native/expo-hono-trpc-better-auth/). The `react-native` ecosystem itself scaffolds the app only.

## Deployment notes

Plan native build profiles, signing credentials, and app identifiers before the first store build. Values read at build time end up in the app bundle, so keep secrets on a server.

## Troubleshooting

| Symptom                                          | Check                                                                                  |
| ------------------------------------------------ | -------------------------------------------------------------------------------------- |
| No `app/` routes directory                       | Expected; React Navigation registers screens in `navigation/native-navigation.tsx`.    |
| Tamagui styles do not appear                     | Confirm the screen renders Tamagui components; the generated screens use `StyleSheet`. |
| Jest fails to transform a new native package     | Add the package to `transformIgnorePatterns` in `jest.config.js`.                      |
| `navigation.navigate("Modal")` fails type checks | Type the screen props with the `RootStackParamList` navigator types.                   |

## Next steps

- Open the [Stack Builder](/new?eco=react-native&fe-n=native-bare&mn=react-navigation&mui=tamagui&mst=none&mte=react-native-testing-library&mpu=none&mota=none&mdl=none).
- Read the [React Native ecosystem docs](/docs/ecosystems/#react-native).
- Review the [CLI create reference](/docs/cli/create/).
