Back to Basics: How to Set Up a React App From Scratch 2020

Building a React app from an empty directory using the latest Webpack and Babel.

Putra Aryotama
Oct 22, 2020 · 13 min read
Photo by Scott Blake on Unsplash

Nowadays, starting a React app is as simple as typing a line of command into the terminal, taking for granted what happens under the hood. We use create-react-app or other boilerplates to start the development process and dive straight into the actual React code.

However, it would be a great learning experience (especially for those who are beginners) to set up a react app from scratch on your own. It will cement your understanding of the bits and pieces that goes into a react application from scratch to deployment. As the saying goes, you learn stuff from breaking things apart and putting it all back together.

In this article I will show you how to set up a react app from an empty directory using the latest Webpack and Babel. On the way, I will explain the ‘parts’ needed to have a react app working. Hopefully, by the end, you will get the big picture and understand the concepts of building and serving a react application. These concepts and understanding may hopefully aid you elsewhere in web development process using other React, other JavaScript libraries, or even other languages!

This article is intended for those who have some basic understanding of JavaScript. It will make it easier going forward. Although, I expect total beginners in coding could follow along too. As always, you can use the mighty internet for reference of parts you still have trouble understanding. Meanwhile, I will try to explain each part as best as I can.

I recommend you to follow along and code on your own while observing this ‘tutorial’. Speaking from experience, coding on your own will help cement the concepts and understanding rather than just reading along.


First and foremost, you will need a code editor where you will actually do the coding. You may use the text editor that your machine have provided, however that is really not recommended. You will not get syntax highlighting, code snippets, autocompletion, and simple error detection (just to name a few benefits) from using a plain text editor.

There are many code editors out there. I personally opt for Visual Studio Code as it is light, open sourced (great community), has a great UX, has built-in git, and has its own terminal (this last one was what made me convert from the last code editor I use)

You will also need to install Node.js on your machine. Node.js is a JavaScript runtime library built on Chrome’s V8 JavaScript engine. Having Node.js installed on your machine will allow JavaScript to run outside of a typical web browser. To install Node.js, follow this link.

Installing Node.js will also install npm. According to it’s official site, npm is two things: it is a repository of open-sourced packages and it is also a command-line utility for interacting with said repository. Npm can be used to install open-sourced packages, manage project versions, and manage dependencies.

Now that we have a code editor, Node.js, and npm installed in our machine, let us dive straight into the project.

The Code

First of all, you will need to create an empty directory where all the files needed for this react app resides. Inside the terminal, type:

mkdir react-app
cd react-app

mkdir (make directory) is a command to create a new directory while cd (change directory) let’s you change the current working directory. From the above instructions, we have created a new directory called “react-app” and then we changed the current working directory so that we are now inside the react-app directory.


Create a package.json file by typing in the following command at the root of react-app folder:

npm init -y

Package.json file is (as the extension implies) a json file which holds an object of key-value pair). By having a package.json file we could install packages and dependencies needed for this project. Inside the package.json file, you should see something like this:

package.json file

It holds the current project’s metadata (name, version, description, keywords, author, and license) and some other stuff (we will get to this later) that can be useful .


The first group of packages (or dependencies) that we need to install comes from babel. Babel is a JavaScript compiler. It compiles (parses, transforms, and print) JavaScript code from one set to another. Babel does this by using plugins — a plugin parses or transforms one specific instruction. A set of plugin is called a preset — using a preset will save the time from installing each individual plugin. At the time of this writing, we use the latest version of babel which is Babel 7.

Why do we need a compiler? It is because of the browsers that JavaScript runs on. Browsers don’t always implement the latest JavaScript version and also different browsers could implement different JavaScript versions. That is why we need to compile our code into a JavaScript version that browsers could read. Also, working with React means that you will be working with a special syntax called JSX. JSX cannot be instantly read by browsers, that’s why we need the help of babel to transform these JSX syntax into JavaScript that browsers can understand.

There are 3 babel dependencies we need to install:
@babel/core — This contains the babel core configuration,
@babel/preset-env — This contains different plugins, the most important of which transforms all ES2015-ES2020 code to be ES5 compatible (the one JavaScript version where almost all browsers implement)
@babel/preset-react —
This contains different plugins to enable React syntax parsing and transformation.

npm install --save-dev @babel/core @babel/preset-env @babel/preset-react

We use the--save-dev flag so that these babel packages are only used in the development environment. After running the commande above, in your package.json file, you will see a new key called devDepencies which has an object containing the information of packages (and version number) that we have installed as dependencies in the development environment. This is one of many ‘other stuff’ mentioned earlier about what information package.json can hold.

