# React vs React Native Development Practices: Key Architectural Differences Explained

> Understand React vs React Native development practices. Discover key architectural differences in renderer, styling, and platform APIs impacting your web and mobile app workflows.

- Repository: [Meta/react](https://github.com/facebook/react)
- Tags: deep-dive
- Published: 2026-02-16

---

**React and React Native share identical component models and hook APIs, but diverge fundamentally in renderer architecture, styling implementation, and platform API access that dictate daily development workflows.**

When building applications with the React library from the `facebook/react` repository, developers must choose between targeting web browsers or native mobile platforms. While both environments leverage the same core reconciler and component lifecycle, the development practices differ significantly in how UI primitives are rendered, how styles are applied, and how platform-specific capabilities are accessed.

## Renderer Architecture: DOM vs Native UI Primitives

The most fundamental difference between React web and React Native development lies in the renderer implementation that translates component trees into actual platform UI.

### Web Rendering with react-dom

React for web utilizes the **react-dom** package to target the browser's DOM API. In [`packages/react-dom/README.md`](https://github.com/facebook/react/blob/main/packages/react-dom/README.md), the renderer exposes the modern `createRoot` API that mounts components to real DOM nodes using standard browser operations like `appendChild` and `removeChild`.

The renderer relies entirely on the browser's layout engine and CSS styling capabilities. When you render a `<div>` or `<span>`, React creates actual HTML elements that the browser parses, styles, and paints.

### Native Rendering with react-native-renderer

React Native employs a separate renderer located in [`packages/react-native-renderer/src/ReactNativeRenderer.js`](https://github.com/facebook/react/blob/main/packages/react-native-renderer/src/ReactNativeRenderer.js) (legacy) and [`packages/react-native-renderer/src/ReactFabric.js`](https://github.com/facebook/react/blob/main/packages/react-native-renderer/src/ReactFabric.js) (modern Fabric architecture). Instead of creating DOM nodes, this renderer constructs a **shadow tree** of native UI primitives.

The shadow tree is translated into actual native view hierarchies—iOS UIView or Android View objects—through the Fabric renderer or legacy bridge. This means when you write `<View>` or `<Text>` in React Native, you are not creating HTML elements but rather instructing the native platform to instantiate platform-specific UI components.

## Styling and Layout Practices

The divergence in renderer architecture forces distinct styling paradigms that fundamentally change how developers write and organize presentation logic.

### CSS and Class Names vs StyleSheet API

React web development uses standard CSS methodologies. Developers apply styles via `className` attributes referencing CSS files, CSS Modules, or CSS-in-JS libraries. The browser's full CSS cascade, media queries, and selector specificity govern the final appearance.

React Native replaces CSS with the JavaScript-only **StyleSheet API**. As noted in the repository's documentation referencing "Learn Once, Write Anywhere," all styling occurs through JavaScript objects that are compiled into native style dictionaries. There are no CSS files, no class names, and no cascade—only flat style objects applied directly to components via the `style` prop.

### Flexbox Implementation Differences

Both platforms use Flexbox for layout, but React Native's implementation differs from web Flexbox in several key ways:

- **Default direction**: React Native defaults to `column` rather than `row`
- **Unitless values**: Dimensions are specified as unitless numbers representing density-independent pixels (dp) rather than `px`, `em`, or `rem`
- **No percentage support**: Legacy React Native versions lack percentage-based dimensions (though modern versions support them with constraints)

## Platform-Specific APIs and Development Workflow

The host environment differences necessitate distinct tooling, debugging strategies, and platform API access patterns.

### Browser Environment vs Native Modules

React web applications run in the browser sandbox with direct access to Web APIs: `window`, `document`, `fetch`, `localStorage`, and DOM events. Third-party libraries typically wrap or polyfill these standard interfaces.

React Native provides access to native device capabilities through **native modules** exposed via the bridge or Fabric. APIs like `AsyncStorage`, `Geolocation`, and `CameraRoll` are not JavaScript implementations but rather thin wrappers that serialize calls to native code. This requires understanding platform-specific linking (or autolinking in modern versions) and sometimes writing native code in Objective-C, Swift, Java, or Kotlin.

### Build Tools and Debugging

The development workflow diverges significantly in tooling:

- **Bundling**: Web projects typically use Webpack, Vite, or Parcel. React Native uses **Metro**, a custom bundler designed for native platforms that handles platform-specific file extensions ([`.ios.js`](https://github.com/facebook/react/blob/main/.ios.js), [`.android.js`](https://github.com/facebook/react/blob/main/.android.js)) and asset scaling.
- **Debugging**: Both platforms support React DevTools, as documented in [`packages/react-devtools/README.md`](https://github.com/facebook/react/blob/main/packages/react-devtools/README.md). However, the backend implementation differs—web uses the DOM renderer backend while native requires the standalone DevTools UI or in-app inspector. For native, you must also use platform-specific debuggers (Xcode Instruments, Android Studio Profiler) to analyze native thread performance.
- **Testing**: Web applications use Jest with DOM testing utilities (`@testing-library/react`). React Native requires `@testing-library/react-native` because the underlying renderer is not a DOM implementation, as noted in [`packages/react-test-renderer/README.md`](https://github.com/facebook/react/blob/main/packages/react-test-renderer/README.md).

## Code Comparison: Counter Component

The following examples demonstrate how the same logical component differs in implementation between web and native platforms.

### React Web Implementation

Using the modern `createRoot` API from `packages/react-dom`:

```tsx
import { createRoot } from 'react-dom/client';
import { useState } from 'react';

function Counter() {
  const [count, setCount] = useState(0);
  return (
    <button onClick={() => setCount(c => c + 1)}>
      Clicked {count} times
    </button>
  );
}

const root = createRoot(document.getElementById('root')!);
root.render(<Counter />);

```

### React Native Implementation

Using native primitives and `AppRegistry` from the native renderer:

```tsx
import { AppRegistry, Text, TouchableOpacity, View } from 'react-native';
import { useState } from 'react';

function Counter() {
  const [count, setCount] = useState(0);
  return (
    <View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
      <TouchableOpacity onPress={() => setCount(c => c + 1)}>
        <Text>Clicked {count} times</Text>
      </TouchableOpacity>
    </View>
  );
}

AppRegistry.registerComponent('MyApp', () => Counter);

```

### Styling Syntax Comparison

Web development uses CSS Modules or standard CSS:

```tsx
/* Web – CSS module */
import styles from './Button.module.css';

<button className={styles.primary}>Web Button</button>

```

React Native uses the `StyleSheet` API with JavaScript objects:

```tsx
/* React Native – StyleSheet */
import { StyleSheet, Text, TouchableOpacity } from 'react-native';

const styles = StyleSheet.create({
  primary: { backgroundColor: '#0066ff', padding: 12, borderRadius: 4 },
});

<TouchableOpacity style={styles.primary}>
  <Text style={{ color: '#fff' }}>Native Button</Text>
</TouchableOpacity>

```

## Summary

- **Renderer architecture** determines the fundamental difference: React uses `react-dom` to manipulate browser DOM nodes, while React Native uses `react-native-renderer` (including [`ReactFabric.js`](https://github.com/facebook/react/blob/main/ReactFabric.js) for the modern architecture) to construct native platform view hierarchies via shadow trees.

- **Styling approaches** are incompatible between platforms: web relies on CSS cascade and class names, while React Native requires JavaScript-only `StyleSheet` objects with Flexbox layout and density-independent units.

- **Platform APIs** differ significantly: web applications access browser APIs like `window` and `localStorage`, while React Native bridges to native modules for device capabilities and requires platform-specific build tools like Metro and Xcode/Android Studio.

- **Development workflows** diverge in debugging and testing: both support React DevTools, but native development requires additional platform-specific profilers and `@testing-library/react-native` rather than DOM-based testing utilities.

## Frequently Asked Questions

### What is the main technical difference between React and React Native renderers?

The main technical difference lies in the host environment target. According to the `facebook/react` source code, React for web uses the `react-dom` package to mutate actual browser DOM nodes using standard web APIs like `appendChild`. In contrast, React Native uses the `react-native-renderer` package (specifically implementations in [`ReactNativeRenderer.js`](https://github.com/facebook/react/blob/main/ReactNativeRenderer.js) and [`ReactFabric.js`](https://github.com/facebook/react/blob/main/ReactFabric.js)) to create a shadow tree that is translated into platform-native view objects (iOS UIView or Android View) rather than HTML elements.

### Can I use CSS files in React Native development?

No, React Native does not support traditional CSS files or the CSS cascade. As implemented in the React Native architecture, styling must be done through JavaScript objects using the `StyleSheet` API. While the layout engine uses Flexbox algorithms similar to the web, styles are defined as JavaScript objects with camelCase properties (e.g., `backgroundColor` instead of `background-color`) and applied directly to components via the `style` prop, bypassing the browser's CSS parsing entirely.

### How does debugging differ between React web and React Native applications?

Both platforms support React DevTools, as documented in [`packages/react-devtools/README.md`](https://github.com/facebook/react/blob/main/packages/react-devtools/README.md), but the debugging workflow differs significantly. For React web applications, developers primarily use browser DevTools (Chrome DevTools, Firefox Developer Tools) to inspect the DOM, monitor network requests, and profile performance. For React Native, developers must use the standalone React DevTools UI or in-app inspector for the component tree, while native performance profiling requires platform-specific tools like Xcode Instruments for iOS or Android Studio Profiler for Android, since the app runs actual native code rather than JavaScript in a browser context.