name: setting-up-expo-with-uniwind-biome description: Sets up a new Expo project with Uniwind (NativeWind v4) for Tailwind styling and Biome for linting and formatting. Use when bootstrapping React Native projects with modern tooling.
Setup Expo Project with Uniwind and Biome
A step-by-step guide to create a new Expo project configured with Uniwind (NativeWind v4) and Biome for linting and formatting.
Prerequisites
- Node.js 18+ installed
- Bun package manager installed (
curl -fsSL https://bun.sh/install | bash)
Step 1: Create Empty Expo Project
bunx create-expo-app@latest my-app --template blank
cd my-app
Step 2: Install Uniwind (NativeWind v4)
Install the required dependencies:
bun add nativewind tailwindcss react-native-reanimated react-native-safe-area-context
Initialize Tailwind CSS configuration:
bunx tailwindcss init
Update tailwind.config.js:
/** @type {import('tailwindcss').Config} */
module.exports = {
content: [
"./App.{js,jsx,ts,tsx}",
"./app/**/*.{js,jsx,ts,tsx}",
"./components/**/*.{js,jsx,ts,tsx}",
"./screens/**/*.{js,jsx,ts,tsx}"
],
presets: [require("nativewind/preset")],
theme: {
extend: {},
},
plugins: [],
}
Create metro.config.js in the root directory:
const { getDefaultConfig } = require("expo/metro-config");
const { withNativeWind } = require("nativewind/metro");
const config = getDefaultConfig(__dirname);
module.exports = withNativeWind(config, { input: "./global.css" });
Create global.css in the root directory:
@tailwind base;
@tailwind components;
@tailwind utilities;
Update babel.config.js:
module.exports = function (api) {
api.cache(true);
return {
presets: [
["babel-preset-expo", { jsxImportSource: "nativewind" }]
],
plugins: [
"react-native-reanimated/plugin",
],
};
};
Create nativewind-env.d.ts for TypeScript support (if using TypeScript):
/// <reference types="nativewind/types" />
Update App.tsx or App.js:
import "./global.css";
import { StatusBar } from 'expo-status-bar';
import { Text, View } from 'react-native';
export default function App() {
return (
<View className="flex-1 items-center justify-center bg-white">
<Text className="text-2xl font-bold text-blue-600">
Hello Uniwind!
</Text>
<StatusBar style="auto" />
</View>
);
}
Step 3: Setup Biome
Install Biome:
bun add --dev --exact @biomejs/biome
Initialize Biome configuration:
bunx @biomejs/biome init
Update biome.json with recommended settings:
{
"$schema": "https://biomejs.dev/schemas/1.9.4/schema.json",
"vcs": {
"enabled": true,
"clientKind": "git",
"useIgnoreFile": true
},
"files": {
"ignoreUnknown": false,
"ignore": [
"node_modules",
".expo",
"dist",
"build",
"android",
"ios"
]
},
"formatter": {
"enabled": true,
"indentStyle": "space",
"indentWidth": 2,
"lineWidth": 100
},
"organizeImports": {
"enabled": true
},
"linter": {
"enabled": true,
"rules": {
"recommended": true,
"suspicious": {
"noExplicitAny": "warn"
}
}
},
"javascript": {
"formatter": {
"quoteStyle": "double",
"semicolons": "always",
"trailingCommas": "es5"
}
}
}
Add scripts to package.json:
{
"scripts": {
"start": "expo start",
"android": "expo start --android",
"ios": "expo start --ios",
"web": "expo start --web",
"lint": "biome lint .",
"format": "biome format --write .",
"check": "biome check --write ."
}
}
Note: Bun will automatically use
bun runfor these scripts.
Step 4: Verify Setup
Run the linter:
bun run lint
Format your code:
bun run format
Start the development server:
bun start
Optional: Pre-commit Hook
Install Husky and lint-staged:
bun add --dev husky lint-staged
bunx husky init
Update .husky/pre-commit:
bunx lint-staged
Add to package.json:
{
"lint-staged": {
"*.{js,jsx,ts,tsx,json}": [
"biome check --write --no-errors-on-unmatched"
]
}
}
Summary
You now have an Expo project with:
- ✅ Uniwind (NativeWind v4) for Tailwind CSS styling
- ✅ Biome for fast linting and formatting
- ✅ TypeScript support (optional)
- ✅ Pre-configured scripts for development
Happy coding! 🚀