Blog

Styles Got 66% Faster in React Native

June 20, 2026 7 min read

How my merged React Native PR made StyleSheet flattenStyle up to 66% faster for nested style arrays.

Styles Got 66% Faster in React Native
React NativeStyleSheetflattenStylePerformanceOpen Source

Yes, 66% faster.

Not "every screen in your app renders 66% faster" faster. If that happened, I would become impossible to talk to.

Also yes, I know this sounds funny in 2026.

We are in the era where AI news moves every five minutes. Claude Fable 5 launched and then got suspended a few days later. People are arguing about AGI-ish models, agents, whole apps being generated, and whatever the next insane benchmark is.

And I am here excited about React Native style flattening.

Fair.

But I still love this kind of work. Maybe it is not an "invention" in the dramatic movie-trailer sense, but making a shared framework path cheaper is still a real contribution. A lot of apps sit on top of these tiny internal paths. When one of them gets simpler and faster, that is still worth being happy about.

This one is about a very specific shared React Native path: flattening nested style arrays. The benchmark shows that path got a lot cheaper, and because style flattening is used in many places, that is still worth caring about.

It started from a very normal React Native thing: styles.

Every React Native developer has written something like this:

<View style={[styles.container, isActive && styles.active]} />

Nothing special. Just daily life.

Then you build reusable components, pass styles through props, merge internal styles with external styles, and suddenly your style prop is not just an array anymore. It can become an array inside another array, sometimes more than one level deep.

Basically:

You start with a clean style array.

Three components later, it looks like someone packed a suitcase by sitting on it.

I contributed a performance improvement to react/react-native, merged as PR #57203. It improves how React Native handles nested style arrays in flattenStyle.

GitHub timeline showing the flattenStyle performance pull request merged into React Native
The small purple label that made my week.

The behavior stays the same. The difference is that React Native avoids creating extra intermediate objects while flattening nested arrays.

Why flattenStyle matters

At first, flattenStyle can sound like a small helper.

You may think it only matters when someone manually calls StyleSheet.flatten.

But React Native also uses this path internally. So it can show up in places like:

  • Text
  • Image
  • ImageBackground
  • TextInput
  • TouchableOpacity
  • ScrollView
  • Animated.ScrollView
  • animated props
  • Fabric public instances
  • developer tooling like the element inspector and React DevTools style resolving

So if a nested style array reaches these paths, improving flattenStyle means React Native does less work.

Important note: this does not mean every screen in every app becomes 66% faster.

Would be nice. I would print the benchmark and frame it.

The improvement is specifically for nested style-array flattening. Still, this is a shared path, and shared paths are exactly where small internal improvements can matter.

How nested styles happen

Here is a simple example:

<View
  style={[
    styles.container,
    [styles.spacing, isActive && styles.active],
    props.style,
  ]}
/>

This kind of thing can happen naturally in design-system components.

One component adds base styles. Another adds spacing. Another passes props.style. Maybe one of those values is already an array.

Nobody wakes up and says, "Today I will create nested style arrays."

It just happens.

Then React Native has to normalize it into one object.

That is the job of flattenStyle.

The old approach

Before the change, nested style arrays were flattened recursively.

That sounds fine, and it worked correctly.

The problem was that nested arrays could create temporary flattened objects. Then React Native had to merge those temporary objects into the final result.

The simplified version looked like this:

const flattened = flattenStyle(style[i]);
if (flattened != null) {
  for (const key in flattened) {
    result[key] = flattened[key];
  }
}

So for nested arrays, React Native could do extra allocation and then extra copying.

Same result, more work.

It is like printing a document, scanning it, and then emailing the scan to yourself.

Technically it works.

Emotionally, no.

The change

The new implementation walks nested arrays directly into one result object.

Instead of flattening a nested array into a temporary object and then copying that object again, the recursive step writes into the same target result.

The important behavior still stays the same:

  • object styles still work
  • falsy values are still ignored
  • nested arrays still work
  • later styles still override earlier styles

That last one matters a lot.

Style order is part of the React Native API. This should still work exactly as developers expect:

<View style={[styles.base, styles.override]} />

If both styles define the same key, styles.override must win.

Performance is nice, but not if it quietly changes styling behavior. That would be the worst kind of "optimization".

A quick example

Take this style structure:

[
  {color: "red", margin: 4},
  [
    {color: "blue"},
    [{padding: 8}],
  ],
]

The final result should be:

{
  color: "blue",
  margin: 4,
  padding: 8,
}

The old implementation could create temporary objects while resolving the nested arrays.

The new implementation reaches the same result while writing into one object.

Same output.

Less work.

That is the whole point.

Benchmark results

I made a small benchmark project outside the React Native repo so I could compare the old and new implementations in isolation:

tarikfp/rn-style-flatten-benchmark

These were the results from the PR:

ScenarioBeforeAfterChange
nested single style array294.79 ms98.73 ms66.5% faster
nested merged style array278.54 ms122.06 ms56.2% faster

The numbers are below 1 second, so milliseconds are easier to read here.

Again, this benchmark measures flattenStyle work for nested style arrays. It does not claim a full app render is 66% faster.

That distinction matters.

Benchmarks are useful, but only when they are honest about what they measure.

Validation

The contribution included focused unit coverage for flattenStyle.

The tests cover the behavior that should not change:

  • object styles
  • falsy entries
  • nested style arrays
  • override order

The benchmark app also had its own checks:

yarn test
yarn lint
yarn workspace style-flatten-benchmark-app tsc --noEmit
yarn bench:compare

And the React Native test command was:

yarn test packages/react-native/Libraries/StyleSheet/__tests__/flattenStyle-test.js --runInBand

The benchmark app was also built and installed on the iOS simulator.

Final thoughts

This is the kind of change I like in framework code.

Developers do not need to learn a new API. They do not need to rewrite components. They do not need to add some magic prop and hope for the best.

React Native just does less work for a case that already exists in real apps.

No behavior change.

No migration.

No drama.

Just fewer temporary objects in a shared path.

Sometimes that is the whole win.