Create React App: Starting React Projects With No Build Configuration
If you’ve started a React app from scratch recently, you know the routine: before writing a single component you’re picking a bundler, wiring Babel presets into it, adding a linter, getting a dev server to rebuild on save, and then working out a separate production build. Last Friday, July 22, Dan Abramov published Create Apps with No Configuration on the official React blog, and it goes straight at that problem. The post acknowledges that people were losing days to project setup when they only wanted to learn React. Its answer is Create React App, an officially supported tool for starting single page React apps with a modern build setup and nothing to configure.
The changelog lists 0.1.0 on July 22 as the initial public release, and it’s still the only release, so everything below describes that version.
A few commands and you’re running
You install the tool globally once. The README asks for Node 4 or newer and recommends Node 6 with npm 3 for faster installs and better disk usage. Then it’s this:
npm install -g create-react-app
create-react-app my-app
cd my-app/
npm start
That opens the app at http://localhost:3000. The README at 0.1.0 also makes a point I like: the tool doesn’t assume a Node backend. Node is only needed for the build tools, so what you ship is static files.
The generated folder is small. You get package.json, index.html, favicon.ico, a README, and a src folder with App.js, App.css, index.js, index.css and logo.svg. There are no config files anywhere. The guide that ships inside the new project says three of those files must keep their exact names for the build to work: index.html is the page template, favicon.ico is the browser tab icon, and src/index.js is the JavaScript entry point. It also says webpack only processes files inside src, so your JavaScript and CSS have to live there. Everything else can be renamed or deleted.
One dependency doing the heavy lifting
Open the generated package.json and you’ll find react and react-dom under dependencies and exactly one devDependency, react-scripts, pinned to 0.1.0. The three scripts, start, build and eject, each just call react-scripts.
The global command barely does anything, and that’s on purpose. A comment at the top of its source says its only job is to set up the project and forward everything else to the local copy, because a globally installed tool is hard to get people to upgrade. When you run it, it makes the folder and a bare package.json, runs npm install for react-scripts with –save-dev and –save-exact, and hands off to an init script inside react-scripts. That script writes the three scripts into package.json, copies the template files into your folder, and runs a second npm install to fetch React.
Everything else lives inside react-scripts. Its package.json at 0.1.0 pulls in webpack 1.13.1 and webpack-dev-server, Babel 6 with the es2015, es2016 and react presets, ESLint 3, Autoprefixer through PostCSS, and a stack of loaders and plugins. According to the README, that gets you React, JSX and ES6 support, language extras beyond ES6 like the object spread operator, a dev server that lints for common errors, CSS and image imports straight from JavaScript, autoprefixed CSS, and a build script that bundles JS, CSS and images for production with sourcemaps. Class properties are switched on in the Babel setup too.
The blog post promises the team will keep Babel, ESLint and webpack on stable versions that work together, so updating a single dependency updates all of them. Because react-scripts is saved with an exact version, that update happens when you choose to bump it, not quietly on the next install.
What npm start and npm run build give you
npm start runs the development server on port 3000 and opens your browser. The page reloads when you edit, and build errors and lint warnings show up right in the terminal. The blog post says the console output is tuned to be minimal, and that the ESLint setup is only a small subset of rules that often lead to bugs, so it isn’t going to nag you about style. CSS you import from a component is reloaded on the fly in development, but components themselves aren’t hot reloaded, which the README lists as a limitation.
npm run build writes a production bundle to a build folder. React is bundled in production mode, the output is minified, and filenames include hashes so they’re safe to cache for a long time. All the CSS you imported ends up concatenated into one minified file. One thing to check before you deploy: the production webpack config sets the public path to the site root, and a TODO comment right next to it notes that won’t work for something like GitHub Pages. At this version, plan on serving the app from the root of a domain.
What it deliberately leaves out
The README says the feature set is intentionally limited. There are no configuration files and no command line options. Its Limitations section says server rendering, testing, some experimental syntax extensions such as decorators, CSS Modules, Less or Sass, and hot reloading of components aren’t currently supported. Yes, testing: there’s no test runner and no test script in 0.1.0. The blog post calls this an intentional limitation and admits it might not work for everybody.
The reasoning is that it’s hard to provide a cohesive experience and easy updates across a set of tools when users can tweak anything. The README leaves the door open for some missing features, but only if they’re stable, useful to most React apps, don’t conflict with existing tools, and don’t add configuration.
Ejecting, and why there’s no way back
For when the defaults stop fitting, there’s npm run eject. The blog post says the team first saw the idea in another project called Enclave. At 0.1.0, the eject script first asks if you’re sure and warns that the action is permanent. It checks that none of the files it’s about to write already exist, and stops if any do. Then it copies the development and production configs for Babel and webpack, the ESLint config, and two Flow stub files into a new config folder, and copies start.js, build.js and a small AppleScript (used to reuse an open Chrome tab on a Mac) into a new scripts folder. It removes react-scripts from your devDependencies and adds its 30 dependencies in its place, points start and build at node ./scripts/start.js and node ./scripts/build.js, deletes the eject script, and runs npm install.
The README puts it bluntly: this is a one-way operation, and once you eject you can’t go back. The single dependency that made upgrades easy is gone, the configuration is now your code, and there’s no command to hand it back to react-scripts. The blog post describes ejecting as forking their configuration and going your own way. npm start and npm run build keep working, but they run the copied scripts, and per the README you’re on your own. Later react-scripts improvements won’t reach your project unless you port them yourself.
The flip side is what the blog post calls no lock in. If you’re experienced with build tooling, it suggests using Create React App as a boilerplate generator: create the app, eject, and fine tune everything. The team expects plenty of people to eject early on and plans to make the defaults more compelling as it learns why.
When it fits and when to roll your own
My advice: if you’re learning React, prototyping, or starting a new single page app that talks to an API and deploys as static files, use it and don’t eject. The README says the curated feature set is suitable for small and middle deployments and that you shouldn’t feel obligated to eject. Not owning a webpack config is a real saving. One build dependency isn’t a small dependency tree, though. There are still dozens of packages under react-scripts; you just aren’t the one keeping them compatible.
I’d reach for my own configuration, or eject on day one, if the project needs anything on that unsupported list. The same goes for an app that has to live under a subpath, given that public path setting. If you’re adding React to an existing site that already has a build, this probably isn’t the tool either. The README notes that React has historically been easy to adopt gradually and says plainly that you don’t have to use this.
If you do eject, treat it like any other big change and give it its own commit in version control. The tool can’t undo it, but your repository can.
The takeaway
Create React App picks sensible defaults, hides them behind a single dependency, tells you exactly what it won’t do, and gives you an exit when you need more. For getting from nothing to a running React app, that’s the right trade. The blog post calls the whole thing an experiment and 0.1.0 is only a few days old, so read the Limitations section before you commit a real project to it.