> ## Documentation Index
> Fetch the complete documentation index at: https://docs.uniwind.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# Migrate from NativeWind to Uniwind

> Drop-in migration from NativeWind to Uniwind in under 5 minutes. No Babel preset, full Tailwind v4, 2x faster — with a step-by-step guide and a one-shot AI skill.

Migrating your project from Nativewind to Uniwind should take no more than a few minutes. This guide highlights the main differences and provides a step-by-step migration process.

<Warning>
  **Use skill to one-shot your app migration from Nativewind to Uniwind.**
  Try [Migrate Nativewind to Uniwind skill](/skills).
</Warning>

## Key Differences

Before starting the migration, it's important to understand how Uniwind differs from Nativewind:

<Check>
  Uniwind supports **Tailwind 4 only**. Make sure you upgrade Tailwind CSS to version 4.
</Check>

* **Default rem value**: Uniwind uses `16px` as the default value for the `rem` unit
* **No global overrides**: We don't override global components like Nativewind's `cssInterop`
* **CSS-based theming**: Themes are defined in CSS files instead of `tailwind.config.js`
* **No ThemeProvider required**: Uniwind doesn't require wrapping your app in a `ThemeProvider` to switch themes

## Prerequisites

Nativewind depends on the following packages:

* `react-native-reanimated`
* `react-native-safe-area-context`
* `tailwindcss`

<Info>
  We recommend keeping both `react-native-reanimated` and `react-native-safe-area-context` in your project, as they are very useful for React Native development.
</Info>

<Warning>
  You'll need to upgrade `tailwindcss` to version 4, as Uniwind requires it.
</Warning>

## Migration Steps

### Step 1: Install Uniwind

Follow the [Quickstart](/quickstart) guide to install Uniwind in your project.

### Step 2: Remove Nativewind Babel preset

Remove the Nativewind Babel preset from your `babel.config.js` file:

```js babel.config.js theme={null}
module.exports = {
  presets: ['<existing presets>'], // [!code ++]
  presets: ['<existing presets>', 'nativewind/babel'], // [!code --]
};
```

### Step 3: Update Metro configuration

Modify your `metro.config.js` to remove the Nativewind configuration and use Uniwind's configuration instead:

```js metro.config.js theme={null}
const { getDefaultConfig } = require('@react-native/metro-config');
const { withUniwindConfig } = require('uniwind/metro'); // [!code ++]

const config = getDefaultConfig(__dirname);

module.exports = withUniwindConfig(config, { // [!code ++:3]
  cssEntryFile: './src/global.css'
});
```

<Warning>
  `cssEntryFile` must be a **relative path string** from the project root (for example, `./src/global.css`).
  Do not use absolute paths or `path.resolve(...)` here.
</Warning>

<Info>
  Learn more about Metro configuration in the [Metro Config](/api/metro-config) documentation.
</Info>

### Step 4: Update your global CSS file

Replace the top of your `global.css` file with the following imports:

```css global.css theme={null}
@import 'tailwindcss';
@import 'uniwind';

/* Your custom CSS and theme configuration (see Step 6) */
```

### Step 5: Remove Nativewind type definitions

Delete the `nativewind.d.ts` file from your project, as it's no longer needed.

### Step 6: Convert your CSS to Tailwind 4 syntax

You can keep most of your existing CSS as-is, but you'll need to follow Tailwind 4's `@theme` syntax for theme configuration.

