~/swaraj.dev
Back to all posts
March 28, 20261 min read

Sharing UI Components Across React Native and Next.js in a Monorepo

Learn how to keep a single source of truth for UI components that work in both React Native and Next.js using a Yarn workspace monorepo and simple build tweaks.

monoreporeact-nativenext.jstypescriptui

Insight

When you maintain separate codebases for a mobile app and its web companion, UI drift is inevitable. A monorepo with Yarn workspaces lets you place shared components in a ui package and consume them from both React Native and Next.js projects. The trick is to align TypeScript path aliases and Metro's resolver so the same import works in both environments, while still allowing platform‑specific implementations via the *.native.tsx and *.web.tsx convention.

Example

// tsconfig.base.json (root)
{
  "compilerOptions": {
    "baseUrl": ".",
    "paths": {
      "@myapp/ui": ["packages/ui/src"]
    }
  }
}

// metro.config.js (React Native app)
const { getDefaultConfig } = require('metro-config');
module.exports = (async () => {
  const { resolver } = await getDefaultConfig();
  return {
    resolver: {
      ...resolver,
      extraNodeModules: {
        '@myapp/ui': require('path').resolve(__dirname, '../ui/src')
      }
    }
  };
})();

Takeaway

Keep a single ui package, use platform‑specific file extensions, and configure TypeScript + Metro once. Your components stay in sync, you reduce duplication, and the shared library can be versioned and tested independently.