> ## Documentation Index
> Fetch the complete documentation index at: https://mintlify.com/preactjs/preact/llms.txt
> Use this file to discover all available pages before exploring further.

# Migrating from React to Preact

> Step-by-step guide to migrate your React application to Preact

## Overview

Migrating from React to Preact with the compat layer is straightforward and can often be done without changing any application code. This guide walks you through the process.

<Note>
  Most React applications can be migrated to Preact by simply configuring bundler aliases and updating dependencies.
</Note>

## Migration Process

<Steps>
  <Step title="Install Preact">
    Remove React dependencies and install Preact:

    ```bash theme={null}
    npm uninstall react react-dom
    npm install preact
    ```

    Or keep React as a peer dependency if you're migrating a library:

    ```bash theme={null}
    npm install preact --save-dev
    ```
  </Step>

  <Step title="Update package.json">
    Update your `package.json` to reference Preact:

    ```json package.json theme={null}
    {
      "dependencies": {
        "preact": "^10.19.0"
      },
      "devDependencies": {
        // Your build tools...
      }
    }
    ```

    <Note>
      If you're using TypeScript, you may also want to install `@types/react` and `@types/react-dom` as dev dependencies for better IDE support.
    </Note>
  </Step>

  <Step title="Configure Bundler Aliases">
    Configure your bundler to alias React imports to Preact. Choose your bundler:

    ### Webpack

    ```javascript webpack.config.js theme={null}
    module.exports = {
      //...other config
      resolve: {
        alias: {
          'react': 'preact/compat',
          'react-dom/test-utils': 'preact/test-utils',
          'react-dom': 'preact/compat',
          'react/jsx-runtime': 'preact/jsx-runtime'
        }
      }
    };
    ```

    ### Vite

    ```javascript vite.config.js theme={null}
    import { defineConfig } from 'vite';
    import preact from '@preact/preset-vite';

    export default defineConfig({
      plugins: [preact()],
      // OR manually configure aliases:
      resolve: {
        alias: {
          'react': 'preact/compat',
          'react-dom/test-utils': 'preact/test-utils',
          'react-dom': 'preact/compat',
          'react/jsx-runtime': 'preact/jsx-runtime'
        }
      }
    });
    ```

    <Note>
      The `@preact/preset-vite` plugin automatically configures aliases and optimizations for Preact.
    </Note>

    ### Rollup

    ```javascript rollup.config.js theme={null}
    import alias from '@rollup/plugin-alias';
    import resolve from '@rollup/plugin-node-resolve';

    export default {
      plugins: [
        alias({
          entries: [
            { find: 'react', replacement: 'preact/compat' },
            { find: 'react-dom/test-utils', replacement: 'preact/test-utils' },
            { find: 'react-dom', replacement: 'preact/compat' },
            { find: 'react/jsx-runtime', replacement: 'preact/jsx-runtime' }
          ]
        }),
        resolve()
      ]
    };
    ```

    ### Parcel

    Add to your `package.json`:

    ```json package.json theme={null}
    {
      "alias": {
        "react": "preact/compat",
        "react-dom/test-utils": "preact/test-utils",
        "react-dom": "preact/compat",
        "react/jsx-runtime": "preact/jsx-runtime"
      }
    }
    ```

    ### esbuild

    ```javascript build.js theme={null}
    import { build } from 'esbuild';

    build({
      entryPoints: ['src/index.js'],
      bundle: true,
      outfile: 'dist/bundle.js',
      alias: {
        'react': 'preact/compat',
        'react-dom': 'preact/compat',
        'react/jsx-runtime': 'preact/jsx-runtime'
      }
    });
    ```
  </Step>

  <Step title="Update TypeScript Configuration (if applicable)">
    If you're using TypeScript, update your `tsconfig.json`:

    ```json tsconfig.json theme={null}
    {
      "compilerOptions": {
        "jsx": "react-jsx",
        "jsxImportSource": "preact",
        "paths": {
          "react": ["./node_modules/preact/compat/"],
          "react-dom": ["./node_modules/preact/compat/"],
          "react/jsx-runtime": ["./node_modules/preact/jsx-runtime"]
        }
      }
    }
    ```

    <Warning>
      The `paths` configuration helps TypeScript resolve the aliased imports correctly but doesn't perform the actual aliasing. Your bundler configuration is still required.
    </Warning>
  </Step>

  <Step title="Update Entry Point">
    If you're using React 18's `createRoot` API, no changes are needed. If you're using the legacy `ReactDOM.render`, you can either:

    **Option 1: Keep using the compat render function**

    ```jsx index.jsx theme={null}
    import { render } from 'react-dom';
    import App from './App';

    // This works with preact/compat
    render(<App />, document.getElementById('root'));
    ```

    **Option 2: Switch to React 18 API (recommended)**

    ```jsx index.jsx theme={null}
    import { createRoot } from 'react-dom/client';
    import App from './App';

    const root = createRoot(document.getElementById('root'));
    root.render(<App />);
    ```

    **Option 3: Use Preact's render directly**

    ```jsx index.jsx theme={null}
    import { render } from 'preact';
    import App from './App';

    render(<App />, document.getElementById('root'));
    ```
  </Step>

  <Step title="Test Your Application">
    Build and run your application to ensure everything works:

    ```bash theme={null}
    npm run build
    npm run dev
    ```

    Run your test suite:

    ```bash theme={null}
    npm test
    ```

    <Note>
      Check your bundle size! You should see a significant reduction compared to React.
    </Note>
  </Step>

  <Step title="Fix Compatibility Issues (if any)">
    While most code works without changes, you may need to address:

    * Libraries that check for specific React internals
    * Code using deprecated lifecycle methods (though these are supported via [compat/src/render.js:49](https://github.com/preactjs/preact/blob/main/compat/src/render.js:49))
    * Custom synthetic event handling
    * PropTypes validation (consider removing in production)

    See the [Differences](/compat/differences) page for details on specific edge cases.
  </Step>
</Steps>

## Migrating Common Patterns

### Class Components

Class components work without changes. The compat layer ensures full compatibility:

```jsx theme={null}
import { Component, PureComponent } from 'react';

// Both work exactly as in React
class MyComponent extends Component {
  render() {
    return <div>{this.props.children}</div>;
  }
}

class OptimizedComponent extends PureComponent {
  render() {
    return <div>{this.props.value}</div>;
  }
}
```

<Note>
  The `PureComponent` implementation in [compat/src/PureComponent.js:14](https://github.com/preactjs/preact/blob/main/compat/src/PureComponent.js:14) performs shallow prop and state comparison just like React.
</Note>

### Hooks

All React hooks are supported:

```jsx theme={null}
import { 
  useState, 
  useEffect, 
  useContext,
  useMemo,
  useCallback,
  useRef,
  useTransition,
  useDeferredValue
} from 'react';

function MyComponent() {
  const [state, setState] = useState(0);
  const [isPending, startTransition] = useTransition();
  
  // All hooks work as expected
  useEffect(() => {
    console.log('Mounted');
  }, []);
  
  return <div>{state}</div>;
}
```

### Context API

```jsx theme={null}
import { createContext, useContext } from 'react';

const ThemeContext = createContext('light');

function ThemedButton() {
  const theme = useContext(ThemeContext);
  return <button className={theme}>Click me</button>;
}

function App() {
  return (
    <ThemeContext.Provider value="dark">
      <ThemedButton />
    </ThemeContext.Provider>
  );
}
```

### Refs and forwardRef

Refs work identically to React. The `forwardRef` implementation in [compat/src/forwardRef.js:12](https://github.com/preactjs/preact/blob/main/compat/src/forwardRef.js:12) ensures full compatibility:

```jsx theme={null}
import { forwardRef, useRef, useImperativeHandle } from 'react';

const FancyInput = forwardRef((props, ref) => {
  const inputRef = useRef();
  
  useImperativeHandle(ref, () => ({
    focus: () => inputRef.current.focus()
  }));
  
  return <input ref={inputRef} {...props} />;
});
```

### Memo and Lazy

```jsx theme={null}
import { memo, lazy, Suspense } from 'react';

// Memoized component
const ExpensiveComponent = memo(({ data }) => {
  return <div>{/* expensive render */}</div>;
});

// Lazy-loaded component
const LazyComponent = lazy(() => import('./LazyComponent'));

function App() {
  return (
    <Suspense fallback={<div>Loading...</div>}>
      <LazyComponent />
    </Suspense>
  );
}
```

### Portals

Portals are fully supported via [compat/src/portals.js:70](https://github.com/preactjs/preact/blob/main/compat/src/portals.js:70):

```jsx theme={null}
import { createPortal } from 'react-dom';

function Modal({ children }) {
  return createPortal(
    children,
    document.getElementById('modal-root')
  );
}
```

## Handling Third-Party Libraries

### Most Libraries Work Automatically

Popular libraries that work out of the box:

* React Router
* Redux / Redux Toolkit
* React Query / TanStack Query
* Zustand
* React Hook Form
* Formik
* Styled Components
* Emotion
* Material-UI (MUI)
* Chakra UI
* Ant Design

### Libraries That May Need Adjustments

Some libraries may require configuration:

```javascript theme={null}
// Example: Configure a library to work with Preact
import { options } from 'preact';

// Some libraries check for React DevTools
if (typeof window !== 'undefined') {
  window.React = require('preact/compat');
}
```

## Optimizing After Migration

### Remove Compat for Core Code

Once migrated, consider importing from `preact` directly in your own code for smaller bundles:

```jsx theme={null}
// Instead of:
import { useState } from 'react';

// Use:
import { useState } from 'preact/hooks';
import { render } from 'preact';
```

### Configure Aliases for Specific Libraries Only

You can be selective about what uses the compat layer:

```javascript webpack.config.js theme={null}
module.exports = {
  resolve: {
    alias: {
      // Only alias for node_modules
      'react$': 'preact/compat',
      'react-dom$': 'preact/compat'
    }
  }
};
```

## Troubleshooting

<AccordionGroup>
  <Accordion title="Build errors about React not found">
    Ensure your bundler aliases are configured correctly and that you've installed preact:

    ```bash theme={null}
    npm install preact
    ```

    Double-check that your bundler configuration is being loaded.
  </Accordion>

  <Accordion title="TypeScript errors about React types">
    Install React types as dev dependencies:

    ```bash theme={null}
    npm install --save-dev @types/react @types/react-dom
    ```

    Update your `tsconfig.json` with the `paths` configuration shown in Step 4.
  </Accordion>

  <Accordion title="Third-party library doesn't work">
    Some libraries perform deep checks on React internals. Options:

    1. Check if there's a Preact-specific version of the library
    2. Report the issue to the library maintainers
    3. Look for alternative libraries
    4. Implement a compatibility shim
  </Accordion>

  <Accordion title="Tests are failing">
    Update your test configuration to use the same aliases:

    ```javascript jest.config.js theme={null}
    module.exports = {
      moduleNameMapper: {
        '^react$': 'preact/compat',
        '^react-dom$': 'preact/compat',
        '^react-dom/test-utils$': 'preact/test-utils',
        '^react/jsx-runtime$': 'preact/jsx-runtime'
      }
    };
    ```
  </Accordion>
</AccordionGroup>

## Next Steps

<CardGroup cols={2}>
  <Card title="Learn the Differences" icon="code-compare" href="/compat/differences">
    Understand key differences between React and Preact
  </Card>

  <Card title="Compat Overview" icon="book" href="/compat/overview">
    Review all supported React features
  </Card>
</CardGroup>
