NativeWind Styling Not Working in NX Monorepo with Expo
I'm setting up a NX monorepo with Expo for mobile apps and using NativeWind for styling. While the project runs fine with standard CSS, I'm encountering issues when integrating NativeWind.
Despite following the official documentation for NativeWind setup with Expo Router (Link: https://www.nativewind.dev/getting-started/expo-router), the styles do not appear on the screen.
My environment setup includes creating the NX Monorepo, installing expo by configuring it successfully and integrating nativewind using the official documentation.
Below is my tailwind.config.js file
/** @type {import('tailwindcss').Config} */
module.exports = {
content: [
"./app/**/*.{js,jsx,ts,tsx}",
"./src/**/*.{js,jsx,ts,tsx}", // Assuming components are in the src folder
],
presets: [require("nativewind/preset")],
theme: {
extend: {},
},
plugins: [],
};
Below is a sample component where styles are not showing up:
import React from 'react';
import { Text, View } from 'react-native';
import "../../global.css";
export default function App() {
return (
<View>
<Text className='flex flex-col justify-center items-center bg-black text-white'>
Hello World
</Text>
</View>
);
}
I tried to debug about this by clearing the cache - expo start -c , ensured tailwind.config.js included all relevant paths and verifying the NativeWind setup with the documentation.
While researching, I found this GitHub issue (https://github.com/nativewind/nativewind/issues/627) suggesting updates to the metro.config.js file. After applying the changes, the project fails to load and shows the following error:
"Development server returned response error code: 500" on the emulator.
I've attached the error screenshot for reference (see below).
I’ve created a GitHub repository to demonstrate the issue: https://github.com/AryanFrobada/nx-monorepo-expo-with-nativewind-setup
Has anyone successfully integrated NativeWind into an NX monorepo with Expo?
I’d appreciate it if someone could review my setup and let me know if I’ve missed something, especially with configurations like the Metro bundler or Tailwind paths.
I’d also like guidance on resolving the status code 500 error that appears after updating the metro.config.js file based on this suggestion - https://github.com/nativewind/nativewind/issues/627
I’d be grateful for any advice or suggestions to resolve this issue. Thank you for your time and support!
I’m also facing the same issue with NativeWind styling not showing up in my NX monorepo with Expo. Like you, I followed the official documentation for setting up NativeWind with Expo Router, but the styles don’t seem to appear on the screen.
I’m also facing the same issue while integrating NativeWind into my NX monorepo with Expo. Despite following the documentation, I’ve tried modifying metro.config.js as suggested in GitHub issue (#627 ), but I ended up with a "Development server returned response error code: 500" on the emulator. It seems like something’s missing or misconfigured, but I haven’t been able to resolve it yet. Any help or suggestions would be appreciated! Here's the GitHub repository: https://github.com/naveenm666/nx-expo-nativewind
I'm encountering the same problem with NativeWind styles not showing in my NX monorepo while using Expo. Like you, I followed the official NativeWind documentation for integration with Expo Router, but the styles aren't rendering on the screen. Could you suggest an alternative solution or approach to resolve this?
Have kinda same issue; no errors after following this which got things working (I thought, at least no errors).
However, applying classNames to any component has no affect. Also tried installing nativecn components, no errors but again - they have no styling at all.
- I'm running the verifyInstallation() which yields
NativeWind verifyInstallation() found no errors. - I've cleared cache upon starting expo
- global.css is present and loads tailwind correctly after following above link example
Package versions;
- "nativewind": "^4.1.23"
- "tailwindcss": "^3.4.17"
Using pnpm
metro.config.js According to link above as to how to load configs within when using NX monorepo.
const { withNxMetro } = require('@nx/expo');
const { getDefaultConfig } = require('@expo/metro-config');
const { mergeConfig } = require('metro-config');
const { withNativeWind } = require("nativewind/metro")
const defaultConfig = getDefaultConfig(__dirname);
const { assetExts, sourceExts } = defaultConfig.resolver;
/**
* Metro configuration
* https://reactnative.dev/docs/metro
*
* @type {import('metro-config').MetroConfig}
*/
const customConfig = {
cacheVersion: 'expo-mobile-app',
transformer: {
babelTransformerPath: require.resolve('react-native-svg-transformer'),
},
resolver: {
assetExts: assetExts.filter((ext) => ext !== 'svg'),
sourceExts: [...sourceExts, 'cjs', 'mjs', 'svg'],
},
};
async function createConfig() {
const nxConfig = await withNxMetro(mergeConfig(defaultConfig, customConfig), {
debug: false,
extensions: [],
watchFolders: []
})
return withNativeWind(nxConfig, {
input: './src/styles/global.css'
})
}
module.exports = createConfig()
babel.config.js
module.exports = function (api) {
api.cache(true)
return {
presets: [
["babel-preset-expo", { jsxImportSource: "nativewind" }],
"nativewind/babel",
],
plugins: [
"react-native-reanimated/plugin",
],
}
}
Output when DEBUG (all green);
- nativewind input: [*****]/src/styles/global.css +0ms
- nativewind important: undefined +49ms
- nativewind checking TypeScript setup +0ms
- nativewind withCssInterop +0ms
- nativewind outputDirectory [******]/node_modules/.pnpm/[email protected]_aoovcboblia2ohvrwqeki57kii/node_modules/react-native-css-interop/.cache +0ms
- nativewind isRadonIDE: false +0ms
- nativewind enhanceMiddleware.setup +296ms
Hitting a dead end after hours of trying to get this to work :/
@jentzon check the path of you global.css, this solved my issue, but I needed to update the path of my global.css
my issue is more related to the fact that react-native-css-interop is not found by eas build, which makes sense when i run the app locally i always have to run
npx expo install nativewind in order for the react-native-css-interop to be set in my root node_modules
@jentzon check the path of you global.css, this solved my issue, but I needed to update the path of my global.css
Thanks for your response! I've double and triple checked basically all paths in my configs 😅 Including the global.css file. I've also tried moving this around but without result. One thing to mention perhaps is that I'm using expo-router with the auth wrap (https://docs.expo.dev/router/reference/authentication/). Anyone else that has problems and uses expo-router wrap like their suggestion for auth? Or are there problems without it as well? I'm loading the global.css file within my _layout.tsx file which is the first entry point after expo-router that I control. The file content is below;
import React from 'react';
import { SessionProvider } from '../auth/authCtx';
import { Slot } from 'expo-router';
import '../styles/global.css';
export const App = () => {
return (
<SessionProvider>
<Slot />
</SessionProvider>
);
};
export default App;
Anyhow, perhaps others here can compare set ups to what I've mentioned and we can drill down to some problematic area together and find what the problem is 🤗
@jentzon I am actually using it with router, mine is a little different since I am doing it inside a NX monorepo so I didn't get the default router that comes out of the box. But I have also setup it up using the router template. My recommendation is re-trace your steps, setup a brand new app and re-apply the steps. If that works, then compare what is different.
After trouble shooting, The issue seems to be metro config related and I have been struggling on this from a month now.
Git repo: https://github.com/Shanie1331/Test
Created same issue on Nx: https://github.com/nrwl/nx/issues/29624
Here is my metro config
const { withNxMetro } = require('@nx/expo');
const { getDefaultConfig } = require('@expo/metro-config');
const { mergeConfig } = require('metro-config');
const exclusionList = require('metro-config/src/defaults/exclusionList');
const { withNativeWind } = require('nativewind/metro');
const defaultConfig = getDefaultConfig(__dirname);
const { assetExts, sourceExts } = defaultConfig.resolver;
/**
* Metro configuration
* https://reactnative.dev/docs/metro
*
* @type {import('metro-config').MetroConfig}
*/
const customConfig = {
cacheVersion: 'Demo',
transformer: {
babelTransformerPath: require.resolve('react-native-svg-transformer'),
},
resolver: {
assetExts: assetExts.filter((ext) => ext !== 'svg'),
sourceExts: [...sourceExts, 'cjs', 'mjs', 'svg'],
blockList: exclusionList([/^(?!.*node_modules).*\/dist\/.*/]),
// unstable_enableSymlinks: true,
// unstable_enablePackageExports: true,
},
};
const nativeWindConfig = withNativeWind(
mergeConfig(defaultConfig, customConfig),
{
input: './global.css',
}
);
module.exports = withNxMetro(nativeWindConfig, {
// Change this to true to see debugging info.
// Useful if you have issues resolving modules
debug: false,
// all the file extensions used for imports other than 'ts', 'tsx', 'js', 'jsx', 'json'
extensions: [],
// Specify folders to watch, in addition to Nx defaults (workspace libraries and node_modules)
watchFolders: [],
});
@Shanie1331, a referenced this link in my first comment up above - https://github.com/nativewind/nativewind/issues/1089#issuecomment-2370432529. This will probably help you resolve the metro config issue.
I have a working expo application running in my nx workspace. Try adding this to your tailwind.config.js:
const { createGlobPatternsForDependencies } = require('@nx/react/tailwind');
const { join } = require('path');
module.exports = {
content: [
join(
__dirname,
'{src,pages,components,app}/**/*!(*.stories|*.spec).{ts,tsx,html}',
),
...createGlobPatternsForDependencies(__dirname),
],
...etc
metro.config.js:
const { getDefaultConfig } = require('@expo/metro-config');
const { withNxMetro } = require('@nx/expo');
const { mergeConfig } = require('metro-config');
const { withNativeWind } = require('nativewind/metro');
async function config() {
const defaultConfig = getDefaultConfig(__dirname);
const { assetExts, sourceExts } = defaultConfig.resolver;
/**
* Metro configuration
* https://facebook.github.io/metro/docs/configuration
*
* @type {import('metro-config').MetroConfig}
*/
const customConfig = {
transformer: {
babelTransformerPath: require.resolve('react-native-svg-transformer'),
},
resolver: {
assetExts: assetExts.filter((ext) => ext !== 'svg'),
sourceExts: [...sourceExts, 'svg'],
},
};
const nxMetroConfig = await withNxMetro(
mergeConfig(defaultConfig, customConfig),
{
// Change this to true to see debugging info.
// Useful if you have issues resolving modules
debug: false,
// all the file extensions used for imports other than 'ts', 'tsx', 'js', 'jsx', 'json'
extensions: [],
// Specify folders to watch, in addition to Nx defaults (workspace libraries and node_modules)
watchFolders: [],
},
);
const finalConfig = withNativeWind(nxMetroConfig, {
input: './global.css',
});
return finalConfig;
}
module.exports = config();
Hey @jentzon, I've never used nx so will be tough for me to assist here but a couple things I would consider:
- why are you including
"./app/**/*.{js,jsx,ts,tsx}",in your content array if your app doesn't have that path? withNxMetroseems to return a Promise so you likely want toawaitthat in yourmetro.config.js, similar to what @kirstilynn has- similar to @Shooksie's suggestion, go back through step by step in a first principle manner to reason about what each addition is actually doing
Regardless, I will note this and surface at our next office hours (held in our Discord) with Mark.
Hi, thanks to everyone here, i managed to make it work on both the web and Android versions with NX as follows:
Note: It also works (with proper config) with expo-router
Finally, the only effective workaround for me was to precede the NativeWind configuration with the NX Metro configuration in metro.config.js
[nx-workspace]/apps/mobile
tailwind.config.js
/** @type {import('tailwindcss').Config} */
module.exports = {
content: [
"./src/**/*.{js,jsx,ts,tsx}",
],
presets: [require("nativewind/preset")],
theme: {
extend: {},
},
plugins: [],
}
global.css
@tailwind base;
@tailwind components;
@tailwind utilities;
.babelrc.js
module.exports = function(api) {
api.cache(true)
return {
presets: [
["babel-preset-expo", {jsxImportSource: "nativewind"}],
"nativewind/babel",
],
plugins: [
"react-native-reanimated/plugin",
]
}
}
metro.config.js
const { getDefaultConfig } = require('expo/metro-config')
const { withNativeWind } = require('nativewind/metro')
const { withNxMetro } = require('@nx/expo')
module.exports = Promise.resolve(getDefaultConfig(__dirname))
.then(config => withNxMetro(config, {
debug: false,
extensions: [],
watchFolders: []
}))
.then((config) => withNativeWind(config, { input: './global.css' }))
index.js / index.ts
import './global.css';
import { registerRootComponent } from 'expo';
import App from './src/app/App';
registerRootComponent(App);
src/app/App.tsx
import {StatusBar} from 'expo-status-bar'
import {StyleSheet, Text, View} from 'react-native'
export default function App() {
return (
<View style={styles.container}>
<Text className="text-red-500 bg-blue-500">Open up App.tsx to start working on your app!</Text>
<Text className="text-green-500 text-lg font-medium">Welcome to Tailwind</Text>
<StatusBar style="auto"/>
</View>
)
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#fff',
alignItems: 'center',
justifyContent: 'center'
}
})
@r3gisrc The metro config / promise was the missing key for me. Thanks!
.... all the nx stuff
module.exports = withNxMetro(mergeConfig(defaultConfig, customConfig), {
// Change this to true to see debugging info.
// Useful if you have issues resolving modules
debug: false,
// all the file extensions used for imports other than 'ts', 'tsx', 'js', 'jsx', 'json'
extensions: [],
// Specify folders to watch, in addition to Nx defaults (workspace libraries and node_modules)
watchFolders: [],
}).then((config) => withNativeWind(config, { input: './global.css' }));
Thanks @r3gisrc, I'll add this to the documentation unless you'd be willing to add a page in the "Setup" section for getting started with NX.
@danstepanov https://github.com/nativewind/nativewind/pull/1387
I already solved it https://github.com/nativewind/nativewind/discussions/542#discussioncomment-14598923