Claude Code for React Native New Architecture: JSI, Fabric, and TurboModules — Claude Skills 360 Blog
Blog / Mobile / Claude Code for React Native New Architecture: JSI, Fabric, and TurboModules
Mobile

Claude Code for React Native New Architecture: JSI, Fabric, and TurboModules

Published: January 28, 2027
Read time: 9 min read
By: Claude Skills 360

React Native’s New Architecture replaces the asynchronous bridge with JSI — a C++ layer that lets JavaScript call native code synchronously, without serialization overhead. TurboModules are JSI-based native modules with TypeScript spec files that Codegen compiles to type-safe C++ interfaces. Fabric is the new renderer that supports concurrent React features like useTransition and startTransition. Bridgeless mode eliminates the legacy bridge entirely. React Native 0.74+ enables the New Architecture by default. Reanimated 3 runs animations entirely on the UI thread via worklets, eliminating frame drops from bridge latency. Claude Code generates TurboModule specs, Fabric component specs, Codegen configurations, Reanimated 3 animated components, and the native module wiring for production React Native New Architecture apps.

CLAUDE.md for React Native New Architecture

## React Native New Architecture Stack
- Version: react-native >= 0.74 (New Arch enabled by default)
- Bridgeless: enabled in RN 0.74+ — no legacy bridge, pure JSI
- TurboModules: define in NativeXxx.ts spec file, implement in C++/ObjC/Java
- Fabric: native components defined in NativeXxxComponent spec
- Codegen: runs during build — generates C++ headers from TypeScript specs
- Reanimated: >= 3.x for worklets, useAnimatedStyle, useSharedValue
- Animations: useSharedValue + useAnimatedStyle replaces Animated.Value

TurboModule Spec

// src/specs/NativeOrderModule.ts — TurboModule TypeScript spec
import type { TurboModule } from "react-native"
import { TurboModuleRegistry } from "react-native"

// Codegen generates native interface from this spec
export interface Spec extends TurboModule {
  // All methods must be explicitly typed
  getOrders(customerId: string): Promise<OrderInfo[]>
  createOrder(payload: CreateOrderPayload): Promise<string>  // Returns orderId
  cancelOrder(orderId: string): Promise<void>
  getStoredAuthToken(): string | null  // Synchronous — JSI enables this
}

interface OrderInfo {
  id: string
  status: string
  totalCents: number
  createdAt: string
}

interface CreateOrderPayload {
  customerId: string
  items: OrderItem[]
}

interface OrderItem {
  productId: string
  quantity: number
  priceCents: number
}

// Register with Codegen name
export default TurboModuleRegistry.getEnforcing<Spec>("OrderModule")
// ios/OrderModule/NativeOrderModule.mm — iOS TurboModule implementation
#import "NativeOrderModule.h"
#import <React/RCTUtils.h>

@implementation NativeOrderModule

RCT_EXPORT_MODULE()

- (std::shared_ptr<facebook::react::TurboModule>)getTurboModule:
    (const facebook::react::ObjCTurboModule::InitParams &)params {
  return std::make_shared<facebook::react::NativeOrderModuleSpecJSI>(params);
}

// Synchronous method — runs on JS thread via JSI
- (NSString *)getStoredAuthToken {
  return [[NSUserDefaults standardUserDefaults] stringForKey:@"auth_token"];
}

// Async methods use the provided resolve/reject
- (void)getOrders:(NSString *)customerId
          resolve:(RCTPromiseResolveBlock)resolve
           reject:(RCTPromiseRejectBlock)reject {
  dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
    // Network call off main thread
    NSURL *url = [NSURL URLWithString:[NSString stringWithFormat:@"https://api.example.com/orders?customer=%@", customerId]];
    NSData *data = [NSData dataWithContentsOfURL:url];

    if (!data) {
      reject(@"FETCH_ERROR", @"Failed to fetch orders", nil);
      return;
    }

    NSError *error = nil;
    NSArray *orders = [NSJSONSerialization JSONObjectWithData:data options:0 error:&error];

    if (error) {
      reject(@"PARSE_ERROR", error.localizedDescription, error);
    } else {
      resolve(orders);
    }
  });
}

@end

Usage in React Components

// src/hooks/useOrders.ts — consuming TurboModule
import NativeOrderModule from "../specs/NativeOrderModule"
import { useEffect, useState, useCallback } from "react"

export function useOrders(customerId: string) {
  const [orders, setOrders] = useState<OrderInfo[]>([])
  const [loading, setLoading] = useState(true)
  const [error, setError] = useState<Error | null>(null)

  const fetchOrders = useCallback(async () => {
    try {
      setLoading(true)
      // Direct JSI call — no bridge serialization
      const data = await NativeOrderModule.getOrders(customerId)
      setOrders(data)
    } catch (e) {
      setError(e as Error)
    } finally {
      setLoading(false)
    }
  }, [customerId])

  useEffect(() => {
    fetchOrders()
  }, [fetchOrders])

  // Synchronous call — works because of JSI
  const authToken = NativeOrderModule.getStoredAuthToken()

  const cancelOrder = useCallback(async (orderId: string) => {
    await NativeOrderModule.cancelOrder(orderId)
    setOrders(prev => prev.filter(o => o.id !== orderId))
  }, [])

  return { orders, loading, error, cancelOrder, authToken, refetch: fetchOrders }
}

