Granite: Toss's React Native Microservice Framework Is Worth a Serious Look
I went into this one skeptical. Another React Native framework? Really? We've spent the last five years watching the RN ecosystem consolidate around Expo, and here comes Toss — yes, the Korean fintech giant behind Toss — shipping a framework that pitches "microservice apps," "200KB bundles," and "brownfield integration" all at once. That's a lot of buzzwords for a project sitting at version 0.1.34.
But then I looked at the commit history. The repo has 475 stars, 51 forks, and it's climbing. The last push was days ago, not months. The contributor list isn't anonymous — leegeunhyeok, gronxb, heecheolman — these are real maintainers shipping real PRs. And it's backed by a company with actual production apps running on this thing. Toss's banking app alone has millions of users.
So I read the code, dug into the architecture, and tried to figure out who this is actually for. Here's my honest take.
What it actually does
Granite is not a competitor to Expo Go. It's not trying to replace your dev server or sell you on managed workflows. What it's actually doing is treating each React Native screen (or screen group) as an independently deployable microservice, with its own bundle, its own release cadence, and its own CDN-backed distribution.
The mental model looks like this: you've got a native iOS/Android app — that's your "host." You write React Native screens that live in separate packages. Each package compiles to a tiny JS bundle (the 200KB claim is real, it's coming from aggressive code splitting plus a curated runtime). The host app fetches these bundles from S3/CloudFront at runtime and mounts them. When you ship a fix to one screen, you don't ship a new app version — you ship a new bundle file.
The brownfield angle is the key selling point. You don't need to rewrite your existing app. You add a native module, point it at your Granite bundles, and start migrating screens one at a time. This is the same pattern Facebook used internally for years before it leaked into the broader ecosystem via React Native's "embedded" mode, but Granite wraps it in a CLI and a deployment pipeline.
The AWS piece isn't a marketing afterthought either. There's a @granite-js/pulumi-aws package that gives you pre-built Pulumi constructs — ReactNativeBundleCDN, the S3 bucket config, IAM, the whole thing. The granite-forge deploy CLI is the production deployment tool. This isn't "BYO infrastructure" with hand-wave docs; it's opinionated infrastructure that you either adopt wholesale or don't.
Why this matters now
The honest truth is that most React Native apps do not need microservice architecture. If you've got a single-team app with 30 screens, shipping monolithically via OTA updates (or, god forbid, app store releases) is fine. You don't need Granite.
But that's not who this is aimed at. Granite is aimed at the Tosses, the Shopees, the Coupangs — companies running React Native at scale inside massive native apps, with dozens of teams shipping at different cadences, where a single bugfix shouldn't require a 14-day App Store review cycle. For that audience, this is a real problem.
The other reason it matters is brownfield. The React Native ecosystem has been terrible at brownfield for years. The official docs treat it as an afterthought. Expo is great for greenfield, but integrating Expo into a 5-year-old native app is a special kind of pain. Granite leads with brownfield as a first-class concern — the GraniteReactHost API, the graniteHostDidStart lifecycle hook (just added in PR #349), the InitialPropsProvider for context propagation from the native host. These are all signals that the team has actually shipped this into a real app and knows where the rough edges are.
And then there's the timing. React Native's New Architecture is finally stabilizing. Hermes is the default. The community has years of muscle memory around how to structure large apps. Granite lands at a moment when the platform is mature enough that this kind of architectural abstraction is actually viable.
Key features worth highlighting
1. Real bundle splitting, not marketing. The 200KB claim isn't aspirational — it's enforced by the build pipeline. Each Granite package compiles independently with ESBuild, and the runtime only loads what each screen needs. If you've ever watched a 5MB JS bundle parse on app launch and wanted to cry, this architecture is genuinely appealing.
2. Pulumi-native infrastructure. Most RN frameworks punt on deployment. Granite gives you a typed Pulumi provider that provisions S3, CloudFront, and IAM in a few lines of TypeScript. For teams already on AWS and already on Pulumi (or willing to be), this is a huge productivity win. For teams on GCP or Azure, it's a non-starter — see "who shouldn't use this" below.
3. A proper host abstraction. The GraniteReactHost API is the bit that made me nod. It exposes lifecycle hooks, lets you pass initial props from native to JS, and gives you a clean place to bridge native modules. This is the API the official React Native docs should have shipped years ago.
4. End-to-end tests as a first-class concern. The README calls this out and it shows in the package layout — every package has its own e2e tests. For an enterprise framework, this is the difference between "it works on my machine" and "it works in production."
5. Changesets + Yarn 4 monorepo. Under the hood it's a well-organized monorepo with Nx, Yarn 4, Changesets, and proper CI. If you've ever tried to maintain a multi-package RN setup, you know how rare this is.
Who should use this
If you're a startup building your first mobile app — go use Expo. Seriously. Granite is not for you. The infrastructure complexity, the AWS lock-in, the microservice mental model — all of it is overhead you don't need yet.
If you're a mid-size company with a single RN codebase and a small team — same answer. Stay simple.
If you're an enterprise with a large native app, multiple teams shipping RN features independently, and you need to deploy those features without going through App Store review every time — Granite is exactly what you've been hand-rolling. And if you've been hand-rolling it badly, this will save you a year of pain.
If you're on AWS and already use Pulumi, the on-ramp is even smoother. If you're not on Pulumi, you're going to learn it, but the framework makes that investment pay off.
If you're on GCP or Azure, hard pass for now. The framework is AWS-first by design, not AWS-compatible.
Concerns and limitations
Let me be honest about what worries me.
The version number. 0.1.34. This is an alpha-grade API surface. The 16 open issues are a hint that things are still moving under your feet. If you adopt this now, you are accepting that you'll be migrating as the framework hits 1.0. The pace of breaking changes implied by the changelog suggests this is real.
The AWS lock-in is real. There's no abstraction layer between Granite and AWS. You use S3, CloudFront, and Pulumi. If your company is multi-cloud or GCP-native, this is a problem. The framework could in theory support other backends, but right now it's all AWS-shaped.
The ecosystem is small. 475 stars is healthy for a niche framework but it's not a community. If you get stuck, you're posting issues and hoping the Toss team responds. There's no Stack Overflow corpus, no third-party tutorials, no Discord with 10,000 users. Documentation lives at granite.run and it's clearly a work in progress.
Language and docs skew Korean. The README has a Korean translation, the contributors are Korean, and a lot of the practical guidance (blog posts, talks, examples) is going to be in Korean. If you're not in that ecosystem, you're going to be translating concepts from Korean-language sources more often than you'd like.
"Prebuilt frameworks (WIP)." The README literally says native build times are a work in progress. If you're shipping a brownfield app, native build times are your life. Until this lands, you're going to feel the pain.
Bundle size claims deserve skepticism. 200KB is the headline number but it's the bundle for a single screen, not the whole app. The total payload across all your screens could still be large. And 200KB is impressive but it's not magic — it's what you get when you aggressively code-split. If you don't architect your screens carefully, you'll end up with larger bundles than expected.
Verdict
Granite is a serious attempt at solving a real problem that most RN frameworks refuse to address: how do you run React Native at enterprise scale, inside a large native app, with independent deployment of features? Toss has built it because they needed it, and that origin story is the best kind of origin story for a framework.
It's too early to bet your company on. But it's not too early to evaluate seriously, prototype with, and pressure-test against your own architecture. If your team fits the target audience — large native app, AWS, Pulumi, multiple RN feature teams — you should be reading the source code, not just the README. The architectural decisions are sound and the maintainers are shipping.
For everyone else, bookmark it and check back when it hits 1.0.
Repo: github.com/toss/granite