DEV Community

Cover image for React Doesn't Need Node.js — Until It Does
Alimur Razi Rana
Alimur Razi Rana

Posted on • Edited on

React Doesn't Need Node.js — Until It Does

The Truth Nobody Tells You When You Start React

Most React tutorials for beginners start the same way

"First, install Node.js..."

And every beginner obeys without question. Most of them never challenge it. It's just accepted as part of the ritual.

But here's the thing — React doesn't actually need Node.js to work.

And understanding why that's true, and where it stops being true, will completely change how developers think about the entire React ecosystem — including Vite, Next.js, and npm itself.

Let's start with a proof.


Part 1: React With Zero Node.js

Create a plain .html file on your desktop. Paste this in:

<!DOCTYPE html>
<html>
  <head>
    <title>React, no Node.js</title>
  </head>
  <body>

    <div id="root"></div>

    <!-- React from CDN -->
    <script src="https://unpkg.com/react@18/umd/react.development.js"></script>
    <script src="https://unpkg.com/react-dom@18/umd/react-dom.development.js"></script>

    <!-- Babel to handle JSX in the browser -->
    <script src="https://unpkg.com/@babel/standalone/babel.min.js"></script>

    <script type="text/babel">
      function App() {
        const [count, setCount] = React.useState(0);
        return (
          <div>
            <h1>Hello from React!</h1>
            <p>Count: {count}</p>
            <button onClick={() => setCount(count + 1)}>Click me</button>
          </div>
        );
      }

      ReactDOM.createRoot(document.getElementById('root')).render(<App />);
    </script>

  </body>
</html>
Enter fullscreen mode Exit fullscreen mode

Double-click the file. Open it in your browser.

It works. State works. JSX works. React works.

No Node.js. No npm. No terminal. No installation.

Just a file and a browser.

This isn't a trick or a hack. This is how React was used in its early days. React is, at its core, just a JavaScript library — the same as jQuery or Lodash. It can be loaded with a <script> tag like anything else.

So if that's true... why does every guide tell you to install Node.js?


Part 2: Where the CDN Approach Breaks Down

The CDN approach works perfectly for small experiments. But the moment the app grows beyond a single file, it hits its real limitations.

First, a common misconception worth clearing up:

Modern browsers actually support ES module imports natively:

<script type="module">
  import Header from './Header.js'
  import Footer from './Footer.js'
</script>
Enter fullscreen mode Exit fullscreen mode

So imports themselves aren't the problem. The real limitations are deeper than that.


1. JSX Needs Compilation

Browsers understand JavaScript. They do not understand JSX:

// ❌ Browser has no idea what this is
function App() {
  return <h1>Hello</h1>
}

// ✅ Browser only understands this
function App() {
  return React.createElement("h1", null, "Hello")
}
Enter fullscreen mode Exit fullscreen mode

Every JSX file needs to be compiled into plain JavaScript before a browser can run it. Native ES modules don't solve this — the browser still can't parse the JSX syntax itself.
This compilation step is handled by different tools depending on setup:

  • Babel — the original JSX compiler, still widely used in plain React projects
  • Vite — the popular choice for modern plain React projects
  • Next.js SWC — Next.js ships with its own built-in compiler

2. npm Packages Aren't ES Module Compatible Out of the Box

Most npm packages are written in CommonJS format — Node.js's own module system:

// CommonJS — how most npm packages are written
const axios = require('axios')
module.exports = something
Enter fullscreen mode Exit fullscreen mode

This is completely different from ES modules:

// ES Modules — what browsers understand
import axios from 'axios'
export default something
Enter fullscreen mode Exit fullscreen mode

Browsers cannot run CommonJS. A bundler is needed to convert and reconcile these formats before they reach the browser.


3. Dependency Management Becomes a Nightmare

Want to use axios? You'd manually find its CDN link. Then manually find CDN links for all of axios's dependencies. Then their dependencies. A single real-world package can pull in dozens of sub-dependencies — tracking all of them by hand is completely unworkable.


4. Performance Suffers With Many Module Files

Even if everything was ES module compatible, loading 200 separate JavaScript files means 200 separate network requests — each with its own overhead. A bundler combines them into one or a few optimized files, which loads dramatically faster.


Part 3: What Node.js Actually Is

Before understanding why Node.js solves these problems, you need to understand what Node.js actually is — because most developers use it for years without knowing this.

Operating system cannot run JavaScript.

OS can run Python (if installed). It can run compiled C++ binaries. But JavaScript? No. Most operating systems don't include a built-in JavaScript runtime that can execute JavaScript files directly.

Only two environments have been able to execute JavaScript:

1. The Browser
   → Chrome, Firefox, Safari all have a built-in JS engine
   → Chrome uses V8 (built by Google)
   → Firefox uses SpiderMonkey

2. Node.js
   → Takes Chrome's V8 engine
   → Strips out the browser parts (DOM, window, etc.)
   → Adds OS-level access (file system, network, processes)
   → Runs as a standalone program on your computer
Enter fullscreen mode Exit fullscreen mode

That's literally all Node.js is. It's Chrome's JavaScript engine, liberated from the browser and given the ability to talk to your operating system.

Ryan Dahl, who created Node.js in 2009, had one core insight:

"JavaScript is already a great language. Why does it only run in browsers? What if it could run anywhere?"

