Getting Started with Express.js: The Basics

posted Originally published at dev.to 3 min read

When you first dive into backend development with Node.js, it doesn’t take long before you bump into Express.js. It’s practically the default framework for building web servers and APIs in JavaScript, and for good reason, it simplifies the otherwise clunky task of handling requests, responses, and routes.

In this article, we’ll take a thorough look at Express:

  • what it is and why it exists,
  • how to set up a simple project,
  • how routing works in practice,
  • and a few must-know tricks to get you comfortable.

This will lay the foundation for the next article in the series (Part 2), where we’ll unlock the real magic of Express: middleware.


Why Use Express.js Instead of Plain Node?

You might be thinking: “Wait, Node.js can already create servers, why do I need Express?”

That’s true, but here’s what a basic raw Node server looks like:

const http = require("http")

const server = http.createServer((req, res) => {
  if (req.url === "/" && req.method === "GET") {
    res.writeHead(200, { "Content-Type": "text/plain" })
    res.end("Home Page")
  } else if (req.url === "/users" && req.method === "GET") {
    res.writeHead(200, { "Content-Type": "text/plain" })
    res.end("Users Page")
  } else {
    res.writeHead(404, { "Content-Type": "text/plain" })
    res.end("Not Found")
  }
})

server.listen(3000, () => {
  console.log("Server running on http://localhost:3000")
})

It works, but it gets messy fast. You have to manually check URLs, methods, and headers.

Now look at the equivalent in Express:

const express = require("express")
const app = express()

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

app.get("/users", (req, res) => {
  res.send("Users Page")
})

app.listen(3000, () => {
  console.log("Server running on http://localhost:3000")
})

Much cleaner. Express handles the boilerplate for you so you can focus on logic.


Setting Up Express

  • Create a project folder and initialize it:
mkdir express-intro
cd express-intro
npm init -y
  • Install Express:
npm install express
  • Create a file called server.js and add:
const express = require("express")
const app = express()

// A simple route
app.get("/", (req, res) => {
  res.send("Hello from Express!")
})

// Start the server
app.listen(3000, () => {
  console.log("Listening on http://localhost:3000")
})
  • Run the server:
node server.js

Go to http://localhost:3000 and boom, you’ve got a web server.


How Routing Works in Express

Express gives you an intuitive way to define routes. A route is just a combination of an HTTP method and a path.

GET Requests

app.get("/about", (req, res) => {
  res.send("About page")
})

Visiting http://localhost:3000/about will trigger this function.

POST Requests

app.post("/submit", (req, res) => {
  res.send("Form submitted")
})

This would respond when you submit a form with POST /submit.

Dynamic Routes

You can use route parameters:

app.get("/users/:id", (req, res) => {
  res.send(`User ID: ${req.params.id}`)
})

Visiting http://localhost:3000/users/42 would return User ID: 42.

Query Parameters

Express makes query strings easy too:

app.get("/search", (req, res) => {
  const term = req.query.q
  res.send(`You searched for: ${term}`)
})

Visiting http://localhost:3000/search?q=node responds with You searched for: node.


Serving Static Files

What if you want to serve an HTML file or an image? Express has you covered:

app.use(express.static("public"))

Now any files in your public/ folder (like index.html or style.css) will be automatically served.
For example: http://localhost:3000/style.css → serves /public/style.css.


Sending JSON Responses

Since APIs often need to send JSON, Express makes this trivial:

app.get("/api/users", (req, res) => {
  res.json([
    { id: 1, name: "Alice" },
    { id: 2, name: "Bob" }
  ])
})

Visiting /api/users will give you structured JSON, no extra setup required.


Handling 404 Errors

It’s a good practice to handle unknown routes:

app.use((req, res) => {
  res.status(404).send("Sorry, page not found")
})

This will catch any route that wasn’t matched earlier.


Why Express Feels So Flexible

The magic of Express is its simplicity. It doesn’t force you into a strict structure. You can:

  • Start with just a single file for a prototype.
  • Gradually break routes into separate files as your app grows.
  • Add middlewares for logging, authentication, validation, and more (coming in Part 2).

It’s like Lego blocks: small and simple by themselves, but powerful when combined.


What’s Next: Middleware

So far, we’ve built an Express app that can:

  • serve routes,
  • return text, HTML, or JSON,
  • handle query strings and parameters,
  • and even serve static files.

But every real-world app has “stuff” that needs to happen before (or after) a request hits your route handler: logging, authentication, input validation, error handling.

That’s where middlewares come in.

In Part 2, we’ll break down middlewares in detail how they works, how to write your own, and how to avoid common mistakes. That’s when Express really starts to shine.

If you read this far, tweet to the author to show them you care. Tweet a Thanks
0 votes
0 votes

More Posts

Getting Started with Backend Development: Web Servers, Node.js, and Bun Explained

Santwan pathak - Jul 20

Handling Different Types of Data in Express.js

Riya Sharma - Jun 26

How to Connect MongoDB to Node.js with Mongoose (Step-by-Step Guide)

Riya Sharma - Jun 14

Strengthening Web Security with HTTP Headers in Express.js

mariohhd - Aug 19

How to set up TypeScript with Node.js and Express (2025)

Sunny - Jun 6
chevron_left