Introduction
One of the most common tasks when building a web server is serving HTML pages to web browsers. Using Node.js's built-in http module along with the fs (File System) module, you can read HTML files from your project and send them as HTTP responses. This approach forms the foundation of traditional server-side web applications before using frameworks such as Express.
Information
Learning Objectives
- Create an HTTP server.
- Read HTML files using the fs module.
- Send HTML content to the browser.
- Serve multiple HTML pages using routing.
- Handle missing files and server errors gracefully.
Project Structure
Creating a Simple HTML File
index.html
<!DOCTYPE html>
<html>
<head>
<title>Home</title>
</head>
<body>
<h1>Welcome to My Website</h1>
<p>This page is served using Node.js.</p>
</body>
</html>Serving a Single HTML File
Use the fs.readFile() method to read an HTML file asynchronously and send its contents to the client.
server.js
const http = require("http");
const fs = require("fs");
const server = http.createServer((req, res) => {
fs.readFile("index.html", (err, data) => {
if (err) {
res.writeHead(500, {
"Content-Type": "text/plain"
});
return res.end("Internal Server Error");
}
res.writeHead(200, {
"Content-Type": "text/html"
});
res.end(data);
});
});
server.listen(3000, () => {
console.log("Server running at http://localhost:3000");
});How It Works
Serving Multiple HTML Pages
Combine routing with file reading to serve different HTML pages for different URLs.
Serving multiple pages
const http = require("http");
const fs = require("fs");
const server = http.createServer((req, res) => {
let filePath = "";
if (req.url === "/") {
filePath = "index.html";
} else if (req.url === "/about") {
filePath = "about.html";
} else if (req.url === "/contact") {
filePath = "contact.html";
} else {
filePath = "404.html";
}
fs.readFile(filePath, (err, data) => {
if (err) {
res.writeHead(500, {
"Content-Type": "text/plain"
});
return res.end("Internal Server Error");
}
const statusCode = filePath === "404.html" ? 404 : 200;
res.writeHead(statusCode, {
"Content-Type": "text/html"
});
res.end(data);
});
});
server.listen(3000);Routing Flow
Understanding fs.readFile()
| Parameter | Description |
|---|---|
| path | Path to the file to be read. |
| callback | Function executed after reading the file. |
| err | Contains an error if the operation fails. |
| data | Contains the file contents as a Buffer by default. |
Reading Files as Text
If you want the file contents as a string instead of a Buffer, specify an encoding such as utf8.
Read file with UTF-8 encoding
fs.readFile("index.html", "utf8", (err, data) => {
if (err) {
return;
}
console.log(data);
});HTTP Status Codes
| Status Code | Meaning | Usage |
|---|---|---|
| 200 | OK | HTML page served successfully. |
| 404 | Not Found | Requested page does not exist. |
| 500 | Internal Server Error | Unable to read the requested file. |
Testing the Server
- Create the required HTML files.
- Run the server using node server.js.
- Open http://localhost:3000 in a browser.
- Visit /about and /contact.
- Request an unknown URL to verify the custom 404 page.
Advantages
- No external dependencies are required.
- Simple and easy to understand.
- Ideal for learning HTTP servers and file handling.
- Works well for small websites and educational projects.
Limitations
- Manual routing becomes difficult as applications grow.
- Each request reads files from disk unless caching is implemented.
- No built-in support for templates or layouts.
- Static assets such as CSS and JavaScript require additional routing.
Warning
Best Practices
- Always set the correct Content-Type header.
- Handle file read errors gracefully.
- Return a custom 404 page for unknown routes.
- Use asynchronous file operations to avoid blocking the event loop.
- Organize HTML files in a dedicated directory such as public or views as the project grows.
Best Practice
Official Documentation
Node.js HTTP Module Documentation and Node.js File System (fs) Module Documentation