# What Is the Eject Process in Create React App and What Are Its Implications?

> Understand the Create React App eject process. Expose hidden configurations and gain full control over your build tools. Learn the implications before you eject.

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

---

**The `eject` process in Create React App is a one-way operation that exposes all hidden build configurations by copying Webpack, Babel, and other tooling files from `react-scripts` into your project, making you responsible for future maintenance.**

The `facebook/create-react-app` repository provides a zero-configuration toolchain for React applications through the `react-scripts` package. While this abstraction simplifies development, the **eject process in Create React App** becomes necessary when you need to customize build tooling beyond the provided options. This irreversible operation, implemented in [`packages/react-scripts/scripts/eject.js`](https://github.com/facebook/create-react-app/blob/main/packages/react-scripts/scripts/eject.js), permanently transfers control of the build pipeline from the CRA maintainers to your development team.

## How the Eject Process Works in Create React App

When you execute `npm run eject` or `yarn eject`, the shell invokes `react-scripts eject`, which runs the Node.js script located at [`packages/react-scripts/scripts/eject.js`](https://github.com/facebook/create-react-app/blob/main/packages/react-scripts/scripts/eject.js). This script orchestrates a complex migration of configuration files and dependencies through several distinct phases.

### Pre-Flight Validation and User Confirmation

The eject script begins by verifying repository safety. It calls `getGitStatus` (lines 30-44 in [`eject.js`](https://github.com/facebook/create-react-app/blob/main/eject.js)) to check for uncommitted changes, aborting if the working directory is dirty. This prevents loss of work during the file migration. Next, the script prompts the user with a confirmation message (lines 65-70): *"Are you sure you want to eject? This action is permanent."* Only explicit confirmation allows the process to continue.

### File Extraction and Content Sanitization

Once confirmed, the script constructs a list of folders and files to copy (lines 112-129), including the `config/` and `scripts/` directories. It verifies target paths using `verifyAbsent` (lines 100-110) to prevent accidental overwrites of existing files. During the copy phase, the script sanitizes file contents by stripping `// @remove-on-eject` comment blocks and completely skipping files marked with `// @remove-file-on-eject` (lines 52-69). This ensures that internal CRA utilities do not leak into the ejected project.

### Dependency Migration and Script Rewriting

The most significant structural change occurs in [`package.json`](https://github.com/facebook/create-react-app/blob/main/package.json). The script removes `react-scripts` from dependencies and explicitly adds every package that `react-scripts` previously managed internally, including `webpack`, `babel-loader`, `eslint`, and `jest` (lines 77-108). It then rewrites the npm scripts to point to the local copies: `"start": "node scripts/start.js"` instead of `"react-scripts start"`. Finally, it generates Jest configuration via `createJestConfig`, adds Babel and ESLint presets if missing, handles TypeScript declaration merging, and reinstalls node modules using `npm install` or `yarn install`.

## Configuration Files Exposed by the Eject Process

After ejecting, your repository contains the entire build toolchain that was previously hidden inside `node_modules/react-scripts`. These files reside in two primary directories created during the process.

### Webpack and Babel Configurations

The `config/` directory contains [`webpack.config.js`](https://github.com/facebook/create-react-app/blob/main/webpack.config.js), which defines the complete module bundling pipeline, including loaders for JavaScript, CSS, and assets. You also gain [`webpackDevServer.config.js`](https://github.com/facebook/create-react-app/blob/main/webpackDevServer.config.js) for development server customization. Babel configuration appears as [`babel.config.js`](https://github.com/facebook/create-react-app/blob/main/babel.config.js) or within [`package.json`](https://github.com/facebook/create-react-app/blob/main/package.json) under the `babel` key, exposing the `react-app` preset and allowing you to add custom plugins or modify transpilation targets.

### ESLint and Jest Setup

Linting configuration moves from an internal dependency to an explicit `eslintConfig` entry in [`package.json`](https://github.com/facebook/create-react-app/blob/main/package.json) or a dedicated `.eslintrc` file, extending `react-app` and `react-app/jest` rules. Testing configuration becomes visible through the `jest` field in [`package.json`](https://github.com/facebook/create-react-app/blob/main/package.json), generated by the `createJestConfig` utility during ejection. This exposes transform patterns, module name mappers, and setup files that were previously abstracted.

### Build and Test Scripts

The `scripts/` directory contains the Node.js executables that power your npm commands. [`scripts/start.js`](https://github.com/facebook/create-react-app/blob/main/scripts/start.js) launches the development server, [`scripts/build.js`](https://github.com/facebook/create-react-app/blob/main/scripts/build.js) handles production optimization, and [`scripts/test.js`](https://github.com/facebook/create-react-app/blob/main/scripts/test.js) runs the Jest test suite. These files import from the `config/` directory and from `react-dev-utils`, giving you direct control over environment variables, build output, and development server behavior.

## Implications of Ejecting from Create React App

Ejecting fundamentally changes the maintenance contract of your React application. While it unlocks customization capabilities, it introduces specific long-term responsibilities that teams must evaluate before executing the command.

**Irreversibility** remains the most critical characteristic. Once the script completes and `react-scripts` is removed from [`package.json`](https://github.com/facebook/create-react-app/blob/main/package.json), you cannot "uneject" to return to the managed configuration. Reversal requires creating a new CRA project and manually migrating source code, or restoring from version control.

**Maintenance Burden** shifts dramatically to your team. Future updates to Webpack, Babel, ESLint, or Jest must be applied manually by editing [`package.json`](https://github.com/facebook/create-react-app/blob/main/package.json) version numbers and resolving breaking changes. You lose the convenience of upgrading a single `react-scripts` dependency to receive tested, compatible toolchain updates.

**Repository Growth** occurs as the `config/` and `scripts/` directories add approximately 2,000 lines of configuration code to your repository. This increases repository size, commit noise, and cognitive load for developers navigating the codebase.

**Full Control** represents the primary motivation for ejecting. You gain the ability to modify any aspect of the build pipeline, such as adding custom Webpack loaders, adjusting Babel presets, or configuring ESLint rules beyond the `react-app` defaults.

**Dependency Visibility** exposes all transitive dependencies that `react-scripts` previously managed internally. While this aids security auditing by making every package explicit in [`package.json`](https://github.com/facebook/create-react-app/blob/main/package.json), it also increases the surface area for `npm audit` warnings and requires manual curation of dependency trees.

## Alternatives to Ejecting in Create React App

Before committing to the irreversible eject process, consider **forking `react-scripts`** as a maintainable alternative. This approach involves creating a custom npm package based on the official `react-scripts` source code, publishing it to a private registry, and referencing it in your [`package.json`](https://github.com/facebook/create-react-app/blob/main/package.json) instead of the official version.

Forking preserves the abstraction layer while allowing organization-wide customizations. You can modify Webpack configurations, add Babel plugins, or adjust Jest settings in your fork, then propagate updates to multiple projects by bumping a single dependency version. The official documentation in [`docusaurus/docs/alternatives-to-ejecting.md`](https://github.com/facebook/create-react-app/blob/main/docusaurus/docs/alternatives-to-ejecting.md) provides detailed guidance on implementing this strategy.

For simple customizations, explore **CRACO** (Create React App Configuration Override) or **react-app-rewired** before ejecting. These community tools allow limited Webpack and Babel modifications without ejecting, though they add dependency risk and may lag behind official CRA updates.

## Practical Example: Running the Eject Command

To initiate the eject process, execute the following command in your project root:

```bash
npm run eject

```

The script located at [`packages/react-scripts/scripts/eject.js`](https://github.com/facebook/create-react-app/blob/main/packages/react-scripts/scripts/eject.js) immediately prompts for confirmation: *"Are you sure you want to eject? This action is permanent."* After confirmation, the script performs the migration.

**Before eject**, your [`package.json`](https://github.com/facebook/create-react-app/blob/main/package.json) contains minimal configuration:

```json
{
  "scripts": {
    "start": "react-scripts start",
    "build": "react-scripts build",
    "test": "react-scripts test",
    "eject": "react-scripts eject"
  },
  "devDependencies": {
    "react-scripts": "5.0.1"
  }
}

```

**After eject**, the same file expands significantly:

```json
{
  "scripts": {
    "start": "node scripts/start.js",
    "build": "node scripts/build.js",
    "test": "node scripts/test.js"
  },
  "dependencies": {
    "webpack": "5.x.x",
    "babel-loader": "8.x.x",
    "jest": "27.x.x",
    "eslint": "8.x.x"
  },
  "babel": {
    "presets": ["react-app"]
  },
  "eslintConfig": {
    "extends": "react-app"
  }
}

```

The `config/` and `scripts/` directories now exist in your repository, containing the full Webpack, Babel, and Jest configurations previously hidden inside `node_modules/react-scripts`.

## Summary

- The **eject process in Create React App** is an irreversible operation defined in [`packages/react-scripts/scripts/eject.js`](https://github.com/facebook/create-react-app/blob/main/packages/react-scripts/scripts/eject.js) that exposes all build configurations by copying them from `react-scripts` into your project.
- Running `npm run eject` triggers a multi-phase migration including Git cleanliness checks, file sanitization with `// @remove-on-eject` directives, and dependency promotion from transitive to explicit.
- After ejecting, you assume full responsibility for maintaining Webpack, Babel, ESLint, and Jest configurations, losing the ability to upgrade `react-scripts` for automatic toolchain updates.
- Alternatives such as **forking `react-scripts`** or using configuration override tools provide customization without sacrificing the zero-configuration benefits.

## Frequently Asked Questions

### Can you undo the Create React App eject process?

No, the eject process is permanently irreversible. Once [`packages/react-scripts/scripts/eject.js`](https://github.com/facebook/create-react-app/blob/main/packages/react-scripts/scripts/eject.js) completes and removes the `react-scripts` dependency, you cannot "uneject" to restore the managed configuration. Reversal requires creating a new CRA project and manually migrating your source code, or restoring from a Git commit prior to the ejection.

### What files are created when you eject from Create React App?

Ejecting creates two primary directories in your repository root: `config/` and `scripts/`. The `config/` directory contains [`webpack.config.js`](https://github.com/facebook/create-react-app/blob/main/webpack.config.js), [`webpackDevServer.config.js`](https://github.com/facebook/create-react-app/blob/main/webpackDevServer.config.js), and environment-specific settings, while `scripts/` contains [`start.js`](https://github.com/facebook/create-react-app/blob/main/start.js), [`build.js`](https://github.com/facebook/create-react-app/blob/main/build.js), and [`test.js`](https://github.com/facebook/create-react-app/blob/main/test.js). These files are copied from `node_modules/react-scripts` and stripped of `// @remove-on-eject` blocks during the migration.

### Why does Create React App require a clean Git status before ejecting?

The eject script enforces Git cleanliness to prevent data loss during the complex file migration. In [`packages/react-scripts/scripts/eject.js`](https://github.com/facebook/create-react-app/blob/main/packages/react-scripts/scripts/eject.js), the `getGitStatus` function (lines 30-44) checks for uncommitted changes and aborts if the working tree is dirty. This safety measure ensures you can revert the operation via Git if the eject process encounters errors or produces unexpected results.

### What are the alternatives to ejecting from Create React App?

Instead of ejecting, you can fork `react-scripts` to create a custom build toolchain while maintaining the abstraction layer, as documented in [`docusaurus/docs/alternatives-to-ejecting.md`](https://github.com/facebook/create-react-app/blob/main/docusaurus/docs/alternatives-to-ejecting.md). Community tools like **CRACO** (Create React App Configuration Override) or **react-app-rewired** allow limited Webpack and Babel modifications without ejecting, though they introduce additional dependencies that may lag behind official CRA updates.