@craco/craco vs customize-cra vs react-app-rewired
Extending Create React App Configuration Without Ejecting
@craco/cracocustomize-crareact-app-rewiredSimilar Packages:

Extending Create React App Configuration Without Ejecting

@craco/craco, customize-cra, and react-app-rewired are utilities designed to override the locked Webpack and Babel configurations in Create React App (CRA) without triggering the irreversible eject command. react-app-rewired was the pioneer in this space, allowing config overrides via a script file. customize-cra is a companion library that provides functional helpers to make react-app-rewired overrides cleaner and safer. @craco/craco (Create React App Configuration Override) is a more modern alternative that offers a plugin ecosystem and a structured config file. Note that since Create React App is now archived and in maintenance mode, these tools are best suited for maintaining existing CRA applications rather than starting new greenfield projects.

Npm Package Weekly Downloads Trend

3 Years

Github Stars Ranking

Stat Detail

Package
Downloads
Stars
Size
Issues
Publish
License
@craco/craco278,2007,440140 kB483 years agoApache-2.0
customize-cra02,780-1156 years agoMIT
react-app-rewired09,87948.9 kB18-MIT

Extending Create React App: CRACO vs Rewired vs Customize-CRA

When Create React App (CRA) was the standard for bootstrapping React projects, developers quickly hit its limitations. The default Webpack configuration was hidden, and the only official way to change it was to eject β€” a one-way operation that copies all build config into your repo, making future CRA updates painful. To solve this, the community built tools to override the config without ejecting. Let's compare the three main players: @craco/craco, customize-cra, and react-app-rewired.

πŸ—οΈ Architecture: How They Hook Into CRA

The core difference lies in how they intercept the build process.

react-app-rewired replaces the react-scripts CLI commands.

  • You change your package.json scripts to use react-app-rewired instead of react-scripts.
  • It looks for a config-overrides.js file in your root directory.
  • This file exports a function that receives the Webpack config and returns a modified version.
// react-app-rewired: config-overrides.js
module.exports = function override(config, env) {
  // Directly mutate or return new config object
  config.resolve.alias['@'] = path.resolve(__dirname, 'src');
  return config;
};

customize-cra is not a standalone runner.

  • It works on top of react-app-rewired.
  • It provides functional helpers to avoid manual config mutation.
  • You still need react-app-rewired in your package.json scripts.
// customize-cra: Used inside config-overrides.js
const { override, addBabelPlugin } = require('customize-cra');

module.exports = override(
  addBabelPlugin('lodash'),
  (config) => {
    // Additional custom logic
    return config;
  }
);

@craco/craco replaces the scripts but uses a structured config file.

  • You change scripts to use craco (e.g., craco start).
  • It uses a craco.config.js file with a specific schema (webpack, babel, jest).
  • It supports a plugin system to share common configurations.
// @craco/craco: craco.config.js
module.exports = {
  webpack: {
    alias: {
      '@': path.resolve(__dirname, 'src'),
    },
  },
  babel: {
    plugins: ['lodash'],
  },
};

🧩 Plugin Ecosystem & Extensibility

Extending the build tool often requires more than just one-off config changes.

react-app-rewired has no official plugin system.

  • Developers share snippets of config-overrides.js code.
  • This leads to copy-pasting logic that might conflict or become outdated.
  • You are responsible for merging Webpack configs correctly.
// react-app-rewired: Manual merging required
const { merge } = require('webpack-merge');
module.exports = function override(config) {
  return merge(config, { /* custom config */ });
};

customize-cra offers functional plugins.

  • It exports helpers like addWebpackAlias, addBabelPreset, etc.
  • These reduce errors but are limited to what the library exposes.
  • Still relies on the react-app-rewired runtime.
// customize-cra: Functional helpers
const { addWebpackAlias } = require('customize-cra');
module.exports = override(
  addWebpackAlias({ '@': path.resolve(__dirname, 'src') })
);

@craco/craco has a dedicated plugin API.

  • You can install community plugins (e.g., craco-alias, craco-less).
  • Plugins hook into specific lifecycle stages of the config build.
  • This makes sharing and maintaining extensions much easier.
// @craco/craco: Plugin usage
module.exports = {
  plugins: [
    {
      plugin: require('craco-alias'),
      options: {
        source: 'tsconfig',
        baseUrl: '.',
        aliases: { '@': './src' },
      },
    },
  ],
};

⚠️ Security & Maintenance Status

This is the most critical factor for architectural decisions today.

react-app-rewired is in maintenance mode.

  • There have been security concerns regarding how config-overrides.js is loaded.
  • Updates are infrequent.
  • With CRA archived, the long-term future is uncertain.

customize-cra follows react-app-rewired status.

  • Since it depends on rewired, it inherits the same risks.
  • It is stable but not actively evolving.

