Why React Needs a Build Step at All
With plain HTML, CSS and JavaScript you can double-click a file and the browser runs it. React is different, and it is worth understanding why before you type any commands, because half of all setup problems come from not knowing what the tools are for.
The syntax you write in a React file — return <h1>Hello</h1> — is called JSX, and no browser understands it. Something has to translate it into ordinary JavaScript function calls before it reaches the browser. That translator is part of your build tool. On top of that, a real project imports dozens of small files and npm packages, and shipping hundreds of separate files to a browser is slow, so the build tool also bundles them together and shrinks them.
That is the whole job of the tooling: translate JSX, resolve imports, bundle for production. Node.js is what runs those tools on your machine, and npm is the package manager that downloads them. Neither Node nor npm runs in your finished website — they are development-time tools, in the same way a compiler is not part of the program it compiles.
- Install Node.js (a current LTS release) from nodejs.org — npm is included with it
- Check it worked with
node -vandnpm -vin your terminal - Install VS Code, plus the ES7+ React snippets and Prettier extensions if you like them
- Install the React Developer Tools extension in Chrome, Edge or Firefox — you will use it constantly
- Because JSX must be compiled, you cannot open your project's
index.htmldirectly from the file system and expect it to work. React projects are always viewed through a dev server or a real web server.
Creating a Project with Vite
Vite is the tool most new React projects start with. It gives you a dev server that starts almost instantly and updates the browser the moment you save a file, a feature called hot module replacement. When you save a component, Vite swaps just that component in the running page instead of reloading everything, so your form stays filled in and your open modal stays open.
Four commands take you from nothing to a running app. The odd-looking -- in the first command is not a typo: it tells npm that the flags after it belong to the Vite scaffolder, not to npm itself. Leave it out and you will get a confusing error about an unknown option.
Pick the React template when it asks, then choose JavaScript or TypeScript. If you are new, choose JavaScript for now — you can add TypeScript later, and mixing a new language with a new library at the same time is a reliable way to get stuck.
# 1. Scaffold a new project (the -- is required)
npm create vite@latest my-app -- --template react
# 2. Move into the folder it created
cd my-app
# 3. Download the dependencies listed in package.json
npm install
# 4. Start the dev server
npm run dev
# VITE ready in 312 ms
# ➜ Local: http://localhost:5173/
# Stop the server with Ctrl+C when you are done. npm installcreates anode_modulesfolder that is often hundreds of megabytes. Never commit it to git and never copy it around — anyone with yourpackage.jsoncan recreate it with one command. A Vite project's.gitignorealready excludes it.
A Tour of the Files You Get
Open the folder in VS Code and the structure is small enough to read in one sitting. Almost everything you write lives in src/. The chain that starts your app is short and worth tracing once by hand: index.html contains an empty <div id="root"></div> and a script tag pointing at src/main.jsx; main.jsx finds that div and tells React to render <App /> inside it; App.jsx is your actual application.
That is the only place in a React app where you connect React to the page. Everything after it is components rendering other components. Beginners often go looking for more wiring; there isn't any.
You will notice <StrictMode> wrapped around your app in main.jsx. It is a development-only helper that switches on extra checks and warnings to surface fragile code early. One consequence surprises everyone: in development, StrictMode deliberately runs certain functions — including your components and your effects — an extra time. If you see a console log appear twice while developing, that is usually why. It does not happen in a production build.
my-app/
├── node_modules/ # downloaded packages — never edit, never commit
├── public/ # files copied as-is; reference them as /logo.png
├── src/
│ ├── assets/ # images imported by components
│ ├── App.jsx # your application's top component
│ ├── App.css # styles for App
│ ├── main.jsx # the entry point — connects React to index.html
│ └── index.css # global styles
├── index.html # the single HTML page; holds <div id="root">
├── package.json # dependencies and the npm scripts
└── vite.config.js # build tool configuration
// src/main.jsx — the one place React meets the DOM
import { StrictMode } from 'react';
import { createRoot } from 'react-dom/client';
import App from './App.jsx';
import './index.css';
createRoot(document.getElementById('root')).render(
<StrictMode>
<App />
</StrictMode>
); src/— every component, hook and stylesheet you writepublic/— static files served unchanged at the site root, such asfavicon.icoindex.html— the only HTML page in the project; edit the title and meta tags heremain.jsx— mounts<App />into#rootpackage.json— the dependency list and thedev,buildandpreviewscripts- Files containing JSX use the
.jsxextension (or.tsxwith TypeScript)
The Dev Server Is Not Your Website
npm run dev starts a server tuned for editing: it compiles on demand, keeps helpful warnings switched on, and does not optimise anything. What it serves is not what you deploy. To produce the real thing you run npm run build, which compiles and minifies everything into a dist/ folder containing plain HTML, CSS and JavaScript.
That dist/ folder is your website. It has no Node in it and needs no Node on the server, which is why a React app can be hosted on ordinary shared hosting, on Netlify or Vercel, or on GitHub Pages. Upload the contents of dist/, not your source folder.
Between those two commands sits npm run preview, which serves the built dist/ folder locally. Use it before every deployment. Problems that only appear in a production build — a missing environment variable, a wrong asset path, a file whose name is capitalised differently from its import — show up here in five seconds instead of after an upload.
npm run dev # development server with hot reloading, at localhost:5173
npm run build # compile + minify into dist/ <-- this is what you deploy
npm run preview # serve dist/ locally so you can test the real build
# Deploying into a subfolder such as https://example.com/myapp/ ?
# Tell Vite, or every asset path will point at the wrong place:
// vite.config.js
import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';
export default defineConfig({
plugins: [react()],
base: '/myapp/'
}); - Anything bundled into
dist/is public. Never put an API key, a database password or any secret in your React source and assume the build hides it — minified code is still readable, and anyone can open it. Secrets belong on a server you control.
Errors You Will Probably Hit on Day One
Setup problems are unglamorous but they stop people cold, so here are the ones that come up again and again, with what they actually mean. None of them indicates you have done something clever and wrong; they are all mechanical.
The most expensive one to discover late is the case-sensitivity trap. Windows and macOS treat Header.jsx and header.jsx as the same file, so an import with the wrong capitalisation works perfectly on your laptop. Most web servers run Linux, where those are two different files, so the same code fails at build or load time after you deploy. Get into the habit of matching the file name exactly, and run npm run build locally before you upload anything.
'vite' is not recognisedorCannot find module— you forgotnpm install, or you are in the wrong folderPort 5173 is in use— another dev server is still running; stop it with Ctrl+C or let Vite pick the next port- A blank white page — open the browser console; a React error almost always prints there with the component name
Failed to resolve import './Header'— wrong path, wrong capitalisation, or a missing.jsxfile- Changes not appearing — you are looking at a stale tab, or the terminal shows a compile error you scrolled past
- Nothing works after copying a project — copy the source, then run
npm installagain; never copynode_modules
- Read the terminal, not just the browser. Vite prints compile errors in the terminal window where the dev server is running, and those messages name the file and line. A silent browser and a red terminal is the most common combination.
Vite, Create React App, or Next.js?
You will find tutorials starting with three different tools, which is confusing when you are new. Here is how to choose without agonising over it.
Vite is the default answer for learning and for most single-page apps: fast, small, and it stays out of your way. Create React App was the standard for years, and a lot of older tutorials and college material still use it, but it is no longer recommended for new projects — if you meet a CRA project you will still be able to read it, since the React code inside is identical. Next.js is a full framework built on React that adds file-based routing, server rendering and its own build pipeline; it is an excellent production choice, but learning it at the same time as React means you will not be sure which rules belong to which tool.
Start with Vite. Everything you learn in this course is plain React and moves to Next.js unchanged when you need it.
- Learning React, or building a dashboard or college project — use Vite
- Joining an existing project that uses Create React App — leave it alone; the React code is the same
- Need SEO, server rendering or a full-stack app in one codebase — use Next.js, after this course
- Need a mobile app from the same skills — React Native, again after this course
- Whichever you choose, the component code is identical. The tool decides how your files are compiled and served; it does not change what a component, a prop or a hook is.
