Skip to main content
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.

Key Differences

Before starting the migration, it’s important to understand how Uniwind differs from Nativewind:
Uniwind supports Tailwind 4 only. Make sure you upgrade Tailwind CSS to version 4.
  • 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
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.
You’ll need to upgrade tailwindcss to version 4, as Uniwind requires it.

Migration Steps

Step 1: Install Uniwind

Follow the 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:
babel.config.js
module.exports = {
  presets: ['<existing presets>'], 
  presets: ['<existing presets>', 'nativewind/babel'], 
};

Step 3: Update Metro configuration

Modify your metro.config.js to remove the Nativewind configuration and use Uniwind’s configuration instead:
metro.config.js
const { getDefaultConfig } = require('@react-native/metro-config');
const { withUniwindConfig } = require('uniwind/metro'); 

const config = getDefaultConfig(__dirname);

module.exports = withUniwindConfig(config, { 
  cssEntryFile: './src/global.css'
});
Learn more about Metro configuration in the Metro Config documentation.

Step 4: Update your global CSS file

Replace the top of your global.css file with the following imports:
global.css
@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.
Check out the official Tailwind 4 theme guide for more details on the new syntax.

Step 7: Migrate theme variables from JavaScript to CSS

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

Before: JavaScript theme configuration

vars.ts
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',
  }),
}

After: CSS theme configuration

Move these variables directly to your global.css file:
global.css
@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;
    }
  }
}
You can now safely delete the file containing the vars helper, as it’s no longer used.
If you need to access CSS variables in JavaScript, you can use useResolveClassNames hook.

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.
tailwind.config.js
/** @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: [],
}
Delete this file. All theme configuration should now be in your global.css file.

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.
tailwind.config.js
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'],
      },
    },
  },
}
Font fallbacks like ['Roboto-Regular', 'sans-serif'] don’t work in React Native. You can only specify a single font file.
Move font definitions to your global.css using the @theme directive, specifying only the actual font file name:
global.css
@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';
}
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.
Usage:
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>

Custom Fonts FAQ

Learn how to load and configure custom fonts in your React Native app

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:
metro.config.js
module.exports = withUniwindConfig(config, {
  cssEntryFile: './src/global.css',
  polyfills: { 
    rem: 14,
  },
});

Step 11: Remove ThemeContext where you set colorScheme

Uniwind doesn’t require a ThemeProvider to manage themes. Simply remove it from your app:
ThemeProvider.tsx
export const ThemeProvider = ({ 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>
    )
}
App.tsx
import { ThemeProvider } from './ThemeProvider';

export default function App() {
  return (
    <ThemeProvider>
      <YourApp />
    </ThemeProvider>
  );
}
App.tsx
export default function App() {
  return <YourApp />;
}

Step 12: Replace cssInterop with withUniwind

If you’re using Nativewind’s cssInterop to style third-party components, replace it with Uniwind’s withUniwind:
Learn more about withUniwind in the withUniwind API documentation.

Step 13: Handle safe area utilities

If you used Nativewind’s p-safe or m-safe class names, you’ll need to use the useSafeAreaInsets hook from react-native-safe-area-context instead:
export default function App() {
  return <View className="p-safe" />;
}
import { useSafeAreaInsets } from 'react-native-safe-area-context';

export default function App() {
  const insets = useSafeAreaInsets();
  return <View style={{ paddingTop: insets.top }} />;
}
Uniwind doesn’t depend on react-native-safe-area-context, and there’s no way to access safe area values directly from React Native’s core APIs.
You can also use SafeAreaView from react-native-safe-area-context to handle safe area insets.

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.
Check out the React Native Reanimated documentation for animation patterns.

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 to properly merge and deduplicate classNames in your components.
Learn how to set up and use tailwind-merge with the cn utility in our FAQ section.
Also check out the Style specificity FAQ to understand how inline styles override className and other priority rules.

Need Help?

Missing Features?

If you’re using Nativewind and notice any missing features in Uniwind, please open an issue on GitHub. We’re happy to add support!
Still having issues with migration? Start a discussion on GitHub and we’ll help you migrate.