So when you install Node.js, you're essentially installing a JavaScript interpreter directly onto your machine — the same engine that powers Chrome, just without the browser.

This is why npm packages need Node.js.

npm packages are JavaScript files. OS can store them just fine — it's great at storing files. But it cannot execute them. It has no JavaScript engine. Node.js provides that engine. Without it, those JavaScript files just sit there on your disk doing nothing.


Part 4: What npm Actually Solves

After Node.js, let's talk about npm — because it's far more than just a package downloader.

When you run npm install axios, npm doesn't just download axios. It:

1. Downloads axios
2. Reads axios's list of dependencies
3. Downloads those dependencies
4. Reads THEIR dependencies
5. Downloads those too
6. Resolves any version conflicts across the whole tree
7. Builds a complete, working dependency graph
8. Stores everything in node_modules
Enter fullscreen mode Exit fullscreen mode

This process — called dependency resolution — is genuinely complex. Packages depend on other packages, which depend on other packages, which might conflict with each other's version requirements. npm handles all of this automatically.

Without npm, developers would need to do this by hand. For a real project with dozens of dependencies, each with their own sub-dependencies, that would be thousands of files to track manually. It would be completely unworkable.

And critically — npm itself is built on Node.js. It needs Node.js to run the resolution logic, download packages, execute install scripts, and manage the entire node_modules directory.

So the chain is clear:

You need npm
  → npm needs Node.js to run
    → Node.js provides the JS engine
      → JS engine executes npm's logic
        → npm manages your packages
          → packages can now be used in your app
Enter fullscreen mode Exit fullscreen mode

Remove Node.js from this chain and the whole thing collapses.


Part 5: In Production, Node.js Disappears (For Plain React)

Here's something that surprises many developers.

When you run npm run build in a plain React + Vite project, Vite does all its work and produces a /dist folder:

/dist
  index.html
  assets/
    main.abc123.js     ← plain JavaScript, no JSX
    styles.abc123.css  ← plain CSS
    logo.abc123.png    ← optimized image
Enter fullscreen mode Exit fullscreen mode

These are completely static files. Plain HTML, CSS, and JavaScript that any browser understands natively.

At this point, Node.js is completely out of the picture. You can take this /dist folder and host it on:

  • AWS S3
  • GitHub Pages
  • Netlify
  • Cloudflare Pages
  • A basic Apache server
  • Literally any file hosting service

No Node.js required. No server running. No ongoing processes. Just files being served.

Node.js was only needed during development — to run the JSX compiler, manage packages, and transform your code. Once the build is done, it has no role left.

Think of it like a printing press:

The printing press (Node.js + JSX compiler) prints the book (HTML/CSS/JS). Once printed, you don't need the press anymore. You just distribute the book. The reader (browser) never knew or cared about the press.


Part 6: Next.js Changes Everything

Everything we've covered so far describes plain React — a client-side application where the browser does all the rendering work.

Next.js fundamentally changes this model.

How Plain React Renders

User visits your site
        ↓
Server sends an almost empty HTML file:

<html>
  <body>
    <div id="root"></div>  ← nothing here
    <script src="bundle.js"></script>
  </body>
</html>
        ↓
Browser downloads bundle.js (can be 1-2MB)
        ↓
JavaScript runs, React builds the UI
        ↓
User finally sees content
Enter fullscreen mode Exit fullscreen mode

The server does almost nothing. The browser does all the work. This means:

  • Users on slow connections wait a long time before seeing anything
  • Search engines see an empty page — bad for SEO
  • The user's device carries all the rendering cost

How Next.js Renders

User visits react site
        ↓
Request hits the Next.js SERVER (Node.js running live)
        ↓
Server executes React components
        ↓
Produces complete HTML with actual content:

<html>
  <body>
    <div id="root">
      <h1>Your Product Name</h1>   ← already here
      <p>Price: $49</p>            ← already here
      <button>Buy Now</button>     ← already here
    </div>
    <script src="bundle.js"></script>
  </body>
</html>
        ↓
Browser receives full HTML instantly
        ↓
User sees content immediately ✅
        ↓
React "hydrates" — attaches event listeners
        ↓
App becomes interactive ✅
Enter fullscreen mode Exit fullscreen mode

The key difference: the server does the rendering work before the browser gets involved.

The Browser Has No Idea

The browser doesn't know — and doesn't care — whether it received HTML from a Next.js server, a plain React build, a WordPress site, or hand-written HTML. It just renders what it gets.

The difference is entirely in what the server sends. Next.js sends richer, fuller HTML. Plain React sends almost nothing and lets the browser figure it out.

Node.js Stays Alive in Production

This is the critical difference from plain React.

In a plain React app, Node.js is a development-only tool that disappears after the build.

In Next.js, Node.js runs permanently in production ( Next.js can also run project with little or no traditional node server, depending on how the application is configured ) — processing every user request, rendering components on the server, fetching data from databases, and generating HTML in real time.

Plain React:
Node.js role → Development only → Gone after build

Next.js:
Node.js role → Development AND Production → Always running
Enter fullscreen mode Exit fullscreen mode

This is why Next.js cannot be deployed to a static file server (unless exported it as fully static). It needs a live Node.js process running 24/7 to handle incoming requests.


Found this useful? Share it with the developer who just ran npm install without knowing why.

Top comments (0)