How to Fix: Using Tamagui to Create Mobile Apps
Using Tamagui to Create Mobile Apps: Fixing the Setup Gap Between Web-First UI and Native Runtime
The core problem behind this issue is that Tamagui is often mistaken for a drop-in mobile app framework when it is actually a cross-platform UI kit and compiler that must be wired correctly into a React Native runtime such as Expo or a bare React Native app. If you install Tamagui without configuring the compiler, Babel, Metro, tokens, and provider setup, the project either fails to start, renders incorrectly, or behaves like a web-only design system instead of a native mobile application stack.
Understanding the Root Cause
This issue happens because Tamagui does not replace the underlying mobile runtime. To build a real mobile app, you still need a native execution environment such as Expo or React Native CLI. Tamagui sits on top of that runtime and provides:
- Cross-platform styled components
- Design tokens for spacing, size, radius, and color
- Static extraction and compiler optimizations
- Shared UI across web and native targets
Most setup failures come from one of these technical causes:
- No React Native host app exists. Installing Tamagui into a plain Node or web project will not produce a mobile app.
- Babel is not configured with the Tamagui plugin, so styled components are not transformed correctly.
- Metro bundler is missing Tamagui integration, especially in Expo-based projects.
- TamaguiProvider is not mounted at the app root, so themes and tokens are unavailable.
- Version mismatch between React Native, Expo, Tamagui, and supporting packages causes runtime or build errors.
- Web assumptions leak into native code, such as using unsupported DOM APIs or web-only styling patterns.
In short, the issue is usually not that Tamagui cannot create mobile apps. It can. The real problem is that Tamagui must be integrated as part of a properly configured native application architecture.
Step-by-Step Solution
The safest way to use Tamagui for mobile apps is to start with Expo and then add Tamagui as the shared UI layer.
1. Create an Expo app
npx create-expo-app@latest tamagui-mobile-app
cd tamagui-mobile-app
This gives you a valid React Native runtime. Without this step, there is no actual mobile host for Tamagui components.
2. Install Tamagui packages
npm install tamagui @tamagui/core @tamagui/config @tamagui/babel-plugin @tamagui/metro-plugin react-native-svg
Depending on your stack, you may also need Expo-compatible peer packages. If dependency warnings appear, align them with your installed Expo version.
3. Create a Tamagui configuration file
Create tamagui.config.ts in the project root:
import { config } from '@tamagui/config/v3'
import { createTamagui } from 'tamagui'
const tamaguiConfig = createTamagui(config)
type AppConfig = typeof tamaguiConfig
declare module 'tamagui' {
interface TamaguiCustomConfig extends AppConfig {}
}
export default tamaguiConfig
This file defines the design system contract Tamagui uses at build time and runtime.
4. Configure Babel
Create or update babel.config.js:
module.exports = function(api) {
api.cache(true)
return {
presets: ['babel-preset-expo'],
plugins: [
[
'@tamagui/babel-plugin',
{
components: ['tamagui'],
config: './tamagui.config.ts'
}
],
'react-native-reanimated/plugin'
]
}
}
The Babel plugin is one of the most important pieces. Without it, Tamagui may still partially run, but you lose proper optimization and can hit component resolution issues.
5. Configure Metro
Create or update metro.config.js:
const { getDefaultConfig } = require('expo/metro-config')
const { withTamagui } = require('@tamagui/metro-plugin')
const config = getDefaultConfig(__dirname)
module.exports = withTamagui(config, {
components: ['tamagui'],
config: './tamagui.config.ts',
outputCSS: './tamagui-web.css'
})
This ensures the Metro bundler understands Tamaguiās transformation pipeline.
6. Wrap the app with TamaguiProvider
Update App.tsx:
import React from 'react'
import { TamaguiProvider, Text, YStack } from 'tamagui'
import tamaguiConfig from './tamagui.config'
export default function App() {
return (
<TamaguiProvider config={tamaguiConfig}>
<YStack flex={1} justifyContent="center" alignItems="center" padding="$4">
<Text fontSize="$8">Tamagui is running on mobile</Text>
</YStack>
</TamaguiProvider>
)
}
If TamaguiProvider is missing, theme values, tokens, and component styling may break or appear inconsistent.
7. Start the mobile app
npx expo start
Then launch the project in:
- iOS Simulator
- Android Emulator
- Expo Go, if your dependency set supports it
8. Verify native behavior
At this point, confirm that:
- Tamagui components render on device
- Spacing and typography tokens apply correctly
- No bundler errors mention missing Tamagui config
- No module resolution issues appear for React Native dependencies
9. Optional: build a reusable shared UI structure
For larger apps, place Tamagui components into a shared folder:
src/
components/
Button.tsx
Card.tsx
screens/
HomeScreen.tsx
App.tsx
tamagui.config.ts
Example shared component:
import { Button as TamaguiButton } from 'tamagui'
export function Button(props) {
return <TamaguiButton size="$4" theme="active" {...props} />
}
This keeps your design system portable across native and web targets.
10. If the app still fails, clean caches
rm -rf node_modules
rm -f package-lock.json
npm install
npx expo start -c
Many Tamagui setup problems are actually stale Metro or dependency cache issues.
Common Edge Cases
1. Expo version and Tamagui version do not align
If you use a newer Expo SDK with older Tamagui packages, bundling can fail. Always verify compatibility against the official Tamagui documentation and the relevant Expo documentation.
2. Missing peer dependencies
Some setups require additional native libraries such as react-native-svg. If icons, gradients, or other UI primitives fail, check the package peer dependency list.
3. Using web-only APIs in shared components
If a component uses window, document, or direct DOM manipulation, it will break on native. Keep shared Tamagui components limited to cross-platform primitives or isolate platform-specific logic.
4. Provider is mounted too low in the tree
If only part of the app is wrapped in TamaguiProvider, nested screens can behave unpredictably. Mount it at the root.
5. Monorepo path resolution problems
In monorepos, Metro may fail to resolve workspace packages or shared config files. In that case, you must explicitly configure workspace-aware Metro and Babel resolution.
6. Native app runs, but styles are inconsistent
This usually indicates incorrect token configuration, duplicate Tamagui versions, or partial compiler setup. Inspect your lockfile and ensure only one active Tamagui version is installed.
7. Confusing Tamagui with a navigation solution
Tamagui provides UI primitives, not full app navigation. For actual mobile screen navigation, combine it with tools such as React Navigation or Expo Router.
FAQ
Can Tamagui create a real iOS or Android app by itself?
No. Tamagui is not the native runtime. It must run inside Expo or React Native to produce actual mobile applications.
Why does Tamagui work on web but fail on mobile?
Web can appear more forgiving because your project may already have working bundler support there. Mobile requires correct React Native, Metro, and Babel integration, plus removal of any DOM-specific code.
Do I need TamaguiProvider even for a small demo app?
Yes. TamaguiProvider supplies the configuration, themes, and tokens that components depend on. Skipping it is a common cause of broken styling and runtime confusion.
The practical fix for this GitHub issue is to stop treating Tamagui as a standalone mobile framework and instead wire it into a properly configured Expo or React Native app. Once the provider, Babel plugin, Metro plugin, and config file are all in place, Tamagui becomes a powerful way to build consistent, production-ready mobile interfaces across platforms.