<Tip>
  Check out the [official Tailwind 4 theme guide](https://tailwindcss.com/docs/theme) for more details on the new syntax.
</Tip>

### Step 7: Migrate theme variables from JavaScript to CSS

If you defined custom theme variables using Nativewind's `vars` helper:

<AccordionGroup>
  <Accordion icon="code" title="Before: JavaScript theme configuration" defaultOpen>
    ```ts vars.ts theme={null}
    import { vars } from 'nativewind'

    export const themes = {
      light: vars({
        '--color-primary': '#00a8ff',
        '--color-gray': '#f0f0f0',
        '--color-typography': '#000',
      }),
      dark: vars({
        '--color-primary': '#273c75',
        '--color-gray': '#353b48',
        '--color-typography': '#fff',
      }),
    }
    ```
  </Accordion>

  <Accordion icon="css" title="After: CSS theme configuration" defaultOpen>
    Move these variables directly to your `global.css` file:

    ```css global.css theme={null}
    @import 'tailwindcss';
    @import 'uniwind';

    /* Other directives like @theme or custom CSS */

    @layer theme {
      :root {
        @variant light {
          --color-primary: #00a8ff;
          --color-gray: #f0f0f0;
          --color-typography: #000;
        }

        @variant dark {
          --color-primary: #273c75;
          --color-gray: #353b48;
          --color-typography: #fff;
        }
      }
    }
    ```

    <Tip>
      You can now safely delete the file containing the `vars` helper, as it's no longer used.
    </Tip>
  </Accordion>
</AccordionGroup>

<Note>
  If you need to access CSS variables in JavaScript, you can use the [`useResolveClassNames`](/api/use-resolve-class-names) hook.
</Note>

### Step 8: Remove tailwind.config.js

With Uniwind, you no longer need a `tailwind.config.js` file. Theme configuration is now done entirely in CSS.

<AccordionGroup>
  <Accordion icon="file-code" title="Example: Old tailwind.config.js">
    ```js tailwind.config.js theme={null}
    /** @type {import('tailwindcss').Config} */
    module.exports = {
      content: ['./App.tsx'],
      presets: [require('nativewind/preset')],
      theme: {
        extend: {
          colors: {
            primary: 'var(--color-primary)',
            gray: 'var(--color-gray)',
            typography: 'var(--color-typography)',
          },
        },
      },
      plugins: [],
    }
    ```

    <Warning>
      Delete this file. All theme configuration should now be in your `global.css` file.
    </Warning>
  </Accordion>
</AccordionGroup>

### Step 9: Migrate font families from tailwind.config.js

If you customized fonts in your `tailwind.config.js`, you'll need to move them to your `global.css` file. Unlike Tailwind CSS on the web, React Native doesn't support font fallbacks, so you must specify only a single font family.

<AccordionGroup>
  <Accordion icon="file-code" title="Before: tailwind.config.js with font fallbacks">
    ```js tailwind.config.js theme={null}
    module.exports = {
      theme: {
        extend: {
          fontFamily: {
            normal: ['Roboto-Regular', 'sans-serif'],
            medium: ['Roboto-Medium', 'sans-serif'],
            semibold: ['Roboto-SemiBold', 'sans-serif'],
            bold: ['Roboto-Bold', 'sans-serif'],
            mono: ['FiraCode-Regular', 'monospace'],
          },
        },
      },
    }
    ```

    <Warning>
      Font fallbacks like `['Roboto-Regular', 'sans-serif']` don't work in React Native. You can only specify a single font file.
    </Warning>
  </Accordion>

  <Accordion icon="css" title="After: global.css with single fonts">
    Move font definitions to your `global.css` using the `@theme` directive, specifying only the actual font file name:

    ```css global.css theme={null}
    @import 'tailwindcss';
    @import 'uniwind';

    @theme {
      /* Single font per variant - no fallbacks */
      --font-normal: 'Roboto-Regular';
      --font-medium: 'Roboto-Medium';
      --font-semibold: 'Roboto-SemiBold';
      --font-bold: 'Roboto-Bold';
      --font-mono: 'FiraCode-Regular';
    }
    ```

    <Info>
      React Native requires separate font files for each weight. Don't include fallback fonts like `sans-serif` or `monospace` - only use the exact font file name.
    </Info>

    Usage:

    ```tsx theme={null}
    import { Text } from 'react-native'

    <Text className="font-normal">Regular text</Text>
    <Text className="font-medium">Medium weight</Text>
    <Text className="font-bold">Bold text</Text>
    <Text className="font-mono">Monospace text</Text>
    ```
  </Accordion>
</AccordionGroup>

<Card title="Custom Fonts FAQ" icon="font" href="/faq#how-do-i-include-custom-fonts">
  Learn how to load and configure custom fonts in your React Native app
</Card>

### Step 10: (Optional) Customize the default rem value

If you want to keep Nativewind's default `rem` value of `14px`, configure it in your `metro.config.js`:

```js metro.config.js theme={null}
module.exports = withUniwindConfig(config, {
  cssEntryFile: './src/global.css',
  polyfills: { // [!code ++:3]
    rem: 14,
  },
});
```

### Step 11: Remove Nativewind's ThemeProvider

Uniwind doesn't require Nativewind's `ThemeProvider` to manage color schemes. Remove the Nativewind-specific theme provider from your app:

<Warning>
  **Important:** This step only applies to **Nativewind's ThemeProvider**. If you're using **React Navigation's ThemeProvider** to manage navigation colors, keep it! Only remove the Nativewind theme management.
</Warning>

<AccordionGroup>
  <Accordion icon="ban" title="Before: With Nativewind ThemeProvider">
    ```tsx NativewindThemeProvider.tsx theme={null}
    export const NativewindThemeProvider = ({ children }: ThemeProviderProps) => {
        const { colorScheme } = useColorScheme()

        return (
            <ThemeContext.Provider value={{ theme: colorScheme as 'light' | 'dark' }}>
                <View style={themes[colorScheme as 'light' | 'dark']} className="flex-1">
                    {children}
                </View>
            </ThemeContext.Provider>
        )
    }
    ```

    ```tsx App.tsx theme={null}
    import { NativewindThemeProvider } from './NativewindThemeProvider';

    export default function App() {
      return (
        <NativewindThemeProvider>
          <YourApp />
        </NativewindThemeProvider>
      );
    }
    ```
  </Accordion>

  <Accordion icon="check" title="After: Without Nativewind ThemeProvider">
    ```tsx App.tsx theme={null}
    export default function App() {
      return <YourApp />;
    }
    ```
  </Accordion>
</AccordionGroup>

### React Navigation Theme Provider

If you're using React Navigation, **keep your NavigationContainer's theme provider**. Uniwind works alongside React Navigation's theme system:

```tsx App.tsx theme={null}
import { NavigationContainer, DefaultTheme, DarkTheme } from '@react-navigation/native'

export default function App() {

  return (
    <NavigationContainer theme={...}>
      {/* ✅ Keep React Navigation's theme */}
      <YourApp />
    </NavigationContainer>
  )
}
```

<Info>
  React Navigation's theme system controls navigation bar colors, header styles, and card backgrounds. This is separate from Uniwind's styling and should be kept for proper navigation UI.
</Info>

### Step 12: Replace cssInterop with `withUniwind`

If you're using Nativewind's `cssInterop` to style third-party components, replace it with Uniwind's `withUniwind`:

<Info>
  Learn more about `withUniwind` in the [withUniwind API documentation](/api/with-uniwind).
</Info>

### Step 13: Handle safe area utilities

Uniwind now supports safe area classNames (`p-safe`, `m-safe`, `safe-*`, `safe-or-*`, `safe-offset-*`) when you forward insets from `react-native-safe-area-context`.

1. Install `react-native-safe-area-context`
2. Wrap your app root with `SafeAreaListener` and update Uniwind insets:

```tsx theme={null}
import { SafeAreaListener } from 'react-native-safe-area-context'
import { Uniwind } from 'uniwind'

export default function App() {
  return (
    <SafeAreaListener
      onChange={({ insets }) => {
        Uniwind.updateInsets(insets)
      }}
    >
      <View className="p-safe">
        {/* content */}
      </View>
    </SafeAreaListener>
  )
}
```

<Warning>
  This applies only to the open source version of Uniwind. In the Pro version, insets are injected automatically from C++.
</Warning>

### Step 14: Update animated class names

If you used Nativewind's `animated` class names from Tailwind, you'll need to use Reanimated's syntax directly.

<Tip>
  Check out the [React Native Reanimated documentation](https://docs.swmansion.com/react-native-reanimated/docs/css-animations/animation-name) for animation patterns.
</Tip>

### Step 15: className dedupe and specificity

Unlike Nativewind, Uniwind does not automatically deduplicate classNames, especially on web. If you have conflicting styles like `className="bg-red-500 bg-blue-500"`, both classes will be applied and the behavior depends on CSS specificity rules. We recommend using [`tailwind-merge`](https://github.com/dcastil/tailwind-merge) to properly merge and deduplicate classNames in your components.

<Info>
  Learn how to set up and use `tailwind-merge` with the `cn` utility in our [FAQ section](/faq#how-do-you-handle-merging-and-deduplicating-classnames).
</Info>

<Tip>
  Also check out the [Style specificity FAQ](/faq#how-does-style-specificity-work-in-uniwind) to understand how inline styles override className and other priority rules.
</Tip>

## Need Help?

<Card title="Missing Features?" icon="github" href="https://github.com/uni-stack/uniwind/issues">
  If you're using Nativewind and notice any missing features in Uniwind, please open an issue on GitHub. We're happy to add support!
</Card>

<Note>
  **Still having issues with migration?** Start a discussion on [GitHub](https://github.com/uni-stack/uniwind/discussions) and we'll help you migrate.
</Note>