Reanimated 3 Animations

// src/components/OrderCard.tsx — Reanimated 3 with New Arch
import React from "react"
import { Pressable, Text, View, StyleSheet } from "react-native"
import Animated, {
  useSharedValue,
  useAnimatedStyle,
  withSpring,
  withTiming,
  interpolateColor,
  runOnJS,
} from "react-native-reanimated"
import { Gesture, GestureDetector } from "react-native-gesture-handler"

interface OrderCardProps {
  order: OrderInfo
  onCancel: (id: string) => void
}

export function OrderCard({ order, onCancel }: OrderCardProps) {
  // Shared values — live on UI thread, no JS bridge
  const scale = useSharedValue(1)
  const translateX = useSharedValue(0)
  const opacity = useSharedValue(1)
  const isPressed = useSharedValue(false)

  // Animated styles — computed on UI thread
  const cardStyle = useAnimatedStyle(() => ({
    transform: [
      { scale: scale.value },
      { translateX: translateX.value },
    ],
    opacity: opacity.value,
    backgroundColor: interpolateColor(
      isPressed.value ? 1 : 0,
      [0, 1],
      ["#ffffff", "#f0f0f0"]
    ),
  }))

  // Gesture runs on UI thread via worklet
  const panGesture = Gesture.Pan()
    .onUpdate((event) => {
      "worklet"
      translateX.value = event.translationX
    })
    .onEnd((event) => {
      "worklet"
      if (event.translationX < -100) {
        // Swipe left to cancel
        translateX.value = withTiming(-500, { duration: 200 })
        opacity.value = withTiming(0, { duration: 200 }, (finished) => {
          if (finished) {
            runOnJS(onCancel)(order.id)
          }
        })
      } else {
        translateX.value = withSpring(0)
      }
    })

  const tapGesture = Gesture.Tap()
    .onBegin(() => {
      "worklet"
      isPressed.value = true
      scale.value = withSpring(0.97)
    })
    .onFinalize(() => {
      "worklet"
      isPressed.value = false
      scale.value = withSpring(1)
    })

  const composed = Gesture.Simultaneous(tapGesture, panGesture)

  return (
    <GestureDetector gesture={composed}>
      <Animated.View style={[styles.card, cardStyle]}>
        <Text style={styles.orderId}>#{order.id.slice(-6)}</Text>
        <Text style={styles.status}>{order.status}</Text>
        <Text style={styles.total}>
          ${(order.totalCents / 100).toFixed(2)}
        </Text>
        <Text style={styles.hint}>← Swipe to cancel</Text>
      </Animated.View>
    </GestureDetector>
  )
}

const styles = StyleSheet.create({
  card: {
    padding: 16,
    borderRadius: 12,
    marginVertical: 6,
    shadowColor: "#000",
    shadowOffset: { width: 0, height: 2 },
    shadowOpacity: 0.1,
    shadowRadius: 4,
    elevation: 3,
  },
  orderId: { fontFamily: "monospace", fontSize: 14 },
  status: { color: "#666", marginTop: 4 },
  total: { fontSize: 18, fontWeight: "bold", marginTop: 4 },
  hint: { fontSize: 11, color: "#999", marginTop: 4 },
})

Fabric Native Component

// src/specs/NativeOrderMapComponent.ts — Fabric component spec
import type { ViewProps } from "react-native"
import type { HostComponent } from "react-native"
import codegenNativeComponent from "react-native/Libraries/Utilities/codegenNativeComponent"

interface NativeProps extends ViewProps {
  // All props must be primitive or registered types
  orders: ReadonlyArray<Readonly<{
    id: string
    latitude: number
    longitude: number
    status: string
  }>>
  selectedOrderId?: string
  onOrderSelected?: (event: { nativeEvent: { orderId: string } }) => void
  showClusters?: boolean
}

export default codegenNativeComponent<NativeProps>(
  "OrderMapComponent"
) as HostComponent<NativeProps>

app.json New Architecture Config

{
  "name": "OrderApp",
  "expo": {
    "newArchEnabled": true,
    "android": {
      "gradle": {
        "newArchEnabled": true
      }
    },
    "ios": {
      "newArchEnabled": true
    }
  }
}
# ios/Podfile — enable New Architecture
require_relative '../node_modules/react-native/scripts/react_native_pods'

platform :ios, min_ios_version_supported

prepare_react_native_project!

target 'OrderApp' do
  config = use_native_modules!

  use_react_native!(
    :path => config[:reactNativePath],
    :app_path => "#{Pod::Config.instance.installation_root}/..",
    # Enables New Architecture (Fabric + TurboModules)
    :hermes_enabled => true,
  )
end

For the Expo managed workflow that abstracts TurboModule setup and provides a curated set of New Architecture-compatible modules, see the Expo guide for managed vs bare workflow decisions. For React Native performance profiling beyond animations — measuring JS thread and UI thread frame rates, identifying layout thrashing — the mobile performance guide covers Flashlight and Perfetto. The Claude Skills 360 bundle includes React Native New Architecture skill sets covering TurboModule specs, Reanimated 3, and Codegen configuration. Start with the free tier to try native module generation.

Put these ideas into practice

Claude Skills 360 gives you production-ready skills for everything in this article — and 2,350+ more. Start free or go all-in.

Back to Blog

Get 360 skills free