What I Learned Building a Production React Native Fintech App
Notes from building and owning a real React Native fintech app: payments, native modules, releases, observability, and the small things that keep users safe.
React Native is not just “write once, run everywhere” when the app is a real fintech product. It becomes a system of JavaScript, native modules, payment SDKs, release pipelines, app-store rules, analytics, crash reports, and user trust.
That is the part I enjoy. The app is not only screens. It is the whole loop from idea to store release.
Payments make everything serious
In a normal app, a failed request is annoying. In a payments app, a failed request can make the user anxious.
That changes how I write code. A payment flow needs:
- Clear loading state
- Retry rules that do not double-charge
- Server verification after gateway success
- Safe timeout behavior
- Logs that help debugging but do not expose sensitive data
- A final screen that tells the user what really happened
The UI cannot just say “Something went wrong” for every case. A pending payment, failed payment, cancelled payment, and successful payment are different states. The app should treat them differently.
Native modules are not optional sometimes
React Native is powerful, but some product ideas need platform-specific work.
On iOS, features like Siri Shortcuts and widgets belong in Swift. On Android, deeper system integrations often belong in Kotlin. The React Native layer should coordinate those modules, not pretend the platforms are the same.
The pattern I like is:
type NativeSavingsResult =
| { status: "available"; savingsText: string; deepLink: string }
| { status: "not-installed" }
| { status: "permission-needed"; permission: "accessibility" | "notifications" };
async function getSavingsState(): Promise<NativeSavingsResult> {
return NativeSavingsModule.getCurrentState();
}
The JavaScript side gets a typed result. The native side owns the platform details. The UI only decides what to show.
That boundary keeps the app maintainable.
Release discipline matters more than clever code
Mobile releases have a cost. You cannot patch every bug instantly like a web app. OTA updates help, but native changes still need store review.
So I like having a release checklist:
- Payment smoke test
- Auth refresh test
- Deep links test
- Android build on real device
- iOS build on real device
- Crash-free check after rollout
- Feature flags for risky changes
- Store listing and screenshots checked
This sounds boring, but boring release discipline saves production apps.
Observability should be designed early
Analytics is not only for marketing. In fintech, it also helps answer operational questions:
- Where are users dropping from checkout?
- Which gateway is failing more?
- Are retries helping or hurting?
- Did a new release increase crashes?
- Are users stuck in KYC, cards, gift cards, or wallet screens?
I prefer event names that read like product facts:
track("payment_verification_failed", {
gateway: "razorpay",
reason: "timeout",
orderStatus: "pending",
});
The event should help an engineer or product person understand the state without opening the code.
Security is a product feature
Users may not read every technical detail, but they feel when an app is careless.
For a fintech app, I care about:
- PIN or biometric app lock
- Secure token storage
- No secrets in app config
- VPN or proxy risk handling where needed
- Careful logging
- Strong logout behavior when auth refresh fails
- Backend verification for all important actions
Security is not a separate layer at the end. It touches the product flow.
The lesson
React Native can absolutely support serious production apps. But the real work is not only component building.
The real work is ownership:
- Own the native edge cases
- Own the release path
- Own the payment states
- Own the logs
- Own the user anxiety when money is involved
That mindset changes how I build. It makes me slower in the right places and faster everywhere else.