Skip to content

Your First Express Server

This lesson walks through building a complete, working Express server from an empty file, then testing it in the browser and with curl. By the end you will have a real server responding to multiple routes.

Writing Your First Server

A minimal Express server needs three things: an app created from express(), at least one route, and a call to app.listen() with a port number. Everything else builds on top of that foundation.

Save the following as server.js inside a project where you have already run npm install express.

const express = require('express');
const app = express();
const PORT = 3000;

app.get('/', (req, res) => {
  res.send('Hello, Express!');
});

app.listen(PORT, () => {
  console.log(`Server running at http://localhost:${PORT}`);
});

Run this with node server.js, then open http://localhost:3000 in a browser to see "Hello, Express!".

Adding More Routes

app.get('/about', (req, res) => { ... });
app.get('/users', (req, res) => { ... });
app.post('/users', (req, res) => { ... });
  • Add as many app.get()/app.post() calls as you need, each targeting a different path.
  • Route order matters, more specific paths should generally come before generic catch-alls.
  • Use res.json() instead of res.send() when returning structured API data.
  • Restart the server (or use nodemon) after every change to see updates.

First Server Cheatsheet

The handful of methods that make up almost every first Express server.

Method Example Result
Plain text res.send('Hi') Sends a plain text/HTML response
JSON res.json({ ok: true }) Sends a JSON response with correct headers
Status code res.status(404).send('Not found') Sets HTTP status before sending
Route param app.get('/users/:id', ...) Captures :id into req.params.id
Start server app.listen(3000, cb) Starts listening, runs cb once ready

Testing Your Server

You can test GET routes directly in a browser, but for other methods, or for quick scripting, curl is the fastest tool.

curl http://localhost:3000/
curl http://localhost:3000/users
curl -X POST http://localhost:3000/users \
  -H "Content-Type: application/json" \
  -d '{"name":"Ada"}'

The -X POST flag sets the method, -H sets a header, and -d sends a JSON body.

A Slightly Bigger Example

Real servers combine several routes, JSON parsing, and a not-found fallback. Here is a small but realistic starting point.

const express = require('express');
const app = express();

app.use(express.json());

const users = [{ id: 1, name: 'Ada' }];

app.get('/users', (req, res) => {
  res.json(users);
});

app.post('/users', (req, res) => {
  const user = { id: users.length + 1, name: req.body.name };
  users.push(user);
  res.status(201).json(user);
});

app.use((req, res) => {
  res.status(404).json({ error: 'Not found' });
});

app.listen(3000);

Common Mistakes

  • Forgetting express.json() and then reading req.body as undefined on POST requests.
  • Using the same port as another running process, causing an EADDRINUSE error.
  • Not checking the terminal for the "Server running" log to confirm the server actually started.
  • Testing POST/PUT/DELETE routes by pasting the URL into a browser address bar, which only sends GET.

Key Takeaways

  • A minimal server needs express(), at least one route, and app.listen().
  • res.send() is for simple text/HTML, res.json() is for structured API data.
  • curl lets you test any HTTP method, not just GET, from the command line.
  • A catch-all app.use() at the end of your routes is a simple way to handle unmatched paths.

Pro Tip

Log the full URL, not just the port, from your listen() callback (e.g. http://localhost:${PORT}), so you can click it directly in most terminals instead of retyping it.