Express.js Tutorial: Build a Hello World App

The terminal prints listening on port 3101 after PORT=3101 node app.js, and a request to / returns Home Page. I want to separate the code that answers the request from the process that accepts it.

Let the Home Page response guide you back to its route. See how Express matches the request to a handler.

What Express.js adds to Node.js

Node.js runs JavaScript outside a browser. Express.js is a web framework that adds routing and middleware to a Node.js app, so you can match a Hypertext Transfer Protocol (HTTP) request and return a page or an application programming interface (API) response.

An Express route matches a request method and path before it calls a handler. The Express routing guide describes that pair as the basis for route selection.

An Express handler can return text or serialize an object as JavaScript Object Notation (JSON). It can also send a Hypertext Markup Language (HTML) file.

LayerWhat it does in this example
Node.jsRuns the JavaScript process and provides the server runtime.
Express.jsMatches request methods and paths, then runs middleware and route handlers.

What you need before the first route

Express 5 requires Node.js 18 or later and a package manager such as npm. The CodeForGeek Node.js setup tutorial covers the runtime setup, and the Express installation guide lists the supported Node.js requirement.

node --version
npm --version

The version commands print their results so you can check both tools before creating the project.

Build and run a Hello World app

The app exposes a root route and a GET route for JSON. It accepts a POST body and returns an HTML file, so register the body parser before any route that reads it.

1. Create the project

Create a project directory and write its package manifest. Then add Express without choosing a fixed version.

mkdir express-hello
cd express-hello
npm init -y
npm install express
mkdir public

The package manifest records Express as a project dependency. The public directory will hold the HTML file returned by one route.

2. Add the Express routes

Create app.js with the middleware and route handlers. The route method and path decide which handler receives a request.

const express = require('express');
const path = require('node:path');

const app = express();
const port = Number(process.env.PORT || 3000);

app.use(express.json());

app.get('/', (req, res) => {
  res.send('Home Page');
});

app.get('/jsonResponse', (req, res) => {
  res.json({
    status: 'success',
    message: 'This request was successfully processed'
  });
});

app.post('/echo', (req, res) => {
  res.status(201).json({ received: req.body });
});

app.get('/front-end', (req, res) => {
  res.sendFile('index.html', { root: path.join(__dirname, 'public') });
});

app.listen(port, () => {
  console.log(`listening on port ${port}`);
});

I kept express.json() above the route handlers because middleware runs in registration order, and the POST handler needs the parsed body before it can respond. The root and JSON routes match GET, while /echo matches POST, so a request with another method does not reach this handler.

The Express middleware guide puts middleware in the request-response cycle. A middleware can modify the request or response, then end the cycle or pass control onward with next().

3. Return an HTML file

Create public/index.html, then use sendFile to return that file from the /front-end route. The root option keeps the file lookup inside the public directory.

<!doctype html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <title>Front-End Page</title>
</head>
<body>
  <h1>Hello from Front-End</h1>
</body>
</html>

Keep the server running in one terminal while you send requests from a second.

PORT=3101 node app.js
curl -sS -i http://localhost:3101/
curl -sS -i http://localhost:3101/front-end

The root route returns Home Page. Express sends that text for a GET request to /.

Browser output showing the Home Page response from an Express route
The root route returns Home Page when a browser requests /.

The /front-end route sends the heading from public/index.html. Its response comes from the file rather than the root handler’s text.

Static page returned by the /front-end route with a Hello from Front-End heading
The route returns the HTML file’s visible heading.

The Express sendFile API accepts an absolute path or a root option, and this example supplies the public directory as the root. When you need to serve a directory of assets, express.static() provides middleware for that job.

4. Return JSON from GET and POST routes

The GET route sends a JSON object without a request body. The POST route reads a JSON body, then returns it with status 201.

curl -sS -i http://localhost:3101/jsonResponse
JSON response from /jsonResponse containing status success and a message
The JSON route returns the status and message properties in its response.

The GET route sends JSON to the client. The POST route sends JSON in the request body.

curl -sS -i -X POST http://localhost:3101/echo -H 'Content-Type: application/json' -d '{"message":"Hello"}'

I ran the POST request with the application/json content type, and Express returned status 201 with the submitted message inside received. Without express.json() before the route, the handler would not have that parsed body.

Express POST /echo response showing HTTP 201 Created and returned JSON
POST /echo returns status 201 and places the submitted body under received.

The response body contains the parsed message, and the status line shows that the route returned 201 Created.

When the browser cannot connect

Compare the error type before changing code, because a refused connection and a 404 come from different layers.

  • Connection refused: no process accepted the connection at that host and port. Check that the server is still running and that the browser address uses the port printed by app.listen().
  • Route or file not found: a 404 means the server answered but did not find the requested route or file. Check the method and path, then check the file path for sendFile routes.
  • Missing POST body: send the application/json content type and register express.json() before the route that reads req.body.

A reader describing “localhost refused to connect” is seeing a listener or port problem, not a route-level 404. The terminal error has no HTTP status because no server answered.

curl -sS -i --connect-timeout 2 http://localhost:31999/
Curl error 7 after a request to localhost:31999
Curl error 7 means the connection to localhost:31999 failed before any HTTP response.

Curl error 7 means it could not connect to the server at localhost:31999. That request never reached an Express route.

curl -sS -i http://localhost:3101/missing
Express 404 Not Found response for GET /missing
Express answered the request, but no route matches GET /missing.

The /missing request reaches Express and returns a 404 because no route matches that path.

Follow a request from path to response

A route is the method and path that select a handler. Once you can trace that match, middleware and response methods have a clear place in the request flow.

Change the root handler’s response text, then send the same request again. The route stays the same while its handler supplies a different response.

curl -sS -i http://localhost:3101/

Express.js questions

These answers focus on the first app and the Node.js knowledge it uses.

What is Express.js used for?

Express.js adds routing and middleware to Node.js web applications, so a handler can return a page or a JSON response. A handler can also send a file for a matching request.

How much Node.js should I know before Express.js?

For this app, you need basic JavaScript plus Node.js and npm. You can add route and middleware concepts while building the app without learning every Node.js feature first.

How long does it take to learn Express.js?

There is no fixed time that fits every project. Once Node.js and npm are available and you know basic JavaScript, you can run a first route and learn the pieces your app needs.

Sushant Dhiman
Sushant Dhiman

Sushant Dhiman writes beginner-friendly Flutter and Dart tutorials covering widgets, layouts, navigation, dialogs, and state. He also covers Node.js, Express, and jQuery fundamentals.

Articles: 14