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")
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 })
Access it anywhere:
getBridge("auth")
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)
Then resolved anywhere:
getBridge("auth")
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)