Figuring out what library to use when starting a new React project is a struggle. There are a bunch of seemingly (hopefully) solid options out there mixed in with 20 different abandoned boilerplates with dependencies six months out of date.
However, while neither option is flat out better than the other, each is designed for solving different problems. This post highlights the strengths and weaknesses of each library and will equip you with the knowledge to make an informed decision in how to start your next React app.
But before we start the comparison, let's look at how each library advertises itself.
What is Next.js?
Built by Vercel, Next.js describes itself as: The React Framework for Production.
This means Next.js provides all the features you need to deploy a production-ready react application: server-side rendering (SSR), static site generation (SSG), code splitting, page routing, and more. All this while providing a first-in-class developer experience with zero configuration to get started.
Next.js is a "batteries included" framework that empowers developers to build server-side rendered websites using modern best-practices for building performant websites without needing to figure out scaling or infrastructure; they can just focus on their app.
What is create-react-app?
Built by the core maintainers of React, create-react-app (aka, CRA) describes itself as: an officially supported way to create single-page React applications.
With a single command, CRA gives you a complete (though purposefully minimal) client-side rendered React application without having to think about build configs, dependency management, or many other pain points of setting up a modern front-end app.
Because CRA is officially supported by the React team, you can trust CRA will continue to be updated to support whatever features React comes out with in the future.
Unlike Next.js, create-react-app is not a "framework": the goal of CRA is to quickly get you from 0 to 1 building a single-page react application. By getting out of your way, it also gives developers the flexibility to evolve their application as the needs of their project evolve.
Now that we have a baseline on the background for each library, let's dive in to the use-cases each is better suited for.
create-react-app is great for...
Experimenting with React
I love to tinker with code. I like experimenting and asking "what if..." about some (often dumb) idea I have.
But I'm also incredibly lazy.
If I can't start playing around immediately there's a good chance I will shrug my shoulders and think "oh well, maybe when I have more time" (spoiler alert: I never have more time).
This is why I love create-react-app support in codesandbox. By just visiting react.new, I instantly get a fully-featured React environment powered by create-react-app via codesandbox. It doesn't get easier than that.
If I'm feeling adventurous and want to go a step further, I can run a single command (
npx create-react-app) to get started and in seconds I have a single-page app to play around with.
While Next.js is just as ridiculously easy to get started (
npx create-next-app), I find CRA has better "tinkerability" than Next.js. This is because I've run into React libraries that don't jive well with being rendered server-side. Since everything in Next.js is server-side rendered by default, it's something you have to work around.
And like I said, if there's any friction whatsoever, I'll probably put the project aside. create-react-app is always there for me; able to take whatever I throw at it.
When it comes to programming, I'm a hands-on learner. I don't want to just read about a new library or technology. I want to put what I'm reading about into practice. While create-react-app wasn't around when I was first learning React, it's exactly the kind of tool I would've loved to have.
The minimal scope of CRA means I can focus just on React. I don't need to muck with build configs or boilerplate templates. I can just code.
Next.js offers this as well, but being a full-blown React framework means if I'm looking to learn React, I need to tease apart which parts are part of the framework and which parts are "just React".
Offline Applications & PWAs
Modern web apps are more often being compared to native apps. One feature users have come to expect of native apps is their ability to work offline. Users are starting to expect this of their web apps too. Progressive Web Apps (PWAs) are the web platform's answer to that expectation and enables web apps to continue working without an internet connection.
The create-react-app docs include a guide for making your CRA project an offline-first PWA. The gist is basically creating your CRA project with the provided PWA template (
npx create-react-app my-app --template cra-template-pwa). Running that command gives you a pre-configured service worker that you have full control over customizing.
While there are some third-party plugins for Next.js that provide PWA capabilities, they're not officially baked into the framework. By being community supported, there are no guarantees the plugin will continue to work between versions, or work for all use-cases of the framework.
While such plugins may work well for some projects, until Next.js provides a first-party solution for PWAs, I would favor going with create-react-app for offline applications.
Highly Dynamic Routing
create-react-app does not ship with a router. For some projects, this is a feature not a bug! CRA makes it easy to drop in any client-side routing solution like the ever-popular react-router. You can even roll your own if that's your jam.
Don't get me wrong, I love the Next.js router: drop a file into the
pages folder and voila, you have a new route. This works great for a lot of apps. Plus, it enables route-based code splitting for free.
That being said, a file-based router has limitations. For example, a cool feature of react-router is that routes are "just components". This means you can compose routes and share data between components dynamically just like any other React component. You can't do that as easily with Next.js routes.
If you find yourself wanting ultimate flexibility with your routing, create-react-app may be a better fit.
Next.js is great for...
Automatic Site Optimizations
Next.js provides implements a lot of modern web development best practices without having to think about it: Route-level code splitting, screen resolution-based image optimization, server-side rendering, static site generation. You get all of this for free or very little work just by using the framework.
For marketing sites, blogs, landing pages, and other websites that feature largely static content these features are all but mandatory to achieve top-tier performance. And without Next.js, you'll be spending way more time wiring this stuff up by hand.
If performance is highly important for your site, Next.js is a breath of fresh air for both developers and users: developers aren't fiddling with rendering static markup and client-side hydration, and users aren't waiting around waiting for their content to load.
Extending Build Configuration
While many Next.js projects can go their entire life without touching configuration, Next.js still graciously provides escape hatches for modifying your babel and webpack configurations.
create-react-app on the other hand locks down tight everything config related. The only options to get at your build config is to use a third party solution, or run
yarn eject: the nuclear option to completely opt out of everything "zero-config" create-react-app offers.
The upside is you get full access to really well documented config files. The downside is you have full access to your config files: from the point you eject you're on your own to manage your configuration. You're also unable to pull in any future improvements the team makes to create-react-app. It's truly a one-way-door that should not be taken lightly.
Serverless Backend APIs
While Next.js positions itself as a React framework, that doesn't mean it's focused just on solving front-end problems. Next's file system-based routing solution extends to API development too.
By dropping a file into the
api folder, you automatically get a new serverless endpoint you can use to make requests from the frontend for any server-based operations.
Should you use Next.js or create-react-app?
Directly comparisons of these two libraries can feel a bit like comparing apples and oranges. One is a full-blown React framework, the other is a zero-config minimal single-page application. However, these two separate paradigms can both be viable starting points depending on your use case.
It comes down to your use case and what the goals of your project are. To recap, here are my criteria for choosing creat-react-app or Next.js:
Use create-react-app if you want...
- to get started learning react
- to quickly experiment with something in react
- robust offline support
- highly dynamic routing
Use Next.js if you want...
- "convention over configuration"
- a "batteries included" react framework
- automatic code splitting
- to easily extend your build configuration
- simple, opinionated routing
- automatic image optimizations
- serverless backend API endpoints
Use either if you want...
- A great developer experience that includes TypeScript, eslint, css modules, and more with zero configuration
- Great, comprehensive documentation that clearly takes you from beginner to advanced concepts
- An active community that is happy to answer your questions