package.json with devDependencies

Note that after installing a package, there will be a file named package-lock.json and a directory called node_modules created at the root of the folder. package-lock.json basically helps determine the exact version of dependecies installed when the project folder is replicated elsewhere using npm install. Meanwhile, the node_modules directory is where all the installed packages resides, so don’t be surprised if the directory size is massive. You can read more about package-lock.json here.


The next group of dependencies that we need to install comes from webpack. Webpack is a static module bundler for JavaScript application. It maps every module (or assets) the project needs in a dependency graph and generates one or more bundles. Why do we need Webpack? In earlier days, when we want to to load different JavaScript files into html we would need to include a <script> tag for each of the JavaScript files and in the correct order. When Node.js came out, it brings along the require() function which allow users to modularize JavaScript files (different JavaScript files for different functions). Webpack allows us to bundle all these JavaScript modules and also non-JavaScript assets such as css, images, and others using its ‘loaders’. You can read more about webpack and why webpack exists here and here.

npm install --save-dev webpack webpack-cli webpack-dev-server 

At the time of writing, the latest webpack version available is webpack 5. There are three packages that need to be installed: webpack, webpack-cli, and webpack-dev-server. webpack is the core webpack functionality package. To use webpack, the webpack-cli package also needs to be installed along. Lastly, webpack-dev-server enables a development server that can be used in a development environment only which provides live reloading.


Of course. It is the main package that will need to be installed. However, different from the last two groups of packages (babel and webpack), react should not be installed using --dev-save flag, instead use the -- save flag (or no flag at all). This is so that react can be used both in the production environment and in the development environment. Install react by typing the following command at the root of the react-app directory:

npm install react react-dom

For react to work, we need to install two main packages: react and react-dom. The react package only contains the functionality to work with react components. However, to interact with and render to the DOM, we need the react-dom package.


Now that we’ve installed the necessary dependencies, let’s configure our app so that we can code with react. We need to create two directories called public and src. Inside the src directory, create a file named app.js From the root of the react-app directory, type in the following commands to the terminal:

mkdir public


mkdir src
touch src/app.js

If you’re using a windows machine, instead of touch, you should use the ni (new item) command. The public directory is where our ready-to-be-served files reside. The src directory is where we will actively code in. The first file in the src directory, app.js, is our entry point to our react application. Our code should begin from here on out.

Next, we need to configure webpack to tell it to bundle files starting from the entry point, the app.js file. Create a file called webpack.config.js:

touch webpack.config.js

Our folder structure should now look like this:

current folder structure

Inside the webpack.config.js file, we type in the following code (explained below):

  1. We require Node’s path module in order to work with file and directory paths.
  2. We export an object, again, using Node’s module.exports. The exported object from webpack.config.js contains the entry and output keys (which will expand later on). The entry key specifies which module or file should webpack use to begin building out its dependency graph. From that point, webpack will determine which other modules that entry point depends on. Our entry point, as specified above, is the ./src/app.js created earlier.
    The output key, on the other hand, specifies the name of the file and the path where the created bundle should be emitted. We specified the emitted file name to be bundle.js which resides in the public directory created earlier.

To test whether what we’ve configure so far works, run the webpack command in the terminal at the root of our project folder. Chances are, an error will be thrown:

webpack : The term 'webpack' is not recognized as the name of a cmdlet, function, script file, or operable program. Check the spelling of the name, or if a path was included, verify that the path is correct and try again.

What happened? Because we have installed webpack and webpack-cli locally as devDependencies (as the documentation suggests), we need to access the webpack command from the local node_modules directory. Run the webpack command again but this time from the node_modules directory. At the root of the project, type the following in the terminal:


When the command is successfully executed, you should see a new file called bundle.js inside the public directory, as specified in the webpack.config.js file. bundle.js should still be empty as we haven’t added any code in app.js yet.

As we will be using jsx and (safely assume) the latest JavaScript features, for all browser compatibility, we will transform our code using babel. To transform our code, we will use a package called babel-loader. babel-loader will allow us to transpile our JavaScript file using babel and webpack.

Install babel-loader by running the following command in the terminal:

npm install --save-dev babel-loader

Add babel-loader in the webpack.config.js file like so:


3. We added a new key called module inside the module.exports object in webpack.config.js file. module is where webpack determines which loader to use. Loaders allow webpack to process files (javascript and non-javascript files) and convert them into valid modules to be consumed by our application and added to the dependency graph. Here we instruct webpack to transform files ending with .js extension using the babel-loader, except those inside the node_modules directory.

