DEV Community

Abdalla Emad
Abdalla Emad

Posted on

Sharing State Across Packages and Apps in a React Monorepo (Web + Mobile)

Article

Introduction

If you're building a modern app, chances are you’re not just building one thing.

You might have:

  • a web app (Next.js)
  • a mobile app (React Native)
  • shared UI packages
  • multiple internal modules

And if you're using a monorepo (with tools like Turborepo, Nx, or Lerna), you’ll quickly run into this problem:

How do you share state across packages… and across apps?


The Real Problem

Sharing state inside a single React app is easy.

Sharing it across:

  • packages
  • apps
  • platforms (web + mobile)

is where things break down.

You start dealing with:

  • duplicated stores
  • inconsistent state
  • complex syncing logic
  • unnecessary API calls

Common Approaches (and Their Limits)

Prop drilling / Context

Only works inside one React tree.


Shared packages

You can move state into a shared package…
but now everything is tightly coupled.


Redux / Zustand across apps

Tools like Redux Toolkit or Zustand work great inside a single app.

But across packages and apps?

You end up writing a lot of glue code.


APIs for syncing state

Works… but:

  • adds latency
  • increases complexity
  • feels like overkill for local state

What We Actually Want

Something like this:

const auth = getBridge("auth")
Enter fullscreen mode Exit fullscreen mode

From:

  • any package
  • any app
  • web or mobile

Same state. Same source of truth.


Introducing shared-state-bridge

I built shared-state-bridge to solve this exact problem.

It’s a cross-package + cross-app state store for React monorepos.


What Makes It Different

1. Share state across packages

Create a named store once:

createBridge("auth", { user: null })
Enter fullscreen mode Exit fullscreen mode

Access it anywhere:

getBridge("auth")
Enter fullscreen mode Exit fullscreen mode

No prop drilling. No wiring.


2. Share state across apps (Web + Mobile)

This is where it gets powerful.

You can sync state between:

  • Next.js apps
  • React Native apps
  • multiple clients

Using built-in WebSocket sync.

That means:

  • login state shared between web and mobile
  • real-time updates across apps
  • consistent user experience everywhere

3. React 18 optimized

Uses useSyncExternalStore for:

  • fine-grained updates
  • minimal re-renders

4. Persistence built-in

Works out of the box with:

  • localStorage (web)
  • AsyncStorage (React Native)

5. Tiny and dependency-free

  • ~1.2 KB core
  • zero dependencies
  • fully tree-shakeable

6. Full TypeScript support

Everything is typed:

  • state
  • setters
  • selectors
  • plugins

Why This Matters

Modern apps are no longer single-platform.

You’re building:

  • web + mobile
  • multiple frontends
  • shared ecosystems

And state becomes fragmented across:

  • apps
  • packages
  • environments

shared-state-bridge gives you:

One shared state layer across everything.


How It Works (Conceptually)

Each state is registered globally by name:

createBridge("auth", initialState)
Enter fullscreen mode Exit fullscreen mode

Then resolved anywhere:

getBridge("auth")
Enter fullscreen mode Exit fullscreen mode

Internally, it uses Symbol.for so it works even when:

  • multiple builds exist
  • packages are duplicated in node_modules

Comparison

Feature shared-state-bridge Zustand Redux Toolkit
Cross-package state
Cross-app (web + mobile)
Real-time sync
Boilerplate Minimal Minimal High

When You Should Use It

This is perfect if you have:

  • a React monorepo
  • multiple apps (web + mobile)
  • shared runtime state
  • real-time requirements

Try It Out

Check it here:

https://www.npmjs.com/package/shared-state-bridge


Final Thoughts

State management is hard.

Cross-package state is harder.

Cross-app state (web + mobile) is where things usually fall apart.

Instead of adding more complexity, a better approach is:

make state globally accessible — across packages and apps.


Feedback

I’d love to hear:

  • how you're handling cross-app state
  • whether you've faced this issue
  • what you think about this approach

Top comments (0)