Stop Using Create React App in 2026
How CRA Became the Trap It Is Today
Create React App was a genuine breakthrough when Facebook released it in 2016. At the time, setting up a production-ready React project required configuring Webpack, Babel, ESLint, and a development server from scratch. A senior developer doing this work correctly would spend a day. Developers newer to the ecosystem often got it wrong in ways that weren't obvious until production. CRA solved this with a zero-configuration scaffold that got you from npx create-react-app my-app to a running development server in two minutes.
The problem was the tradeoff CRA made to achieve this: it hid all configuration behind the react-scripts abstraction. You couldn't customize Webpack without "ejecting" — a one-way operation that dumped all the configuration files into your project and made you responsible for maintaining them. This was fine when CRA was the active, well-maintained option and the alternatives were worse. It became a trap when the CRA team stopped maintaining the abstraction.
The abandonment happened gradually. The maintainers were Facebook engineers who had other priorities; the community couldn't easily contribute because changes to react-scripts required careful consideration of compatibility across every user's hidden configuration. Issues accumulated. The build times that seemed acceptable in 2018 became embarrassing by 2021, when Vite demonstrated that dev server startup under a second was achievable. By 2022, the React team was quietly recommending Next.js and Vite in conversations while CRA lingered in the docs as the official starter.
When the React docs were rewritten in 2023 and CRA was removed from the recommendations entirely, it was the official acknowledgment of what the community had known for a year: Create React App was over.
The npm download count tells the story of a tool in long-term decline: from a peak of ~20 million weekly downloads to roughly 500K in 2026, almost all of which comes from existing CI pipelines and unmaintained tutorials rather than new project creation. Every team that starts a new React project in 2026 with CRA is making a choice that their future selves will regret — not because CRA doesn't work today, but because it won't be maintained tomorrow.
TL;DR
Create React App is dead. It was officially deprecated in 2023 and hasn't received a meaningful update since 2022. Installing it today means 1,200+ packages, Webpack 5 under the hood with 30-60 second build times, and no official support path forward. The React team removed it from their docs. Vite starts in 300ms, builds in under 5 seconds, and comes with first-class TypeScript support. There is no reason to use CRA in 2026.
Key Takeaways
- CRA is officially deprecated — removed from React's official docs in 2023
- 1,200+ transitive dependencies — massive attack surface, slow installs
- Webpack under the hood — 30-60 second builds; Vite builds in 2-5 seconds
- No update path — security vulnerabilities accumulate with no upstream fix
- Vite is the answer — 300ms dev start, 2-5s builds, identical React support
Why Vite Is the Correct Replacement for CRA
Vite isn't a better-configured Webpack. It's a different architecture that exploits a capability that modern browsers gained after Webpack was designed. Native ES modules in the browser mean that during development, the browser can import JavaScript files directly — the way you import modules in Node.js — without them being bundled first. Vite's dev server serves your source files directly as ES modules, transforming them on demand (with esbuild, which is written in Go and runs at near-native speed). The browser requests main.tsx, Vite transforms it, the browser requests each imported file, Vite transforms those. This happens incrementally, on demand, in milliseconds.
Hot module replacement works by the same logic. When you save a file in a Webpack project, Webpack must determine what changed, rebuild the affected chunk(s), and send the new bundle to the browser. This takes seconds even with good caching. When you save a file in a Vite project, Vite knows exactly which module changed, sends just that module to the browser, and the HMR runtime replaces just that module in the running application. The rest of the module graph is untouched. This is why Vite HMR is measured in milliseconds rather than seconds.
For production builds, Vite uses Rollup — a mature, optimized JavaScript bundler — which produces the highly optimized output that CRA's Webpack produced, without the development-mode overhead. The end result is a tool that's faster in development (dramatically so), comparable in production output quality, and vastly simpler to configure and maintain.
What Happened to Create React App
Timeline:
2016: Facebook releases Create React App
→ Solves "configuration hell" of setting up React + Webpack + Babel
→ Huge success — developers can start in 30 seconds
→ "The blessed way to start React projects"
2018-2020: CRA dominates
→ ~20M weekly downloads at peak
→ Hundreds of tutorials built around it
→ Every bootcamp, every intro course uses CRA
→ Problem: it's accumulating tech debt faster than it's being maintained
2021: Cracks start showing
→ Webpack 5 migration is painful
→ Cold start times: 30+ seconds for medium apps
→ Hot reload: 5-15 seconds per save
→ Other tools (Next.js, Vite) are dramatically faster
→ CRA maintainers are burned out, community contribution drops
2022: CRA development effectively stops
→ Last major release: v5.0.1 (March 2022)
→ Open issues pile up (1,000+)
→ Security vulnerabilities go unpatched
→ The React team starts quietly recommending alternatives
2023: Official deprecation
→ React docs rewritten — CRA removed from recommendations
→ React team announces CRA is in "maintenance mode" (deprecated)
→ Recommended alternatives: Vite, Next.js, Remix
→ npm download count begins multi-year decline
2025-2026: Decline is complete
→ Downloads: still ~500K/week (from legacy CI pipelines and tutorials)
→ But new project starts: near zero
→ Every CRA project is technical debt waiting to be migrated
The Numbers That Killed CRA
The numbers below tell the same story that developers experienced in practice. Cold start times, hot reload latency, install time, and bundle size — every metric moved dramatically against CRA as the rest of the ecosystem advanced and CRA stagnated. The fundamental issue was that Webpack's architecture had a performance ceiling that couldn't be overcome through configuration or optimization alone.
# Install time comparison (2026):
# Create React App:
npx create-react-app my-app
# → Downloads: 1,300+ packages
# → Install time: 45-90 seconds (cold cache)
# → node_modules size: ~350MB
# → dev start time: 20-35 seconds
# → Hot reload: 5-15 seconds
# → Production build: 60-120 seconds
# Vite (React template):
npm create vite@latest my-app -- --template react-ts
# → Downloads: ~23 packages
# → Install time: 3-8 seconds
# → node_modules size: ~40MB
# → dev start time: 300ms
# → Hot reload: <100ms (HMR, not full reload)
# → Production build: 2-5 seconds
# Numbers don't lie:
# CRA dev start: 30s vs Vite: 0.3s → Vite is 100x faster to start
# CRA build: 90s vs Vite: 3s → Vite is 30x faster to build
# CRA packages: 1,300 vs Vite: 23 → CRA has 57x more dependencies
# CRA node_modules: 350MB vs Vite: 40MB → CRA takes 9x more disk space
CRA's Core Problem: Webpack
CRA is Webpack all the way down.
Every config decision in CRA was made to abstract away Webpack.
But Webpack's fundamental architecture is blocking:
Webpack (used by CRA):
→ JavaScript-native bundler
→ Processes every file synchronously during module resolution
→ Must scan and process ALL imports before starting dev server
→ 30 second start = 30 seconds of Webpack scanning your 500-file app
→ Hot reload requires rebuilding the affected module graph
Vite (what replaced it):
→ Uses esbuild (Go binary) for dependency pre-bundling
→ Serves files via native ES modules during development
→ Only processes files when the browser actually requests them
→ 300ms start = "I'm ready, request files as you need them"
→ Hot reload replaces only the changed module (no rebuild needed)
The performance difference isn't optimizations.
It's a fundamentally different architecture.
Webpack can't be optimized to match Vite.
The design decisions are incompatible.
Choosing Your CRA Replacement
The replacement for CRA depends on what you need to build, and the React ecosystem in 2026 has clearer guidance than it did in 2022 when the major alternatives were still maturing. The decision is primarily between Vite (for SPAs and apps that don't need server-side rendering) and Next.js (for applications that need SSR, server components, or tight Vercel integration).
Vite is the correct choice when you're building a React SPA that runs entirely in the browser — a dashboard, a web app that authenticates against an external API, a tool that reads local files, or any other application where you control the deployment and don't need search engine indexing. Vite is what CRA should have evolved into: fast, zero-config, TypeScript-native, and framework-agnostic.
Next.js is the correct choice when you need server-side rendering for SEO, server components that run code server-side, file-based routing with automatic code splitting, API routes colocated with your frontend, or the deployment efficiency that comes from a framework purpose-built for Vercel. Next.js is a full-stack framework, not a replacement for a build tool — it does significantly more than Vite, which is both its strength and its reason for being a separate choice.
Astro deserves mention for content-heavy websites: documentation sites, marketing pages, blogs, and portfolios where most content is static but a few interactive components exist. Astro's "islands architecture" sends minimal JavaScript and renders everything that can be rendered statically at build time.
What to Use Instead
# Scenario 1: New React SPA (no SSR needed)
npm create vite@latest my-app -- --template react-ts
cd my-app && npm install && npm run dev
# → TypeScript, React Fast Refresh, Vite, ready in under 10 seconds total
# Scenario 2: Next.js app (SSR, file-based routing, API routes)
npx create-next-app@latest my-app
# → Prompts for TypeScript, ESLint, Tailwind, App Router
# → Best choice if you need: SSR, SEO, server components, API routes
# Scenario 3: Full-stack with meta-framework
# Remix
npx create-remix@latest my-app
# → Full-stack, server-centric, data loading patterns
# Tanstack Start
npm create @tanstack/router@latest
# → Type-safe routing, file-based, works with Vite
# Scenario 4: You actually want a static site
npm create astro@latest
# → Build fast static sites, use React for interactive islands
# Decision guide:
# SPA (client-rendered, no SSR) → Vite
# SSR, SEO, server components → Next.js
# Full-stack, form-heavy → Remix
# Static, content-heavy → Astro
# Using CRA → Migrate to Vite
The Migration Story: What Actually Changes
The Vite migration is smaller than most CRA developers expect when they start planning it. The code you've written — React components, custom hooks, business logic, API calls — doesn't change at all. Vite supports JSX and TypeScript natively, so no code transformation is required. The migration is entirely in the build infrastructure: the tool that compiles your code changes, not the code itself.
The three-to-five areas that typically require attention are environment variables (the prefix changes from REACT_APP_ to VITE_), absolute imports (which need a path alias configuration in vite.config.ts if you were using CRA's module name mapper), the index.html location (moves from public/ to the project root), the test runner (if you were using CRA's built-in Jest, you'll want to add Vitest), and the web server configuration for development proxying (moves from proxy in package.json to server.proxy in vite.config.ts).
After these structural changes, most CRA projects start and build correctly with Vite. The commonly cited "gotchas" — dynamic require(), global variables like process.env, Node.js polyfills — affect a minority of CRA projects and have well-documented solutions.
Migrating Existing CRA Projects to Vite
# Migration is surprisingly straightforward
# Step 1: Remove CRA
npm uninstall react-scripts
# Step 2: Install Vite
npm install --save-dev vite @vitejs/plugin-react
# Step 3: Create vite.config.ts
cat > vite.config.ts << 'EOF'
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'
export default defineConfig({
plugins: [react()],
server: {
port: 3000, // Match CRA's default port
},
})
EOF
# Step 4: Move index.html
# CRA: public/index.html
# Vite: index.html (root of project)
mv public/index.html .
# Add script tag to new index.html:
# <script type="module" src="/src/main.tsx"></script>
# Step 5: Update package.json scripts
{
"scripts": {
"start": "vite", // was: react-scripts start
"build": "vite build", // was: react-scripts build
"preview": "vite preview", // new: preview production build
"test": "vitest" // replace Jest with Vitest
}
}
# Step 6: Handle environment variables
# CRA: process.env.REACT_APP_*
# Vite: import.meta.env.VITE_*
# → Search and replace: REACT_APP_ → VITE_
# Step 7: Fix absolute imports
# Add to vite.config.ts:
resolve: {
alias: {
'@': '/src',
},
},
# That's the core migration. Most CRA apps migrate in 30-60 minutes.
# Common gotchas:
# → process.env → import.meta.env
# → REACT_APP_ prefix → VITE_ prefix
# → Jest config → Vitest config
# → CRA's built-in ESLint → add your own
The Ecosystem Moved On
Who still uses CRA?
→ Old tutorials on YouTube (pre-2023)
→ Bootcamp courses that haven't updated
→ Legacy enterprise projects from 2019-2022
→ Developers who haven't started a new project since 2022
Who the React ecosystem recommends:
React Docs (react.dev):
→ Next.js ← mentioned first
→ Remix
→ Gatsby (niche)
→ "Vite for SPAs" (effectively)
→ CRA: NOT LISTED
React community consensus (State of JS 2025):
→ Vite: 92% satisfaction rate
→ Next.js: 74% satisfaction
→ CRA: 32% satisfaction (mostly "meh, it used to work")
→ CRA usage intent: negative (more people leaving than joining)
The message is clear:
CRA solved a 2016 problem with 2016 tools.
Vite solved the same problem with 2021 tools.
The performance difference is 10-100x.
There is no reason to use CRA in 2026.
Security: Why CRA is Actively Dangerous in 2026
The security dimension of continuing to use CRA is separate from the performance and developer experience issues, and it's the most urgent reason to migrate now. CRA's last major release (v5.0.1) was March 2022. Security vulnerabilities discovered in CRA's 1,300+ transitive dependencies since then have no upstream fix. There will be no CRA v6.
Running npm audit on a fresh CRA install in 2026 returns dozens of moderate and high-severity vulnerabilities. Most of these are in deeply nested transitive dependencies — packages you never directly installed, packages you don't know exist in your project, packages that have known issues but no CRA patch to install. The npm audit fix command will repair some of them via dependency hoisting, but others require version bumps that CRA's locked dependency tree won't accommodate.
The standard enterprise response to this is to use npm audit --audit-level=high and accept low and moderate findings as unavoidable technical debt. This is a reasonable operational decision for a legacy app undergoing planned migration, but it's a genuinely bad security posture for a new application or one serving sensitive data. Every day you spend building on CRA is a day spent building on an unmaintained foundation.
The argument for CRA — "my existing tests and tooling all work" — doesn't survive contact with the security reality. The performance penalty was forgivable as long as CRA was maintained. The security debt is not forgivable when the solution (migrate to Vite) is documented, tested by millions of teams, and achievable in a day for most projects.
The State of CRA in Open Source
The open source dynamics around CRA's abandonment are instructive for how to evaluate the health of any project you depend on. CRA wasn't abandoned because it stopped working — it was abandoned because the maintainers lost interest and the project structure made community maintenance difficult. The abstracted react-scripts package meant that anyone wanting to contribute needed to understand the full, hidden build pipeline. Pull requests that improved one user's experience might break another's. The maintainability cost was too high for volunteer contributors.
This is a common failure mode for "zero-configuration" tools: the configuration lives somewhere, and when it needs to change, it's harder to change than if it were explicit. Vite's explicit vite.config.ts means that power users can understand and contribute to the project without reading internal implementation details. The plugin system means that community contributions can extend the tool without touching the core. These architectural choices are why Vite's GitHub repository has thousands of active contributors while CRA's repository has effectively zero.
The broader lesson: prefer tools with an explicit, composable configuration over ones that abstract everything away. Abstractions that you can't extend or customize are fine while they're maintained; when maintenance stops, they become constraints you can't remove without a rewrite.
If You're Stuck With CRA (Enterprise Reality)
# You have a 200,000 line CRA app and can't migrate right now.
# What do you do?
# 1. Pin your CRA version
{
"dependencies": {
"react-scripts": "5.0.1" // Last stable version, pin it
}
}
# 2. Override vulnerable transitive dependencies
{
"overrides": {
"semver": ">=7.5.2",
"nth-check": ">=2.0.1",
"postcss": ">=8.4.31"
}
}
# This patches CVEs without needing upstream fixes
# 3. Suppress npm audit noise (CRA will always fail audit)
# .npmrc
# legacy-peer-deps=true
# audit=false ← do NOT do this for security reasons
# Instead: npm audit --audit-level=critical
# Only fail on truly critical vulns, not the hundreds of low/moderate
# 4. Plan the migration
# Migrate one route at a time using module federation or separate Vite apps
# For very large apps: create new routes as Vite micro-frontends
# Run CRA and Vite apps side by side behind a reverse proxy
# 5. Schedule the migration
# CRA is dead weight. It's not a matter of if, but when.
# Every month you wait: more security debt, more friction, slower builds.
# Set a date. Migrate.
Compare Vite vs Webpack (the bundler under CRA) at PkgPulse.
See also: Turbopack vs Vite and React vs Vue, The Problem with JavaScript Framework Benchmarks.
See the live comparison
View vite vs. webpack on PkgPulse →