Once babel-loader is set up in the webpack.config.js file, we need to create another file to configure babel at the root of the folder called babel.config.json. In earlier versions of babel, this configuration file for babel was rather named .babelrc. However, following the latest babel documentation, we use the babel.config.json as recommended:

touch babel.config.json

Inside babel.config.json, add the following code:


babel-loader will try to find the babel configuration file —this babel.config.json. The code in this file instructs babel-loader to use @babel/preset-env and @babel/preset-react presets that we have installed earlier when transpiling our code.

In order for us to see our react-app site (and changes to it) on the browser in development mode, we take advantage of webpack-dev-server. The configurations for webpack-dev-server should also be inside webpack.config.js. Inside webpack.config.js add the following code inside module.exports (instruction number 5) object:


5. The devServer key describes the configurations that can be made to webpack-dev-server. Here, we tell webpack-dev-server to serve files from our public directory.

Lastly for the configurations, we need to add the following scripts in package.json:


To make our development easier, we add three scripts to run from npm: build, start, and watch. The build command will instruct webpack to start building the dependency graph from the source file and generate the bundle into the targeted directory according to webpack.config.js file we created earlier. Instead of repeatedly instructing webpack to run the full build manually, we can use the watch command. This command will instruct webpack to listen to any changes saved in our project and immediately recompile to a new bundle. Meanwhile, the start command will instruct webpack to start a simple development server so that we can see our project live in the browser. Note that in earlier versions of webpack, the instruction to start a development server would be webpack-dev-server --watch. Any changes saved to our project will automatically reload the server with the new changes.

npm run build|start|watch

Main Code

Our project needs to have an html file where our react app can render into. We create a standard html file in the public directory. From the root of our project directory, type the following in the terminal to create an html file:

touch public/index.html

Next, add the following html inside public/index.html:


Here is a standard html file boilerplate with a head and body tag. Inside the head, goes our meta tags which defines the html metadata. The area we need to focus is the body tag.

6. Inside the body tag, there are two tags: a div tag with the id “root” and a script tag that references to our bundle.js file created by webpack. The “root” div is where our react-app will render into. Meanwhile, bundle.js file is where our react-app from src/app.js gets bundled into. In a way, this html file will use the JavaScript code from bundle.js, which holds our bundle (and transformed) react-app code, which will then be render into the “root” div (hope this makes sense).

Now, let’s code our react-app inside src/app.js like so:


Inside src/app.js, we create an App component which will be rendered into the root div that we specified earlier.

To test whether our app works, let’s recompile our app.js using webpack:

npm run build

We fire up our development server by running the following command at the root of the project folder.

npm run start

The result of that command in the terminal should point to a localhost url (usually http://localhost:8080/) where the current project is being served. Entering that url in the browser will take you to the react-app page:

Our react-app page

We did it! We have made a react-app from scratch using the latest from tools from babel and webpack. If we make any changes to our code in src/app.js, webpack will automatically recompile and the changes should be updated live as we save the file.

I encourage you to poke around just for the sake of learning how everything in our react-app directory works. I recommend you start from src/app.js.

Next, we will try and build an Express server where we could serve this app from. The app could be delivered/served to the client via client-side rendering or server-side rendering. To understand how client-side rendering works using Express back end (and continuing with this react-app project from scratch), follow the link below:

To understand how server-side rendering works using Express back end, follow the following link instead:

The Startup

Get smarter at building your thing. Join The Startup’s +800K followers.

Putra Aryotama

Written by

I write for fun! I write about my field of work (tax, accounting, and economics) and hobby (programming, javascript, react). Sometimes in Indo, usually in Eng

The Startup

Get smarter at building your thing. Follow to join The Startup’s +8 million monthly readers & +800K followers.

Putra Aryotama

Written by

I write for fun! I write about my field of work (tax, accounting, and economics) and hobby (programming, javascript, react). Sometimes in Indo, usually in Eng

The Startup

Get smarter at building your thing. Follow to join The Startup’s +8 million monthly readers & +800K followers.

Medium is an open platform where 170 million readers come to find insightful and dynamic thinking. Here, expert and undiscovered voices alike dive into the heart of any topic and bring new ideas to the surface. Learn more

Follow the writers, publications, and topics that matter to you, and you’ll see them on your homepage and in your inbox. Explore

If you have a story to tell, knowledge to share, or a perspective to offer — welcome home. It’s easy and free to post your thinking on any topic. Write on Medium

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store