# Introduction to Express.js

Course: [Express.js](https://www.devtutorials.ai/learn/expressjs) · Section: Express.js Foundations
Source: https://www.devtutorials.ai/learn/expressjs/foundations/introduction-to-express

> What Express.js is and why it was created, its history and features, Express versus the Node.js http module, Express 4 versus Express 5, how a request flows through an app, what you can build, and how to set up, configure, run and test your first Express 5 server.

## Express.js Introduction

**Express.js** = a small framework that helps you build web servers with Node.js.

- A **web server** is a program that waits for requests and sends back answers.
- **Node.js** lets JavaScript run on a computer, outside the browser.
- Express sits on top of Node.js and does the boring server work for you.
- You write short rules like "when someone asks for `/menu`, send the menu".
- Most people just call it **Express**.

**Simple lesson:** Express helps you write a web server in JavaScript with very little code.

### A Real-World Example

Your school canteen gets a new app. Students open it on their phones.

- A student taps **Menu**. The phone sends a request to the canteen server.
- The server is written with Express.
- Express finds the rule for `/menu` and runs it.
- The rule sends back the list: Idli, Dosa, Vada.
- The phone shows the list. All of this takes a few milliseconds.

<figure className="xfig ngc-fig">
<svg viewBox="0 0 560 190" role="img" aria-labelledby="xfig-rr" style={{ width: "100%", maxWidth: 560, height: "auto" }}>
  <title id="xfig-rr">Animation: a phone sends GET /menu to an Express server, and the server sends the menu back</title>
  <defs><marker id="xfig-rr-arrow" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="7" markerHeight="7" orient="auto"><path d="M0 0 L10 5 L0 10 z" style={{ fill: "var(--ngc-blue)" }} /></marker></defs>
  <g style={{ fontFamily: "var(--sans)", fontSize: 13, fontWeight: 700 }}>
    <rect x="20" y="40" width="90" height="120" rx="14" style={{ fill: "var(--ngc-blue-soft)", stroke: "var(--ngc-blue)", strokeWidth: 2 }} />
    <rect x="32" y="58" width="66" height="74" rx="4" style={{ fill: "var(--panel)", stroke: "var(--ngc-blue)", strokeWidth: 1 }} />
    <text x="65" y="80" textAnchor="middle" style={{ fill: "var(--ngc-blue)", fontSize: 11 }}>Canteen</text>
    <text x="65" y="96" textAnchor="middle" style={{ fill: "var(--ngc-blue)", fontSize: 11 }}>app</text>
    <text x="65" y="180" textAnchor="middle" style={{ fill: "var(--ink)" }}>Client (phone)</text>
    <rect x="410" y="40" width="130" height="120" rx="12" style={{ fill: "var(--ngc-green-soft)", stroke: "var(--ngc-green)", strokeWidth: 2 }} />
    <text x="475" y="78" textAnchor="middle" style={{ fill: "var(--ngc-green)" }}>Express</text>
    <text x="475" y="98" textAnchor="middle" style={{ fill: "var(--ngc-green)", fontWeight: 400, fontSize: 11 }}>on Node.js</text>
    <text x="475" y="126" textAnchor="middle" style={{ fill: "var(--ngc-green)", fontFamily: "var(--mono)", fontWeight: 400, fontSize: 11 }}>app.get("/menu")</text>
    <text x="475" y="180" textAnchor="middle" style={{ fill: "var(--ink)" }}>Server</text>
  </g>
  <line x1="118" y1="80" x2="400" y2="80" style={{ stroke: "var(--line)", strokeWidth: 2, strokeDasharray: "5 5" }} />
  <line x1="400" y1="122" x2="118" y2="122" style={{ stroke: "var(--line)", strokeWidth: 2, strokeDasharray: "5 5" }} />
  <g style={{ fontFamily: "var(--mono)", fontSize: 12, fontWeight: 700 }}>
    <g>
      <rect x="-48" y="-13" width="96" height="24" rx="12" style={{ fill: "var(--ngc-blue)" }} />
      <text x="0" y="4" textAnchor="middle" style={{ fill: "#fff" }}>GET /menu</text>
      <animateMotion path="M165 80 L355 80" dur="6s" repeatCount="indefinite" keyPoints="0;0;1;1" keyTimes="0;0.1;0.4;1" calcMode="linear" />
      <animate attributeName="opacity" values="0;1;1;0;0" keyTimes="0;0.1;0.4;0.45;1" dur="6s" repeatCount="indefinite" />
    </g>
    <g opacity="0">
      <rect x="-70" y="-13" width="140" height="24" rx="12" style={{ fill: "var(--ngc-green)" }} />
      <text x="0" y="4" textAnchor="middle" style={{ fill: "#fff" }}>Idli, Dosa, Vada</text>
      <animateMotion path="M335 122 L185 122" dur="6s" repeatCount="indefinite" keyPoints="0;0;1;1" keyTimes="0;0.55;0.85;1" calcMode="linear" />
      <animate attributeName="opacity" values="0;0;1;1;0" keyTimes="0;0.55;0.56;0.9;1" dur="6s" repeatCount="indefinite" />
    </g>
  </g>
  <g style={{ fontFamily: "var(--sans)", fontSize: 12 }}>
    <text x="260" y="62" textAnchor="middle" style={{ fill: "var(--ngc-blue)" }}>1. Request</text>
    <text x="260" y="150" textAnchor="middle" style={{ fill: "var(--ngc-green)" }}>2. Response</text>
  </g>
</svg>
<figcaption>The phone asks. Express finds the matching rule and answers.</figcaption>
</figure>

In this lesson, you will learn:

1. What Express is, why it was made and what it can build.
2. How Express compares with plain Node.js and with Express 4.
3. How a request travels through an Express app.
4. How to set up a project and keep secrets out of your code.
5. How to write, run, test and fix your first server.

## Before You Start

Check these before you go on. You will learn faster if you already know them:

- **JavaScript basics:** variables, functions, arrays and objects.
- **Arrow functions:** `(req, res) => ...` is used everywhere.
- **Modules:** `import` and `export` between files.
- **Promises, async and await:** for work that takes time, such as a database.
- **Node.js basics:** running a file with `node file.js`.
- **npm basics:** installing packages with `npm install`.
- **HTTP basics:** requests and responses. The next lesson teaches these.
- **Node.js 18 or later:** Express 5 needs it. The current LTS version is best.

**Simple lesson:** Know modern JavaScript and a little Node.js, and you are ready.

## Your First Express Server

Here is a complete Express server. It has just three steps: create the app, add a route, and start listening on a port.

Prefer TypeScript? Choose **TypeScript** in the **Language** menu in the top bar. Your choice applies to every lab and exercise in this course. TypeScript labs run with `npx tsx`. The lesson **Express with TypeScript** explains the extra parts.

Press **▶ Run**. Then look at the panel on the right.

- **Terminal** shows the start command (`$ node server.js`) and the message from `console.log`.
- **Response** shows `200 OK` and the welcome text.
- Press the **GET /hello** button. You get `404 Not Found`, because there is no rule for `/hello`.

In this lab, a small copy of Node.js and Express 5 runs inside your browser. On your own computer, the same code runs with real Node.js. The Download button gives you the project as a zip.

**Simple lesson:** `app.get` adds a rule, and `app.listen` starts the server.

## Why Express Was Created

Node.js can already make a web server. So why do we need Express?

- Plain Node.js gives you the request as raw text and numbers.
- You must check the URL yourself with many `if` statements.
- You must set every header, such as the content type, by hand.
- You must read the request body piece by piece.
- Every project ends up writing the same helper code again.
- Express puts these helpers in one small, shared package.

**Simple lesson:** Express removes the repeated work, so you can focus on what your app does.

## History of Express.js

- **2010:** TJ Holowaychuk released Express. It was inspired by Sinatra, a small Ruby framework.
- **2014:** The company StrongLoop took care of the project.
- **2015 to 2016:** IBM bought StrongLoop, and Express moved to the Node.js Foundation.
- **Today:** Express belongs to the OpenJS Foundation and is looked after by volunteers.
- **2024:** Express 5.0 came out, the first big update in about ten years.
- **2025:** Express 5.1 became the default version that `npm install express` gives you.

**Simple lesson:** Express is old, stable and still updated. This course uses Express 5.

## Features of Express.js

- **Routing:** match a method and a path, such as `GET /menu`, to your code.
- **Middleware:** small functions that run one after another on every request.
- **Request helpers:** read the path, query and headers easily with `req`.
- **Response helpers:** send text, JSON, files and status codes with `res`.
- **Body parsing:** turn sent JSON or form data into a JavaScript object.
- **Static files:** serve images, CSS and HTML from a folder.
- **Templates:** build HTML pages from data with a view engine.
- **Huge ecosystem:** thousands of ready-made packages work with Express.

**Simple lesson:** Express gives you the basic tools. You add more only when you need them.

## Minimal and Unopinionated

Think about two ways to eat at a canteen.

1. A fixed thali comes with every dish already chosen.
2. A plain dosa counter gives you a dosa, and you pick your own chutneys.
3. The thali is quick to start, but hard to change.
4. The dosa counter takes a few choices, but you get exactly what you like.

Express is the dosa counter.

### Minimal

**Minimal** = Express ships with only the core pieces.

- No database tool is built in.
- No login system is built in.
- No fixed folder layout is built in.
- The package stays small and easy to learn.

### Unopinionated

**Unopinionated** = Express does not force one "right way".

- You choose the database, such as PostgreSQL or MongoDB.
- You choose the folder layout.
- You choose the validation and login packages.
- The downside: you must make these choices yourself.

**Simple lesson:** Express gives you a small base and lets you choose the rest.

## Express.js vs Node.js

People often mix these two up. They are not the same kind of thing.

- **Node.js** = the runtime. It runs JavaScript on a computer.
- **Express** = a package. It runs inside Node.js.
- You install Node.js once on your computer.
- You install Express into each project with npm.
- Express cannot run without Node.js. Node.js runs fine without Express.

<figure className="xfig ngc-fig">
<svg viewBox="0 0 520 220" role="img" aria-labelledby="xfig-layers" style={{ width: "100%", maxWidth: 520, height: "auto" }}>
  <title id="xfig-layers">Layers: your code on top of Express, on top of Node.js, on top of the computer</title>
  <g style={{ fontFamily: "var(--sans)", fontSize: 14, fontWeight: 700 }}>
    <rect x="60" y="14" width="400" height="40" rx="9" style={{ fill: "var(--ngc-orange-soft)", stroke: "var(--ngc-orange)", strokeWidth: 2 }} />
    <text x="260" y="39" textAnchor="middle" style={{ fill: "var(--ngc-orange)" }}>Your code: routes like app.get("/menu")</text>
    <rect x="60" y="64" width="400" height="40" rx="9" style={{ fill: "var(--ngc-green-soft)", stroke: "var(--ngc-green)", strokeWidth: 2 }} />
    <text x="260" y="89" textAnchor="middle" style={{ fill: "var(--ngc-green)" }}>Express: routing, middleware, req and res helpers</text>
    <rect x="60" y="114" width="400" height="40" rx="9" style={{ fill: "var(--ngc-blue-soft)", stroke: "var(--ngc-blue)", strokeWidth: 2 }} />
    <text x="260" y="139" textAnchor="middle" style={{ fill: "var(--ngc-blue)" }}>Node.js: runs JavaScript, http module, files</text>
    <rect x="60" y="164" width="400" height="40" rx="9" style={{ fill: "var(--ngc-purple-soft)", stroke: "var(--ngc-purple)", strokeWidth: 2 }} />
    <text x="260" y="189" textAnchor="middle" style={{ fill: "var(--ngc-purple)" }}>Your computer or a cloud server</text>
  </g>
</svg>
<figcaption>Each layer stands on the one below it.</figcaption>
</figure>

**Simple lesson:** Node.js runs your program. Express is a helper package inside it.

## Express.js vs the Node.js HTTP Module

The best way to see the difference is to build the same server twice.

Both servers answer `/` with a welcome and `/menu` with a list.

### The Plain Node.js Way

This version uses the built-in `node:http` module only.

Run it and press all three buttons.

- `/` and `/menu` work.
- `/menu?veg=true` gives **404**, because `req.url` is the whole text `/menu?veg=true`.
- To fix it, you would have to split the URL yourself.

### The Express Way

Run it and press all three buttons.

- All three work, including `/menu?veg=true`.
- Express matches the **path** only, and keeps the query separately.
- `res.send` saw an array, so it sent JSON and set the content type for you.
- The 404 page for unknown paths comes free.

### Side by Side

<div className="tscroll">

| Job | Node.js http module | Express |
|---|---|---|
| Match a URL | Many `if` checks on `req.url` | `app.get("/menu", ...)` |
| Query string | Split the URL yourself | Ready in `req.query` |
| Send JSON | `JSON.stringify` and set the header | `res.send(data)` or `res.json(data)` |
| Unknown paths | Write your own 404 branch | Automatic 404 |
| Request body | Read it in chunks | One line: `express.json()` |

</div>

**Simple lesson:** Express is built on the http module. It just does the repeated work for you.

## Express 4 vs Express 5

Express 5 is the current version. Many older tutorials still show Express 4.

- You do not need to learn this whole table now. Later lessons teach each row.
- For now, remember two things: copy paths from old code carefully, and check your Node.js version.

<div className="tscroll">

| Topic | Express 4 | Express 5 |
|---|---|---|
| Node.js version | Very old versions work | Node.js 18 or later |
| Errors in `async` handlers | Lost unless you call `next(err)` | Sent to the error handler for you |
| Match any path | `"*"` | A named wildcard, such as `"/*splat"` |
| Optional part of a path | `"/:id?"` | Curly braces, such as `"/{:id}"` |
| `app.listen` callback | Gets no error | Gets the error, if the port is busy |
| `req.query` | Can be replaced | Read-only |
| Removed old methods | `req.param()`, `res.redirect("back")` work | They are gone |

</div>

You can see one change right now. Run the lab below.

- The server stops with `TypeError: Unexpected ?`.
- Change `"/menu/:id?"` to `"/menu{/:id}"` and press Run again.
- Now both `/menu` and `/menu/2` work.

**Simple lesson:** Learn Express 5 syntax. When you copy old code, check its paths first.

## How an Express App Works

Every request goes on the same short trip through your app.

1. **Request:** a client sends a method and a path, such as `GET /menu`.
2. **Middleware:** helper functions run first, in the order you added them.
3. **Route matching:** Express looks for a rule with the same method and path.
4. **Route handler:** the matching function runs your code.
5. **Response:** the handler sends an answer with `res.send` or `res.json`.
6. **Done:** the trip ends. No match means a 404 answer.

<figure className="xfig ngc-fig">
<svg viewBox="0 0 580 170" role="img" aria-labelledby="xfig-flow" style={{ width: "100%", maxWidth: 580, height: "auto" }}>
  <title id="xfig-flow">Animation: a request passes through middleware, route matching and the handler, then a response goes back</title>
  <g style={{ fontFamily: "var(--sans)", fontSize: 12, fontWeight: 700 }}>
    <rect x="10" y="40" width="90" height="50" rx="10" style={{ fill: "var(--ngc-blue-soft)", stroke: "var(--ngc-blue)", strokeWidth: 2 }} />
    <text x="55" y="70" textAnchor="middle" style={{ fill: "var(--ngc-blue)" }}>Request</text>
    <rect x="125" y="40" width="100" height="50" rx="10" style={{ fill: "var(--ngc-purple-soft)", stroke: "var(--ngc-purple)", strokeWidth: 2 }} />
    <text x="175" y="70" textAnchor="middle" style={{ fill: "var(--ngc-purple)" }}>Middleware</text>
    <rect x="250" y="40" width="100" height="50" rx="10" style={{ fill: "var(--ngc-orange-soft)", stroke: "var(--ngc-orange)", strokeWidth: 2 }} />
    <text x="300" y="62" textAnchor="middle" style={{ fill: "var(--ngc-orange)" }}>Route</text>
    <text x="300" y="78" textAnchor="middle" style={{ fill: "var(--ngc-orange)" }}>matching</text>
    <rect x="375" y="40" width="90" height="50" rx="10" style={{ fill: "var(--ngc-green-soft)", stroke: "var(--ngc-green)", strokeWidth: 2 }} />
    <text x="420" y="70" textAnchor="middle" style={{ fill: "var(--ngc-green)" }}>Handler</text>
    <rect x="490" y="40" width="80" height="50" rx="10" style={{ fill: "var(--ngc-blue-soft)", stroke: "var(--ngc-blue)", strokeWidth: 2 }} />
    <text x="530" y="70" textAnchor="middle" style={{ fill: "var(--ngc-blue)" }}>Response</text>
  </g>
  <g style={{ stroke: "var(--line)", strokeWidth: 2 }}>
    <line x1="100" y1="65" x2="125" y2="65" /><line x1="225" y1="65" x2="250" y2="65" /><line x1="350" y1="65" x2="375" y2="65" /><line x1="465" y1="65" x2="490" y2="65" />
  </g>
  <circle r="9" cy="65" style={{ fill: "var(--ngc-orange)" }}>
    <animate attributeName="cx" values="55;175;300;420;530;530" keyTimes="0;0.2;0.4;0.6;0.8;1" dur="7s" repeatCount="indefinite" />
  </circle>
  <g style={{ fontFamily: "var(--sans)", fontSize: 13, fontWeight: 700 }}>
    <text x="290" y="130" textAnchor="middle" opacity="0" style={{ fill: "var(--ngc-blue)" }}><animate attributeName="opacity" values="1;1;0;0" keyTimes="0;0.18;0.2;1" dur="7s" repeatCount="indefinite" />1. GET /menu arrives</text>
    <text x="290" y="130" textAnchor="middle" opacity="0" style={{ fill: "var(--ngc-purple)" }}><animate attributeName="opacity" values="0;0;1;1;0;0" keyTimes="0;0.19;0.2;0.38;0.4;1" dur="7s" repeatCount="indefinite" />2. Middleware runs first</text>
    <text x="290" y="130" textAnchor="middle" opacity="0" style={{ fill: "var(--ngc-orange)" }}><animate attributeName="opacity" values="0;0;1;1;0;0" keyTimes="0;0.39;0.4;0.58;0.6;1" dur="7s" repeatCount="indefinite" />3. Express finds the GET /menu rule</text>
    <text x="290" y="130" textAnchor="middle" opacity="0" style={{ fill: "var(--ngc-green)" }}><animate attributeName="opacity" values="0;0;1;1;0;0" keyTimes="0;0.59;0.6;0.78;0.8;1" dur="7s" repeatCount="indefinite" />4. Your handler runs</text>
    <text x="290" y="130" textAnchor="middle" opacity="0" style={{ fill: "var(--ngc-blue)" }}><animate attributeName="opacity" values="0;0;1;1" keyTimes="0;0.79;0.8;1" dur="7s" repeatCount="indefinite" />5. The answer goes back to the client</text>
  </g>
</svg>
<figcaption>One request, one trip, one response.</figcaption>
</figure>

You will learn each step in detail later in this course.

**Simple lesson:** A request goes in, passes through your functions, and exactly one response comes out.

## What You Can Build with Express

- **Web applications:** full websites with pages and forms.
- **REST APIs:** send JSON data to apps, such as the canteen menu.
- **Backend services:** do work for other programs, such as sending emails.
- **Server-rendered websites:** build HTML pages on the server.
- **Login services:** check passwords and keep users signed in.
- **File upload services:** accept photos and documents.
- **Mobile app backends:** give Android and iPhone apps their data.
- **Single-page app backends:** serve a React or Vue app and its API.
- **Microservices:** many small servers, each doing one job.

**Simple lesson:** If it talks over HTTP, you can probably build it with Express.

## Setting Up an Express Project

Open a terminal in the folder where you keep your projects. Run these one by one.

```bash
mkdir canteen-api
cd canteen-api
npm init -y
npm install express
npm list express
```

What each command does:

- `mkdir canteen-api` makes a new project folder.
- `cd canteen-api` moves into it.
- `npm init -y` creates `package.json` with default answers.
- `npm install express` downloads Express into `node_modules`.
- `npm list express` prints the version. It should start with `express@5`.

### Turn On ES Modules

Open `package.json`. Add `"type": "module"` and two scripts.

```json
{
  "name": "canteen-api",
  "version": "1.0.0",
  "type": "module",
  "scripts": {
    "dev": "node --watch server.js",
    "start": "node server.js"
  },
  "dependencies": {
    "express": "^5.1.0"
  }
}
```

- `"type": "module"` lets you use `import` and `export` in `.js` files.
- `npm run dev` starts the server and restarts it every time you save a file.
- `npm start` starts the server once. Real servers in the cloud use this one.

Easy way to remember: **install** once (`npm install`), **dev** while you code (`npm run dev`), **Ctrl + C** to stop.

**Simple lesson:** `npm init`, `npm install express`, then add `"type": "module"`.

## Splitting app.js and server.js

Real projects keep two small files instead of one.

- **app.js** = builds the app: the routes and settings. It does not start anything.
- **server.js** = starts the app with `app.listen`.
- Tests can import `app.js` without starting a real server.
- Later, you can start the same app in different ways.

- The terminal runs `npm start`, which runs `node server.js`.
- `server.js` imports the app from `./app.js`. Note the `.js` at the end.
- Node.js needs the full file name when you use `import`.

**Simple lesson:** app.js describes the app. server.js switches it on.

## Environment Configuration

Some values change from computer to computer, such as the port or a database password.

- Do not type these values into your code.
- Keep them in **environment variables** instead.
- **Environment variable** = a named value the computer gives your program.
- Node.js puts them all in `process.env`.
- Every value in `process.env` is a string, such as `"4000"`.

### The .env File

During development, you keep these values in a file named `.env`.

```bash
PORT=4000
CANTEEN_NAME=Green Valley School Canteen
```

### Loading .env

Node.js does not read `.env` by itself. Pick **one** of these two ways.

- **Node.js 20.6 or later:** run `node --env-file=.env server.js`.
- **The dotenv package:** run `npm install dotenv`, then add `import "dotenv/config";` at the top of `server.js`.
- Do not use both. Two loaders make it hard to know where a value came from.

- The server listens on **4000**, the value from `.env`.
- Open the `.env` tab, change `PORT` to `5000`, and press Run again.
- Then delete the `PORT` line. The server falls back to **3000**.

### Keeping .env Secret

- Add `.env` to your `.gitignore` file, so Git never uploads it.
- Create `.env.example` with the same names but no real values.
- Teammates copy `.env.example` to `.env` and fill in their own values.

```bash
# .env.example
PORT=3000
CANTEEN_NAME=
```

Never push `.env` to GitHub. Bots scan public code for passwords within minutes.

**Simple lesson:** Settings live in `.env`, your code reads them from `process.env`, and Git never sees `.env`.

## Development Tools

You need a way to send requests to your server while you build it.

- **node --watch:** restarts the server when you save a file. `npm run dev` uses it.
- **Browser:** good for quick `GET` requests. Type `http://localhost:3000/menu`.
- **curl:** a terminal command that sends any request. It is built into Windows, macOS and Linux.
- **Postman:** a popular app for sending and saving requests.
- **Bruno:** a free, open-source app like Postman. It saves requests as files in your project.

Try these curl commands while your server runs:

```bash
curl http://localhost:3000/
curl http://localhost:3000/menu
curl -i http://localhost:3000/hello
```

- `curl URL` prints the response body.
- `curl -i URL` also prints the status line and headers.

In this course, the **Send** panel in each lab works like a tiny Postman.

**Simple lesson:** Use the browser for quick checks and curl, Postman or Bruno for everything else.

## Starter Project Files

Your finished starter project looks like this:

```text
canteen-api/
├── node_modules/      packages downloaded by npm (never edit)
├── .env               your settings and secrets (never commit)
├── .env.example       the same names, no real values (commit this)
├── .gitignore         files Git should ignore
├── app.js             builds the Express app and its routes
├── package.json       name, scripts and packages
├── package-lock.json  exact package versions (made by npm)
└── server.js          starts the server
```

The `.gitignore` file needs only two lines for now:

```bash
node_modules
.env
```

**Simple lesson:** Five small files are enough to start any Express project.

## Your First Express Application, Step by Step

Here is the full `app.js` and `server.js` again. Every line is explained below.

### The Pieces

- **express()** = creates the **application object**, usually called `app`.
- **app.get(path, handler)** = adds a route for `GET` requests to that path.
- **Route handler** = the function that runs when the route matches.
- **req** = the request object. `req.query.name` reads `?name=Priya`.
- **res** = the response object. `res.send()` sends text, HTML or JSON.
- **Port** = a door number on the computer. Your server listens at door 3000.
- **app.listen(port, callback)** = starts the server. The callback runs once it is ready.

Try `/greet?name=Priya`, then `/greet` with no name. The `||` gives a default value.

### Stopping and Restarting

- Press **Ctrl + C** in the terminal to stop the server.
- Run `npm run dev` (or `node server.js`) to start it again.
- With `--watch`, saving a file restarts the server for you.
- Without `--watch`, you must stop and start the server to see changes.

In this lab, **↻ Restart** does the same as stopping and starting.

**Simple lesson:** Create the app, add routes, then listen on a port.

## Fixing Common Startup Errors

When a server will not start, the terminal tells you why. Read the first error line.

Press Run. The terminal shows `ERR_MODULE_NOT_FOUND`.

- The import says `"./app"`, but the file is `app.js`.
- Change it to `"./app.js"` and run again.

### The Errors You Will Meet Most

- **Cannot find module './app':** add the `.js` ending to the import.
- **Cannot find package 'express':** run `npm install express` in the project folder.
- **Warning: MODULE_TYPELESS_PACKAGE_JSON** (older Node.js shows **Cannot use import statement outside a module**): add `"type": "module"` to `package.json`.
- **EADDRINUSE: address already in use :::3000:** another server already uses port 3000. Stop it, or pick another port.
- **The server starts on the wrong port:** `.env` was not loaded. Use `--env-file=.env` or `import "dotenv/config"`.

Copy the first error line into your search engine. Someone has almost always met it before.

**Simple lesson:** Read the first line of the error. It usually names the exact problem.

## Common mistakes

<div className="tscroll">

| Mistake | Wrong idea | Correct idea | What goes wrong |
|---|---|---|---|
| `import app from "./app"` | Node.js adds `.js` for you | ES modules need the full file name | `ERR_MODULE_NOT_FOUND` |
| No `"type": "module"` in `package.json` | `import` works in every `.js` file | Node.js must be told the file is a module | Errors or warnings about module type |
| Running `node server.js` outside the project | Node.js finds your project anywhere | Commands run in the current folder | `Cannot find module` |
| Forgetting to load `.env` | Node.js reads `.env` by itself | Use `--env-file=.env` or `dotenv` | `process.env.PORT` is `undefined` |
| Committing `.env` to Git | It is just a settings file | It holds secrets | Passwords leak online |
| Two servers on port 3000 | Many servers can share a port | One port, one server | `EADDRINUSE` |
| Copying Express 4 paths like `"*"` or `"/:id?"` | All Express code is the same | Express 5 uses `"/*splat"` and `"{/:id}"` | `TypeError` at startup |
| Editing files and expecting changes | The server reloads by itself | Restart, or use `node --watch` | You see old answers |

</div>

## Check Yourself

## Exercises

## What to Remember

- Express is a small, unopinionated framework for web servers on Node.js.
- It adds routing, middleware and easy `req` and `res` helpers to the http module.
- This course uses Express 5, which needs Node.js 18 or later and newer path syntax.
- Start a project with `npm init -y`, `npm install express` and `"type": "module"`.
- Read settings from `process.env`, load `.env` one way only, and never commit it.
- A first server is three steps: `express()`, `app.get(...)`, `app.listen(...)`.

Next: **HTTP Fundamentals**. You will learn what requests, responses, methods and status codes really are.
