Optimization Coverage
What React Native Boost can optimize today, what it skips, and why.
React Native Boost is conservative by design. If it cannot prove an optimization is safe, it skips it. While this means it'll often skip optimizations that would be safe in practice, it also means that you can trust that optimizations that do happen are safe and won't cause behavioral changes or other bugs.
At a Glance
| Component | Optimized when... | Common bailout reasons |
|---|---|---|
Text | Imported from react-native, no blacklisted props, primitive children, safe ancestor chain | contains blacklisted props, has Text ancestor, has unresolved ancestor and dangerous optimization is disabled, contains non-primitive children, is a direct child of expo-router Link with asChild |
View | Imported from react-native, safe ancestor chain, no spread that may carry a translated prop | has a spread that may carry a translated prop, has both a dynamic id and a nativeID (ambiguous precedence), has Text ancestor, has unresolved ancestor and dangerous optimization is disabled |
Image | Opted in with optimizations.image: true, imported from react-native, native platform known, supported source/style props, safe ancestor chain | target platform is unknown, has a Unistyles style and there is no lean Image host to route to, has an unresolved style source that may be a Unistyles style, contains unsupported Image props, has a spread that may carry Image wrapper props, has Text ancestor, has unresolved ancestor and dangerous optimization is disabled |
Global Bailouts
These skip optimization before component-specific checks:
- File path matches
ignores - Line is marked with
@boost-ignore
No log for ignored files
Files skipped via ignores are filtered before optimizer checks, so you will not see per-component skip logs for
those files.
Overriding Bailouts
Use @boost-force to force optimization on a component that would otherwise be skipped. This bypasses all bailout checks except the react-native import check. See the Decorators page for details.
Text Coverage
Text is optimized when all checks pass.
Text blacklisted props
If any of these are present, the Text node is skipped:
- Interaction/responder props (
onPress,onLongPress,onResponder*,pressRetentionOffset,suppressHighlighting, etc.) selectionColoraria-hidden
id is renamed to nativeID at build time (id wins when both are present). Text bails only if id/nativeID arrive via a spread, or a dynamic id appears alongside a nativeID.
Text structure checks
- Children must be provably primitive (resolve to a
stringornumber). Anything that could be a React element (nested elements, function calls, unresolved identifiers) bails ascontains non-primitive children.
Text ancestor safety checks
Like View, Text optimization depends on ancestor classification:
safe: optimizetext: skip (has Text ancestor) — aTextnested in anotherTextrenders as the inlineNativeVirtualTexthost (RCTVirtualText), notNativeText(RCTText), so optimizing it would emit the wrong host.unknown: skip by default
Set dangerouslyOptimizeTextWithUnknownAncestors: true to optimize unknown ancestors too.
Dangerous Mode
Enabling dangerous mode can introduce regressions if an unresolved ancestor renders a Text wrapper. A concrete
example is expo-router's Link, which wraps its children in a <Text> by default — so a Text under a Link
must render as NativeVirtualText, and optimizing it would be wrong.
A Text used as a direct child of expo-router Link with asChild is always skipped
(is a direct child of expo-router Link with asChild), even under the dangerous flag, because Link makes that child
pressable.
import { Link } from 'expo-router';
import { Text } from 'react-native';
<Link asChild>
<Text>Open profile</Text>
</Link>;View Coverage
View and Text share the same ancestor safety checks. The View wrapper translates a few ergonomic props into
native equivalents; Boost reproduces each translation at build time (or via a small runtime helper for dynamic values),
so these props no longer force a bailout.
View translated props
aria-*→accessibility*(aria-label,aria-labelledby,aria-live,aria-hidden, and the state/value groups)tabIndex→focusableid→nativeID(idwins when both are present)
Everything else — including accessible, accessibilityLabel, and a lone accessibilityState/accessibilityValue —
is passed through unchanged.
View prop bailouts
- A spread that may carry one of the translated props, since Boost cannot reach inside it to translate.
- A dynamic
idalongside anativeID(their runtime precedence cannot be resolved statically).
Ancestor safety checks
View optimization depends on ancestor classification:
safe: optimizetext: skip (has Text ancestor)unknown: skip by default
Set dangerouslyOptimizeViewWithUnknownAncestors: true to optimize unknown ancestors too.
Dangerous Mode
Enabling dangerous mode can increase optimization coverage, but it can also introduce regressions if unresolved ancestors render Text wrappers.
Image Coverage
Image optimization is opt-in for now because it uses deprecated React Native deep imports, which may print deprecation warnings. See Configure the Babel Plugin.
The optimizer rewrites supported Image elements when the target platform is known (ios or android) and the
source/style/accessibility props can be reproduced safely.
In Unistyles mode, an Image is skipped when its style is (or may be) a Unistyles style.
Spread Props: Resolvable vs Unresolvable
Unresolvable spread props are treated as unsafe and cause bailouts.
// Usually optimizable (resolvable object literal)
<Text {...{ selectable: true }}>Hello</Text>
// Usually skipped (cannot be statically resolved)
<Text {...props}>Hello</Text>Same rule applies to View.