@craco/craco is the most actively maintained.

  • The community rallied around CRACO when CRA updates slowed down.
  • It addresses some security concerns by having a stricter config schema.
  • It is the recommended path for existing CRA apps needing config changes.

πŸ› οΈ Real-World Scenarios

Scenario 1: Adding Path Aliases

You want to import files using @/components instead of ../../components.

  • βœ… Best choice: @craco/craco
  • Why? Built-in support or simple plugin (craco-alias). No manual Webpack merging.
// craco.config.js
module.exports = {
  webpack: {
    alias: { '@': path.resolve(__dirname, 'src') },
  },
};

Scenario 2: Using Decorators in Babel

You need to enable legacy decorators for a legacy codebase.

  • βœ… Best choice: customize-cra (if already on rewired) or @craco/craco.
  • Why? Both simplify Babel config injection compared to raw rewired.
// customize-cra
module.exports = override(
  addBabelPlugin(['@babel/plugin-proposal-decorators', { legacy: true }])
);

Scenario 3: Migrating Off CRA Eventually

You plan to move to Vite or Next.js in 6 months but need fixes now.

  • βœ… Best choice: @craco/craco
  • Why? Its config structure is closer to standard Webpack/Vite configs than config-overrides.js. Easier to extract later.
// craco.config.js
// This structure is easier to port to vite.config.js later
module.exports = {
  webpack: { configure: (config) => { /* ... */ } },
};

πŸ“Œ Summary Table

Feature@craco/cracocustomize-crareact-app-rewired
Standaloneβœ… Yes❌ Needs rewiredβœ… Yes
Config Filecraco.config.jsconfig-overrides.jsconfig-overrides.js
Plugin Systemβœ… Yes⚠️ Functional Helpers❌ No
Maintenance🟒 Active🟑 LowπŸ”΄ Minimal
Security🟒 Better Isolation🟑 Inherits RewiredπŸ”΄ Known Risks
CRA CompatibilityHighHighHigh

πŸ’‘ The Big Picture

Important Context: Create React App is officially archived. Meta is no longer recommending it for new projects.

@craco/craco is the pragmatic choice for teams stuck on CRA.

  • It extends the life of your current setup safely.
  • Use it to bridge the gap while you plan a migration to Vite, Remix, or Next.js.
  • Its plugin system saves engineering time on common tasks.

react-app-rewired and customize-cra are legacy tools.

  • They served a vital purpose in 2018–2021.
  • Today, they represent technical debt.
  • Only keep them if the cost of migrating to CRACO (or off CRA entirely) is too high right now.

Final Thought: Do not start new projects with these tools.

  • For new apps, choose a framework with exposed config (Vite, Next.js).
  • For existing CRA apps, use @craco/craco to manage config cleanly until you can migrate.
  • Treat all three as temporary solutions in the modern React ecosystem.

How to Choose: @craco/craco vs customize-cra vs react-app-rewired

  • @craco/craco:

    Choose @craco/craco for any new configuration work on existing CRA apps. It has an active plugin ecosystem, better TypeScript support, and does not require changing the package.json scripts as aggressively as rewired. It is the safest long-term bet for extending CRA before migrating to a different build tool.

  • customize-cra:

    Choose customize-cra only if you are already committed to react-app-rewired and want to clean up your override logic. It is not a standalone solution; it relies on react-app-rewired to function. It helps avoid manual Webpack config manipulation by providing tested helper functions.

  • react-app-rewired:

    Avoid react-app-rewired for new projects due to maintenance concerns and past security vulnerabilities related to how it loads config files. Only use it if you are maintaining a legacy codebase that already depends on it and migration to CRACO is too risky or costly.

README for @craco/craco

CRACO

Create React App Configuration Override, an easy and comprehensible configuration layer for create-react-app.

Find config docs, API docs, plugins, and example configs at craco.js.org!


npm status npm downloads npm license GitHub stars GitHub contributors PRs Welcome

Get all the benefits of Create React App and customization without using 'eject' by adding a single configuration (e.g. craco.config.js) file at the root of your application and customize your ESLint, Babel, PostCSS configurations and many more.

  1. Install the latest version of the package from npm as a dev dependency:

    npm i -D @craco/craco
    
  2. Create a CRACO configuration file in your project's root directory and configure:

      my-app
      β”œβ”€β”€ node_modules
    + β”œβ”€β”€ craco.config.js
      └── package.json
    
  3. Update the existing calls to react-scripts in the scripts section of your package.json to use the craco CLI:

    "scripts": {
    -  "start": "react-scripts start"
    +  "start": "craco start"
    -  "build": "react-scripts build"
    +  "build": "craco build"
    -  "test": "react-scripts test"
    +  "test": "craco test"
    }
    

Visit craco.js.org to learn more.