How to Configure Create‑React‑App to Use a Specific Older React Version

You can configure Create React App to use a specific older React version by modifying the dependency specifiers in your project's package.json file and reinstalling dependencies, as CRA's build pipeline reads the React version directly from your project's declared dependencies rather than enforcing its own.

Create React App (CRA) provides a zero‑configuration build wrapper around react-scripts, but developers often need to configure create-react-app to use a specific older react version for legacy browser support or migration testing. According to the facebook/react source code, the framework determines which React version to bundle solely from the dependencies listed in your project's package.json, while the canonical version definitions in the monorepo are maintained in ReactVersions.js.

How CRA Handles React Versioning

CRA is essentially a thin scaffold generator that creates a package.json based on templates provided by the react-scripts package. The actual build logic does not enforce a specific React version; it simply bundles whatever version your package.json declares. In the React monorepo, the single source of truth for published versions is ReactVersions.js, which defines the current stable version (e.g., ReactVersion = '19.3.0') and maps all packages to that release. When you generate a new CRA project, the template copies default dependency ranges like "react": "^18.x" into your local package.json, but you are free to override these before or after installation.

The fixtures/owner-stacks/package.json file within the React repository demonstrates this pattern in practice, explicitly pinning an experimental React version to test specific features. This confirms that CRA projects can safely target any semantically compatible React release by adjusting their own manifest files.

Method 1: Downgrade an Existing CRA Project

The fastest way to target an older version is to generate the project normally, then reinstall specific versions. This ensures that react and react-dom remain synchronized, which is critical because mismatched versions cause runtime errors.

Run the following commands in your terminal:


# Scaffold a new project

npx create-react-app my-legacy-app
cd my-legacy-app

# Install the specific older version (e.g., 16.8.6)

npm install [email protected] [email protected]

After execution, your package.json will reflect the pinned versions:

{
  "dependencies": {
    "react": "16.8.6",
    "react-dom": "16.8.6",
    "react-scripts": "5.0.1"
  }
}

Method 2: Pre‑configure package.json Before Installation

To avoid downloading the latest React version entirely, you can edit the package.json immediately after running npx create-react-app but before running npm install. Alternatively, if you are using a custom template or manually extracting the CRA template, specify the versions directly in the dependencies object.

Edit the generated package.json to pin your desired versions:

{
  "name": "my-legacy-app",
  "version": "0.1.0",
  "private": true,
  "dependencies": {
    "react": "16.8.6",
    "react-dom": "16.8.6",
    "react-scripts": "5.0.1"
  },
  "scripts": {
    "start": "react-scripts start",
    "build": "react-scripts build",
    "test": "react-scripts test",
    "eject": "react-scripts eject"
  }
}

Then run npm install or yarn to fetch the specified legacy versions.

Method 3: Use a Custom Template with Older Dependencies

Some community‑maintained templates ship with older React dependencies already pinned. You can point CRA at a specific tagged version of a template to scaffold a project that uses a legacy React release by default.

npx create-react-app my-app --template [email protected]

In this example, the 1.0.0 tag of cra-template bundles React 16.8.x. The generated package.json will already contain the older versions, requiring no further manual changes.

Method 4: Enforce Versions with Yarn Resolutions

If you use Yarn and need to guarantee that every sub‑dependency resolves to a specific React version—preventing any transitive dependency from pulling in a newer release—add a resolutions field to your package.json.

{
  "resolutions": {
    "react": "16.8.6",
    "react-dom": "16.8.6"
  }
}

Run yarn install to apply the resolutions. Yarn will rewrite the lockfile to ensure all packages use the specified versions, effectively forcing the entire dependency tree to comply with your legacy requirement.

Key Files in the React Repository

Understanding how the React team manages versions helps clarify why CRA permits these downgrades. The following files from the facebook/react repository illustrate the versioning architecture:

  • ReactVersions.js: The central authority defining the current stable React version (e.g., 19.3.0) and mapping all published packages to that version.
  • packages/react/package.json: The manifest for the published react package; its version field is derived from ReactVersions.js.
  • fixtures/owner-stacks/package.json: A fixture demonstrating how to pin an experimental React version, serving as a concrete example of how CRA‑style projects can override default versions.
  • react-scripts (external): While maintained in a separate repository, this package contains the CRA template package.json used during scaffolding. It does not enforce React versions, only providing default suggestions.

Summary

  • CRA does not lock React versions: The react-scripts build pipeline reads React directly from your project's package.json dependencies.
  • Modify package.json to downgrade: Change the version specifiers for react and react-dom to your target version (e.g., 16.8.6) and run npm install.
  • Keep packages synchronized: Always ensure react and react-dom share the same version number to avoid runtime errors.
  • Use Yarn resolutions for strict control: Add a resolutions field to force all sub‑dependencies to use your specified legacy version.

Frequently Asked Questions

Can I use Create React App with React 16?

Yes. CRA's build scripts are compatible with React 16 and newer. Simply install the specific 16.x versions of react and react-dom in your project, and react-scripts will bundle them without requiring any configuration changes or ejecting.

Do I need to eject from CRA to change React versions?

No. Ejecting is unnecessary for version downgrades. Because react-scripts treats React as a standard peer dependency, you only need to modify your package.json dependencies and reinstall. Ejecting should only be considered if you need to modify the underlying Webpack configuration for other reasons.

How do I verify which React version my CRA app is actually running?

Check the version at runtime by opening your browser's developer console and typing React.version. Alternatively, inspect your package-lock.json or yarn.lock file to confirm the resolved version of the react package matches your package.json specifier.

Will downgrading React break my existing CRA code?

Potentially. If your application uses features introduced in newer React versions (such as React 18's concurrent rendering hooks or automatic batching), those features will fail or behave differently when running on an older React 16 or 17 build. You must ensure your application code is compatible with the target legacy version.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →