Create React App’s deprecation left a real gap for teams who want to start a new React project without immediately committing to a full framework like Next.js - sometimes you genuinely just need a client-rendered React app, no server rendering, no file-based routing, and reaching for a full framework adds complexity you don’t need. Here’s what we actually reach for instead, and when.
Why CRA’s approach stopped being the right default
CRA’s core problem wasn’t the tool itself so much as what it represented - a single, monolithic, hard-to-customize build configuration at a time when the ecosystem had moved toward faster, more flexible build tooling. Its build times were noticeably slower than modern alternatives, and customizing its webpack configuration meant “ejecting” into an unmaintainable, unmerge-able copy of its internal config - a real dead end for any project that needed genuine build customization down the line.
What we actually reach for now
- Vite, for genuinely client-rendered single-page applications - dramatically faster development server startup and hot module reload than CRA ever offered, with a build configuration that’s genuinely readable and customizable rather than hidden behind an ejection process. For dashboards, internal tools, and applications that don’t need server rendering or SEO, this is our default starting point today.
- Next.js, when you need server rendering, SEO, or a fuller-featured framework - for anything public-facing where search visibility and initial load performance matter, or where you know you’ll eventually need server-side data fetching and API routes, starting directly with Next.js avoids a later migration from a purely client-rendered setup.
What a genuinely good project setup actually needs, beyond the build tool choice
- TypeScript from the start, not bolted on later - retrofitting TypeScript onto an existing JavaScript codebase is real, avoidable work compared to starting with it configured correctly from day one.
- A real linting and formatting setup, enforced in CI, not just locally - consistency across a team compounds in value as a codebase and team grows, and it’s far cheaper to establish this from the start than to retrofit consistency onto an inconsistent codebase later.
- Testing infrastructure configured from day one, even if the initial test coverage is thin - the barrier to writing the first test is dramatically lower when the tooling already works than when someone has to set up a testing framework from scratch months into a project, at which point testing debt has usually already accumulated.
Where we push back on over-configuring a new project
Elaborate custom build configurations, unusual state management setups, or heavy tooling choices made before the project has any real requirements driving them add complexity that isn’t earning its cost yet. We start new projects with the sensible, well-supported defaults for the chosen tool (Vite or Next.js) and add complexity deliberately as genuine requirements emerge, rather than front-loading configuration decisions the project doesn’t need yet.
What we’d actually recommend
For a new client-rendered React project today, Vite with TypeScript, ESLint, and a testing framework configured from the start is our default. For anything needing server rendering or SEO, Next.js from the beginning avoids a costly later migration.
We set up every new project with this foundation as part of our React development work. Talk to us about what you’re building and we’ll recommend the right starting configuration.