Log in to GraphQL EditorGet started
React Native monorepo with shared components & TypeScript

Marcin Falkowski

2/28/2023

React Native monorepo with shared components & TypeScript

React Native monorepo with shared components & TypeScript

To start we should ask a simple question: why should I use a monorepo for React Native apps? It's actually very useful when you have two (or more) similar applications. Monorepos enable sharing of components, functions and logic between all of the included applications. This can unlock a variety of benefits like core sharing, simplified ci/cd process and consistent tooling.

Setting up workspaces with Yarn

When creating a monorepo for react native applications, it is better to avoid using nohoist because we don't need duplicates inside the root level and inside the project level node_modules.

Project structure

Our projects need to be divided into subfolders. We treat them as separate entities. Here’s an example of how our project structure can look like:

Project structure

Creating a package.json file in the root directory

  1. open your terminal and go to the root directory cd my-app,
  2. create a package.json file with yarn init -y,
  3. open and check your package.json file. It should look something like this:

package.json file

  • Private: true is required. That's very important because we don't want to make our workspaces public.
  • Name: the name of your monorepo.
  • Workspaces: our workspace with the projects structured in a tree. For now, it's okay as is.

Creating React Native projects

To create React Native projects we can use the following commands:

cd packages
npx react-native init FirstApp --directory app1 --template react-native-template-typescript
npx react-native init SecondApp --directory app2 --template react-native-template-typescript

If your app names and directories match you can use this instead:

cd packages
npx react-native init app1 --template react-native-template-typescript
npx react-native init app2 --template react-native-template-typescript

where app1 and app2 are the names of both our apps and their directories.

Most likely your apps have now been created but pods will not install. No worries, we’ll fix this in the next step:

IOS configuration

  1. Open Podfile go into your app and change paths to the node_modules

Node modules paths

  1. Open your terminal and install pods. If you are in the packages/app* folder run:
	cd ios
	pod install
  1. Open XCode and your project, select the Project navigator and click on the name of your project. This will open project settings.

XCode

  1. Click Build Phases, open Bundle React Native code and images and change the script paths:

script paths

XCode

!Remember to repeat this for each app in your monorepo!

Android setup

For React Native below 0.71

  1. Open your build.gradle file and change the paths to node_modules

build file

  1. Open your settings.gradle file and change the paths to node_modules

settings file

  1. Open your build.gradle and override the default location of the cli

cli path

In the same file change these lines:

react paths

react paths

For React Native above 0.71

  1. Go to your build.gradle file
  2. Find and edit the following:

hermesc

  1. then add the codegen directory path

codegen dir

  1. and this:

build path

!Remember to repeat this for every app in your monorepo!

Android setup

For React Native below 0.71

  1. Open your build.gradle file and change the paths to node_modules

node modules paths

  1. Open your settings.gradle file and change the paths to node_modules

node modules paths

  1. Open your build.gradle file again and override the default location of the cli

cli path

In the same file change these lines:

react paths

react paths

For React Native above 0.71

  1. Go to your build.gradle file
  2. Find and edit the following:

hermesc

  1. then add this

build paths

  1. and this

build paths

!Remember to repeat this for every app in your monorepo!

Metro configuration

Now we should indicate for metro where node_modules are located. Go to the metro.config.js file and add watchFolders:

metro config

Shared package

Inside the shared folder, create a package.json file.

	cd shared
	yarn init -y

Your package.json file should look something like this:

package json

Close your package.json and now let's create a tsconfig.json file:

ts config

Now go into your shared folder, and create an src folder there. Its structure should look something like mine:

structure

Where Test.tsx is a React Function component :)

Now, we can export this via index.ts in a shared folder.

Now let's create a build of our shared directory:

yarn build

With that, we have finished setting up our shared folder. Now we should indicate this directory to our applications. So now we need to add our shared dependency to the package.json file in all our applications:

dependency

and for metro.config.js:

metro config

Then go back into your root directory and run:

yarn

Now we should be able to import things from shared directly into our React Native Apps:

import React, { type PropsWithChildren } from 'react';
import {
  SafeAreaView,
  ScrollView,
  StatusBar,
  StyleSheet,
  Text,
  useColorScheme,
  View,
} from 'react-native';

import {
  Colors,
  DebugInstructions,
  Header,
  LearnMoreLinks,
  ReloadInstructions,
} from 'Libraries';

import { Test } from '@my-app';

const Section: React.FC<
  PropsWithChildren<{
    title: string;
  }>
> = ({ children, title }) => {
  const isDarkMode = useColorScheme() === 'light';
  return (
    <View style={styles.sectionContainer}>
      <Text
        style={[
          styles.sectionTitle,
          {
            color: isDarkMode ? Colors.white : Colors.black,
          },
        ]}>
        {title}
      </Text>
      <Text
        style={[
          styles.sectionDescription,
          {
            color: isDarkMode ? Colors.light : Colors.dark,
          },
        ]}>
        {children}
      </Text>
    </View>
  );
};

const App = () => {
  const isDarkMode = useColorScheme() === 'dark';

  const backgroundStyle = {
    backgroundColor: !isDarkMode ? Colors.darker : Colors.lighter,
  };

  return (
    <SafeAreaView style={backgroundStyle}>
      <StatusBar
        barStyle={!isDarkMode ? 'light-content' : 'dark-content'}
        backgroundColor={backgroundStyle.backgroundColor}
      />
      <ScrollView
        contentInsetAdjustmentBehavior="automatic"
        style={backgroundStyle}>
        <Header />
        <Test />
        <View
          style={{
            backgroundColor: !isDarkMode ? Colors.black : Colors.white,
          }}>
          <Section title="Step One">
            Edit <Text style={styles.highlight}>App.tsx</Text> to change this
            screen and then come back to see your edits.
          </Section>
          <Section title="See Your Changes">
            <ReloadInstructions />
          </Section>
          <Section title="Debug">
            <DebugInstructions />
          </Section>
          <Section title="Learn More">
            Read the docs to discover what to do next:
          </Section>
          <LearnMoreLinks />
        </View>
      </ScrollView>
    </SafeAreaView>
  );
};

const styles = StyleSheet.create({
  sectionContainer: {
    marginTop: 32,
    paddingHorizontal: 24,
  },
  sectionTitle: {
    fontSize: 24,
    fontWeight: '600',
  },
  sectionDescription: {
    marginTop: 8,
    fontSize: 18,
    fontWeight: '400',
  },
  highlight: {
    fontWeight: '700',
  },
});

export default App;

And that’s how it works! Enjoy!

Check out our other blogposts

GraphQL cache: using LRU cache with GraphQL Zeus
Michał Tyszkiewicz
Michał Tyszkiewicz
GraphQL cache: using LRU cache with GraphQL Zeus
1 min read
13 days ago
Unlocking the Power of React 19
Tomasz Gajda
Tomasz Gajda
Unlocking the Power of React 19
1 min read
about 2 months ago
Zeus update - GraphQL spread operator
Michał Tyszkiewicz
Michał Tyszkiewicz
Zeus update - GraphQL spread operator
1 min read
3 months ago

Ready for take-off?

Elevate your work with our editor that combines world-class visual graph, documentation and API console

Get Started with GraphQL Editor