skip to content

What does StyleSheet.create do in React Native 0.87, and how does it differ from passing an inline style object?

level: juniorimportance: must knowfreq 64%

answer

  1. identity function with a dev freeze
  2. type checking is the main benefit
  3. no numeric IDs anymore
  4. inline literal: new object each render
  5. dynamic values stay inline

basics

~20 s

In React Native 0.87, StyleSheet.create returns the object it is given, freezing each style in development; its practical benefit is TypeScript checking. An inline style object works the same but is recreated on every render.

solid answer

~50 s

`StyleSheet.create` in React Native 0.87 is an **identity function**: it returns the same object you pass, and in development it freezes each named style so accidental mutation fails loudly. The docs name static type checking against native style properties as its main practical benefit. It does not register styles, return numeric IDs or send anything to native ahead of time - that description is from much older releases. An inline object such as `style={{ opacity: 0.5 }}` is resolved exactly the same way; the difference is that the literal is a **new object on every render**, which matters when a memoized child compares props, and that styles declared at module scope read better and are shared. Use `create` for static styles at module scope, and inline objects or computed entries for values derived from props, state or window size.

go deeper

for a junior

Recall that StyleSheet.create declares named style objects, and that inline objects work too but are recreated on every render.

for a middle

Explain that create is an identity function with a development freeze, correct the numeric-ID myth, and say when identity actually matters.

for a senior

Pick static module-scope styles for appearance and inline entries for dynamic values, and spot mutation bugs that only surface in release builds.

for a principal

Set a styling convention for the codebase that separates static styles from dynamic and themed values, and keep it grounded in measured render costs rather than folklore.

## What create does today The React Native 0.87 implementation of `StyleSheet.create` is short. It loops over the named styles and, **in development only**, calls `Object.freeze` on each one; then it returns the object it received. The docs describe it as "an identity function for creating styles" whose main practical benefit is **static type checking** against native style properties. That means: - `styles.card` is the very object you wrote, not an ID or a handle. - Nothing is sent to native code at creation time; styles travel with props when a component renders. - There is **no runtime validation** in `create`; a misspelt property is caught by TypeScript, not by `create`. ## A myth worth correcting Many interview answers still say `create` "sends styles over the bridge once and returns numeric IDs", so it is "faster than inline styles". Early React Native releases did register styles and hand back numbers. Current releases do not - the source even carries a TODO about call sites still typing the return value as a number. On the New Architecture, which is the only architecture since 0.82, there is no bridge to cross either. The honest performance story today is about **object identity**, not registration. ## create versus inline, side by side | | `StyleSheet.create` at module scope | Inline object literal | |---|---|---| | Object identity | the same object on every render | a new object on every render | | Type checking | checked against `ViewStyle`, `TextStyle`, `ImageStyle` | checked when passed to a typed `style` prop | | Mutation | frozen in development | freely mutable | | Dynamic values | not possible at module scope | natural - computed from props or state | | Readability | named, shared, out of the render body | local, visible where used | ## Why identity matters React Native compares props when it re-renders. For the core components, an equal-looking new object is diffed by value and generally produces no native update, so an inline `style` is not a correctness problem. It matters when a **memoized** component - a `React.memo` coupon row, for instance - receives `style` as a prop: a new literal each render defeats the shallow comparison and the row re-renders. Module-scope styles from `create` keep the same reference. That is the whole of the performance difference, and whether it matters depends on the component tree. ## The development freeze Because each named style is frozen in development, `styles.card.opacity = 0.5` inside a component throws a `TypeError` in strict-mode code (which module code is). In a **release build nothing is frozen**, so the same mutation would silently change the shared style for every coupon card on screen. The freeze exists to catch that class of bug early; the fix is to express the change as another array entry, never as a mutation. ## When to use which 1. **Static appearance** - padding, radius, typography, the disabled variant's colours: `StyleSheet.create` at module scope. 2. **Values from props, state or layout** - a width from `useWindowDimensions`, a progress bar's percentage, a colour chosen at runtime: an inline object or a small computed entry in the style array, such as `[styles.bar, { width: barWidth }]`. 3. **Theme-dependent colours** - kept separate from static layout styles; how themes reach components is its own topic. 4. **Hot paths with memoized children** - keep style props referentially stable, for example with module-scope styles or `StyleSheet.compose`. ## What create does not do - It does not **validate** values at runtime; a misspelt key or a wrong value type is caught by TypeScript, not by `create`. - It does not **deduplicate** or merge styles; two named styles with identical properties stay two objects. - It does not **copy**; the object you get back is the object you passed, so keep it at module scope rather than rebuilding it inside render. ## Why teams still standardise on create Even with no runtime magic, `StyleSheet.create` earns its place: it keeps render bodies short, gives each style a name that explains its purpose, lets editors autocomplete and type-check every property, and turns an accidental mutation into a development-time error.

  • Why can mutating a style from StyleSheet.create pass every development test but break a release build?
    Because `create` freezes each named style only in development. There, `styles.card.opacity = 0.5` throws a `TypeError` in strict-mode code, so a test that exercises it fails. If the mutation sits on a path tests never hit, the release build - where nothing is frozen - silently changes the shared object and every card using `styles.card` turns semi-transparent.
  • Is an inline style object slower for a plain View than a StyleSheet.create style?
    Not in any meaningful way for a core component in React Native 0.87. `create` returns plain objects and registers nothing, and the renderer diffs an equal-looking new object without sending a native update. The measurable cost appears when the style is a prop of a memoized component, where a new literal each render defeats its shallow prop comparison.

StyleSheet.create is a labelled spice rack rather than a spice grinder: it does not transform what you put in, it just gives every jar a name, checks the label, and seals the lid during development so nobody pours into the wrong jar.

saying these in an interview costs you the question

  • StyleSheet.create returns numeric IDs that are sent over the bridge once.
  • StyleSheet.create validates style properties at runtime in React Native 0.87.
  • Inline style objects cause a native view update on every render.
  • Styles from StyleSheet.create are frozen in release builds too.
  • Dynamic values from props must also go into StyleSheet.create at module scope.