ADR-002 — MPowerUP Cross-Platform Framework Selection¶
| Field | Value |
|---|---|
| Status | Accepted |
| Date | 2026-05-22 |
| Project | MPowerUP |
| Deciders | Kevin Crump |
Context¶
MPowerUP is a cross-platform mobile application serving vulnerable populations (people in recovery, reentry, houselessness, elderly). Choosing a mobile framework is therefore not only an engineering decision — it is also a governance decision. The question that prompts this ADR is one that recurs in funder, partner, and contributor conversations:
Is React Native the only viable open-source cross-platform option for MPowerUP, given that it is ultimately steered by Meta?
The answer is no — but the realistic alternatives are narrower than the public framework landscape suggests, because MPowerUP's architecture is constrained more by what its load-bearing libraries need than by aesthetics.
Architectural constraints driving the choice¶
MPowerUP's core stack depends on JS-ecosystem-specific libraries that cannot easily be replaced:
| Existing dependency | Ecosystem coupling |
|---|---|
| Yjs + y-protocols | JS-native CRDT; one YDoc per Circle; Rust port (y-crdt / y-octo) exists but lags in feature parity |
| js-libp2p (WebRTC + circuit-relay-v2 + KAD-DHT + noise + yamux) | JS implementation is the most feature-complete; Rust/Go impls exist but DHT + WebRTC + circuit-relay parity is uneven |
| TweetNaCl (Ed25519, secretbox) | Trivially portable, but identity/Circle keypairs already live in expo-secure-store |
| WatermelonDB | JS + SQLite; tightly coupled to React Native's JSI |
| expo-secure-store | Platform keystore access through Expo's native module |
This means: any framework that is not a JS runtime on mobile forces either porting or wrapping js-libp2p + Yjs, which is the load-bearing part of the architecture — not a swappable detail. That single constraint collapses the candidate list more than the "no tech giant" filter does.
Governance framing¶
"Tech giant backed" is a governance question, not a license question. The MIT license on React Native is permissive and fork-safe; the substantive risk is that Meta controls roadmap direction (e.g., the New Architecture rollout). That risk is real but bounded — RN has substantial outside contributors (Microsoft, Software Mansion, Expo Inc, Shopify, Callstack) and the codebase could be maintained without Meta if it had to be. It is also worth naming the second governance dependency: Expo Inc, an independent VC-backed company that owns EAS, Expo Router, and the platform modules MPowerUP relies on. RN and Expo are treated as a bundled platform choice in this ADR because their fates ride together in practice.
This ADR is written at decision time so the trade-off is legible to future contributors, and so the answer to the recurring question above is on record rather than re-derived each time it comes up.
Decision¶
Continue building MPowerUP on React Native 0.81 + Expo SDK 54, treated as a bundled platform choice.
Component breakdown¶
- React Native 0.81 (MIT, Meta-steered) — JS runtime on device, native bridge to platform APIs (location, camera, secure storage, notifications, etc.)
- Expo SDK 54 (MIT, Expo Inc) — build pipeline (EAS Build, EAS Update), file-based routing (Expo Router), platform modules (
expo-secure-store,expo-location,expo-camera,expo-notifications,expo-background-fetch, etc.) - NativeWind v4 + React Native Paper — UI layer, accessibility-friendly Material Design 3 components
- Yjs + js-libp2p + TweetNaCl + WatermelonDB — sync, networking, crypto, persistence — all run unmodified on this platform
Governance surface¶
The RN + Expo bundle creates these effective governance dependencies, named explicitly so the surface area is visible:
| Dependency | Governance type | Notes |
|---|---|---|
| Meta | Single-company steward of RN core | MIT licensed; fork-able if needed |
| Expo Inc | VC-backed independent company | EAS pricing, acquisition, layoff risk |
| Software Mansion | Independent company | Maintains Reanimated, Screens — critical native pieces |
| Microsoft | Active contributor | Not steward, but invested in RN survival via VS Code / Office mobile |
Neither dependency alone is a critical risk. Both together represent the cost of choosing this platform.
Consequences¶
Positive¶
- The existing JS-ecosystem stack (Yjs, js-libp2p, TweetNaCl, WatermelonDB) runs unmodified — no porting work
- Mature component ecosystem: React Native Paper (accessible MD3 components), Reanimated (worklets-driven animation), Expo Router (file-based navigation)
- EAS Build / EAS Update is a turnkey CI/CD pipeline; no separate build infrastructure required
- Large public hiring pool and active community — onboarding new contributors is straightforward
- The architectural pattern (CRDT-per-Circle over libp2p WebRTC) was designed against React Native's threading model and Expo's native module surface — moving frameworks would force re-litigating decisions already settled
Negative / trade-offs¶
- Meta governance: RN roadmap direction is set by Meta. Past examples include the New Architecture (Fabric + TurboModules) rollout, which has consumed significant ecosystem effort
- Expo governance: Expo Inc is VC-backed; layoffs, acquisition, or EAS pricing changes are real risks that BNI does not control
- Dual-governance surface: unlike a single-foundation framework (NativeScript, Cordova), MPowerUP carries two corporate dependencies in parallel
- Lock-in cost: swapping RN later would require rebuilding the UI layer, replacing WatermelonDB's JSI adapter, and reconfirming
js-libp2pWebRTC parity on the replacement platform
Neutral¶
- License is MIT — forking either RN or Expo is technically possible if governance ever became blocking, though the practical maintenance cost of a fork is high
- The choice does not foreclose any future direction: web (Phase 5) and desktop targets can be added via
react-native-weband Electron-equivalent shells without re-platforming the mobile app
Alternatives Considered¶
The alternatives below are the genuine non-tech-giant options that were evaluated. Each is described with an honest assessment of why it was not chosen.
NativeScript (OpenJS Foundation)¶
JS/TypeScript on device with direct native API access (no WebView). Governance is the cleanest of any candidate — OpenJS Foundation, not a single company. The existing Yjs + TweetNaCl code would run unmodified.
Rejected because:
[HYPOTHESIS]js-libp2p WebRTC + circuit-relay-v2 has production parity on NativeScript. No confirmed production deployment of this exact stack on NativeScript has been observed; the RN community has more validated libp2p deployments- Component ecosystem is materially smaller; React Native Paper has no direct NativeScript equivalent with the same accessibility surface
- WatermelonDB's JSI adapter is RN-specific; would require swapping to a different SQLite wrapper
Strongest re-evaluation candidate if Meta governance becomes blocking.
Capacitor + Svelte / SolidJS / Vue (Ionic Inc, MIT)¶
Modern WebView shell with native plugin bridge. Governance: Ionic Inc (independent VC-backed company) for Capacitor + a community frontend framework. Strongest browser-API compatibility for the p2p stack — js-libp2p WebRTC code lives closer to its native browser environment in a WebView than in RN's JS engine.
Rejected because:
- WebView UX is materially less native-feeling than RN's component-native rendering; matters for an accessibility-first app
- Accessibility parity with React Native Paper would need rebuild against a headless component library (Headless UI, Ark UI, or similar)
- Two governance dependencies remain (Ionic Inc + frontend framework steward); not a clean improvement on the RN + Expo bundle
- NativeWind would not apply — styling would migrate to plain Tailwind
Second-strongest re-evaluation candidate, especially if a more browser-native p2p stack is prioritized.
Tauri Mobile (Tauri Foundation / CommonsHaus)¶
Rust core + system WebView. Strong governance (Tauri Foundation under CommonsHaus). Mobile support reached GA-ish status in late 2025.
Rejected because:
[HYPOTHESIS]Tauri Mobile production maturity in May 2026 is comparable to Capacitor. The ecosystem is meaningfully thinner than Capacitor's- Native integration goes through Rust — a context-switch from the team's current JS/TS stack
- Yjs and libp2p-js would still run inside the WebView (works), but the architectural seam between Rust core and WebView UI adds complexity not present in either RN or Capacitor
Dioxus Mobile (community OSS)¶
Rust, React-like component model. Mobile support is alpha/beta. Excellent governance (community-led).
Rejected because:
- Would require Rust ports of every existing dependency —
y-crdtinstead of Yjs (workable),rust-libp2p(solid but not feature-equivalent for WebRTC + circuit-relay-v2), and full UI rewrite - 12+ month rewrite, not a migration
Slint (SixtyFPS GmbH)¶
Rust/C++ UI toolkit. Mobile is experimental.
Rejected because:
- Mobile support is experimental, not production-ready
- Single small company (SixtyFPS GmbH) — bus-factor risk
- Toolkit, not a framework — would still need the entire p2p, persistence, and native-bridge stack built separately
Apache Cordova (Apache Software Foundation)¶
WebView + plugin bridge. Excellent governance (ASF).
Rejected because:
- Strictly dominated by Capacitor — same architectural approach with older, less-maintained tooling
"Vue instead of React" framing¶
A recurring follow-up question deserves an answer on record: would Vue — a more community-governed component framework than React — change this analysis?
The honest answer is no, because there is no live Vue equivalent of React Native. The "Vue Native" project (the closest direct analogue) has been effectively unmaintained since ~2021 and is not a credible target. "Vue over React" on mobile therefore reduces to one of the existing options above:
- NativeScript-Vue — Vue syntax on NativeScript's native bridge (covered under NativeScript above)
- Capacitor + Vue (or Ionic Vue, or Quasar Framework) — Vue web app in a Capacitor WebView (covered under Capacitor + Svelte / SolidJS / Vue above; Vue is one of the eligible frontend framework choices, not a separate platform)
The Vue component-layer governance story is genuinely cleaner than React's — Vue Foundation + Evan You vs. Meta-stewarded React. But the mobile platform governance (NativeScript steward, Capacitor steward, or RN+Expo) is where the load-bearing risk lives, and that conversation does not change based on whether the component layer is Vue or React.
Switching from React to Vue while remaining on React Native is not coherent: Vue Native is the only path and it is dead. The framework-component swap and the mobile-platform swap travel together — [HYPOTHESIS] the Vue component ecosystem (Vuetify, PrimeVue, Quasar components, NativeScript-Vue widgets) reaches accessibility parity with React Native Paper, which would need verification before treating Vue as a viable accessibility-first choice for vulnerable-population users.
Detailed comparison: React Native vs NativeScript¶
NativeScript is the strongest re-evaluation candidate and warrants a closer comparison than the brief entry above. This subsection extends that analysis specifically for long-term project fit (5–10 year horizon).
Side-by-side¶
| Axis | React Native | NativeScript |
|---|---|---|
| License | MIT | Apache 2.0 |
| Steward | Meta (with Microsoft, Software Mansion, Expo Inc, Shopify, Callstack as major contributors) | OpenJS Foundation; core team at nStudio (~5 people) |
| Funding model | Multi-corporate engineering investment from internal RN-dependent products (Instagram/WhatsApp, Office mobile) | Foundation-governed; engineering largely from a single small company + community |
| Bridge model | JSI / TurboModules (New Architecture) — JS↔native via C++ ABI | Direct native API access from JS via reflection; no bridge concept |
| JS engine | Hermes (default) or JSC | V8 (Android), JSC (iOS) |
| UI rendering | Native components via Fabric | Native components via direct API calls |
| First-class frontend frameworks | React | TypeScript/JS, Vue, Angular, Svelte, React |
| Plugin ecosystem | Very large (npm + Expo modules) | Significantly smaller; @nativescript/* core + community plugins |
| Cloud build pipeline | EAS Build (Expo Inc) | None equivalent; bring your own CI |
| Accessibility OOTB | React Native Paper (MD3, screen-reader-validated) | NativeScript-UI + community; [HYPOTHESIS] thinner accessibility-validated surface |
| WebRTC for js-libp2p | react-native-webrtc — widely deployed |
@nativescript-community/webrtc — [HYPOTHESIS] production deployment of libp2p WebRTC + circuit-relay-v2 on NativeScript is unverified |
| Hiring pool | Large, active market | Significantly smaller |
| Detox / E2E | Native Detox support | No Detox; Appium or NS-specific tooling |
Survival risk¶
RN: low short-term survival risk. Meta uses RN in Instagram, WhatsApp, Facebook Marketplace; Microsoft uses it in Office mobile. These internal dependencies are stronger than any external promise. The realistic risk is governance direction, not abandonment.
NativeScript: meaningfully higher long-term survival risk. OpenJS Foundation provides governance stability but not engineering funding. The core engineering team is small. [HYPOTHESIS] — the project survived the 2019 Progress-to-community transition, which is a positive signal, but the funding model has not been stress-tested by a recession.
For an app serving vulnerable populations on a 5–10 year horizon, the relative failure modes matter: RN's worst case is "Meta forces a disruptive migration" (recoverable). NativeScript's worst case is "maintainers run out of funding and the platform stagnates" (harder to recover from).
Direct native API access — NativeScript's architectural advantage¶
NativeScript's reflection-based native bridge is the one area where it is architecturally superior to RN, not just different. Example: accessing androidx.work.WorkManager or AVAudioSession directly in TypeScript without writing a plugin.
For MPowerUP this matters because libp2p's mobile networking needs platform-specific tuning (Wi-Fi/cellular routing, Doze mode coordination, background task scheduling) that may eventually require APIs no Expo module covers. [HYPOTHESIS] — RN's plugin ecosystem covers ~95% of what MPowerUP needs; the remaining 5% may force the team to write native modules anyway, which is exactly the work NativeScript eliminates.
This is a real but bounded advantage. If MPowerUP hits a hard ceiling on Expo modules, NativeScript becomes materially more attractive.
Ecosystem and contributor onboarding¶
RN dominates. For a project that wants outside contributors (BNI is open source, two-person team, hoping for community involvement), the React/RN hiring pool is roughly an order of magnitude larger than NativeScript's. New contributors will already know RN; they will need to learn NativeScript.
This is a sustained drag on NativeScript over a 10-year horizon, especially for a non-profit that cannot pay competitive salaries to attract specialists.
MPowerUP-specific compatibility¶
| Dependency | RN | NativeScript |
|---|---|---|
| Yjs | runs unmodified | runs unmodified |
| js-libp2p (core) | in production | [HYPOTHESIS] works, less validated |
| js-libp2p WebRTC + circuit-relay-v2 | via react-native-webrtc |
[HYPOTHESIS] via @nativescript-community/webrtc — unverified at this stack depth |
| TweetNaCl | works | works |
| WatermelonDB | native target | would need @nativescript/sqlite + custom layer |
| Secure storage | expo-secure-store |
@nativescript/secure-storage |
| Background fetch | expo-background-fetch |
@nativescript/background-http or direct WorkManager |
| Location (significant changes) | expo-location |
@nativescript/geolocation |
The load-bearing unknown is the libp2p WebRTC stack on NativeScript. No confirmed production deployment of js-libp2p WebRTC + circuit-relay-v2 + KAD-DHT on NativeScript has been observed at the time of writing. Until that is verified, a migration carries real architectural risk on MPowerUP's central feature.
Accessibility¶
RN's accessibility story is meaningfully more mature, primarily because React Native Paper exists and has been screen-reader-tested by a large community. NativeScript can absolutely build accessible apps (its direct native API access actually helps here) but the project would have to rebuild accessibility validation from scratch rather than inheriting it from a community-tested component library.
For an app whose users are recovery / reentry / elderly populations, this is non-negotiable.
Migration cost estimate (if MPowerUP ever switched)¶
| Component | Effort |
|---|---|
| Domain logic (Yjs, libp2p, TweetNaCl, identity) | Survives unchanged |
WatermelonDB → @nativescript/sqlite |
High — different ORM model |
| RN Paper + NativeWind → Vue/Angular component library | High — full UI rebuild |
| Expo Router → NativeScript routing | Medium |
| EAS Build → custom CI | Medium |
| Native module shims | Variable — some win (no native code), some lose (no Expo plugin equivalent) |
| Accessibility re-validation | High and ongoing |
[HYPOTHESIS] — 4–6 months of focused work for a two-person team to reach feature parity, assuming the libp2p WebRTC question resolves favorably.
Verdict¶
For long-term fit, React Native remains the better default for MPowerUP today — driven primarily by:
- Larger contributor pool (matters more for a small non-profit than for a corporate user)
- More validated libp2p WebRTC stack (the load-bearing dependency)
- Mature accessibility tooling (non-negotiable for BNI users)
- Lower platform-survival risk over 5–10 years
NativeScript becomes the right choice if any of these hold:
- Meta makes a roadmap decision that materially blocks MPowerUP (the review trigger at the bottom of this ADR)
- MPowerUP hits a hard ceiling on Expo's native module surface and starts writing custom native code — at which point NativeScript's direct native access eliminates that ongoing tax
- The libp2p team or community publishes validated NativeScript bindings for WebRTC + circuit-relay-v2
- Governance becomes a funder-facing concern that materially affects fundability
Framing: NativeScript is the credible exit, not the default.
Known unknowns specific to this comparison¶
- Production parity of js-libp2p WebRTC + circuit-relay-v2 on NativeScript
- nStudio's engineering capacity and sustainability over 5+ years
- Whether NativeScript-Vue / NativeScript-React UI ecosystem can reach React Native Paper's accessibility baseline
- Relative battery performance under heavy P2P workloads (
[HYPOTHESIS]comparable, no benchmarks for this exact workload) - Whether MPowerUP will actually hit Expo's native module ceiling, or whether the existing plugin surface covers Phase 2+ needs
Explicitly excluded (tech-giant-backed)¶
Per the governance filter that prompted this ADR:
- Flutter — Google
- .NET MAUI — Microsoft
- Compose Multiplatform — JetBrains (gray area; smaller than FAANG but corporately steered)
- Lynx — ByteDance
- Hippy — Tencent
These were not evaluated because they fail the governance filter, not because they are technically unsuitable. Flutter in particular is a capable framework; the exclusion is policy-driven.
Review trigger¶
This decision should be revisited when any of the following occur:
- Meta makes a React Native roadmap decision that materially conflicts with MPowerUP's needs (e.g., a deprecation of native modules MPowerUP depends on, or a license change)
- Expo Inc undergoes a governance change — acquisition, license change, or EAS pricing change that breaks the project's budget
- NativeScript demonstrates production-validated js-libp2p WebRTC + circuit-relay-v2 parity (would elevate it from
[HYPOTHESIS]to a credible swap) - Capacitor's mobile UX or accessibility story closes the gap with React Native Paper
- A specific Meta-policy concern arises in a funder or partner conversation that requires moving for reasons of mission alignment rather than technical fit
Re-evaluation does not have to mean migration. The first review action when a trigger fires should be to update this ADR's status to Proposed (replaced by ADR-NNN) and write the successor ADR weighing the new evidence.