Skip to main content

Command Palette

Search for a command to run...

How I Built a Simple Blog App with Node.js, Express, EJS & JSON (as a Mini Database)

Published
5 min read

Nice, let’s turn this into a proper Hashnode article you can copy-paste and tweak.
I’ll write it in Markdown so you can drop it straight into Hashnode’s editor.


# How I Built a Simple Blog App with Node.js, Express, EJS & JSON (as a Mini Database)

I recently built a small full-stack blog application using **Node.js**, **Express**, **EJS**, and **JSON** as a mini database.  
In this post, I’ll walk you through what I built, how it works, and what I learned along the way.

> 💡 I used a *little bit* of AI help for UI ideas and styling suggestions, but all the logic, structure, and implementation was done by me.

---

## 🧩 What I Built

The project is a **simple blog platform** where you can:

- ✍️ **Create** a blog post  
- 📄 **View** each blog on its own page  
- 🗑 **Delete** a blog  
- 🌓 Enjoy a **clean dark-themed UI**

I wanted something that feels like a “mini Medium clone” but with very simple tech and no heavy database — so I used a **JSON file** to store all the blog data.

---

## 🛠 Tech Stack

- **Node.js** – JavaScript runtime for the backend  
- **Express.js** – web framework for routing and middleware  
- **EJS** – template engine for rendering dynamic HTML  
- **JSON + fs** – used as a tiny database for storing blog posts  
- **CSS** – custom dark theme styling  
- **body-parser** – to handle form submissions  

---

## 🧱 Project Structure

Here’s a simplified version of the folder layout:

```bash
project/
├── public/
│   └── styles/
│       └── index.css          # main styling
│
├── views/
│   ├── index.ejs              # home page (list of blogs)
│   ├── blog.ejs               # single blog view
│   ├── create-blog.ejs        # create form
│   ├── about.ejs              # about page
│   └── partials/
│       └── navbar.ejs         # navigation bar
│
├── blogs.json                 # JSON storage for blogs
├── index.js                   # main Express server
└── package.json

📦 Storing Blogs in JSON

Instead of using a real database like MongoDB or PostgreSQL, I decided to store my posts in a simple JSON file called blogs.json.

A single blog post looks like this:

{
  "id": 1712737289120,
  "title": "My First Blog",
  "content": "This is my first blog post...",
  "createdAt": "2025-04-10T12:34:49.120Z"
}

All the posts are stored as an array inside blogs.json.

To safely read the blogs without crashing when the file is empty or missing, I wrote a helper function:

import fs from "fs";

function readBlogs() {
  if (!fs.existsSync("blogs.json")) return [];
  let data = fs.readFileSync("blogs.json").toString();
  if (data.trim() === "") return [];
  return JSON.parse(data);
}

This prevents the classic:

SyntaxError: Unexpected end of JSON input

when JSON.parse is used on an empty file.


🌐 Routes Overview

These are the main Express routes I used:

import express from "express";
import bodyParser from "body-parser";
import fs from "fs";

const app = express();

app.use(bodyParser.urlencoded({ extended: true }));
app.use(express.static("public"));
app.set("view engine", "ejs");

// Home - show all blogs
app.get("/", (req, res) => {
  const blogs = readBlogs();
  res.render("index.ejs", { blogs });
});

// Create page
app.get("/create", (req, res) => {
  res.render("create-blog.ejs");
});

// Submit new blog
app.post("/submit", (req, res) => {
  const blogs = readBlogs();

  const newBlog = {
    id: Date.now(),
    title: req.body.title,
    content: req.body.content,
    createdAt: new Date()
  };

  blogs.push(newBlog);

  fs.writeFileSync("blogs.json", JSON.stringify(blogs, null, 2));

  res.redirect("/");
});

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

// Single blog page
app.get("/blog/:id", (req, res) => {
  const blogs = readBlogs();
  const blog = blogs.find(b => b.id == req.params.id);

  if (!blog) {
    return res.status(404).send("Blog not found");
  }

  res.render("blog.ejs", { blog });
});

app.listen(3000, () => {
  console.log("Server running on port 3000");
});

Later, it’s also easy to add a delete route using .filter():

app.post("/delete/:id", (req, res) => {
  const blogs = readBlogs();
  const id = req.params.id;
  const updatedBlogs = blogs.filter(blog => blog.id != id);
  fs.writeFileSync("blogs.json", JSON.stringify(updatedBlogs, null, 2));
  res.redirect("/");
});

🎨 Dark Theme UI

For the styling, I wanted a modern dark look, so I used a dark grey background and lighter cards for contrast:

body {
  background-color: #2c2c2c;
  color: #f1f1f1;
  margin: 0;
  padding: 0;
  font-family: "Poppins", sans-serif;
}

.home-container {
  width: 80%;
  max-width: 1100px;
  margin: 40px auto;
}

.blogs-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
  gap: 25px;
}

.blog-card {
  background-color: #353535;
  padding: 20px;
  border-radius: 10px;
  box-shadow: 0 0 12px rgba(0,0,0,0.25);
  transition: transform 0.2s ease, box-shadow 0.2s ease;
}

.blog-card:hover {
  transform: translateY(-4px);
  box-shadow: 0 0 18px rgba(0,0,0,0.35);
}

The individual blog page (blog.ejs) uses a centered card layout with a “Back” button and a readable content area.


🤝 Using a Little Bit of AI

I want to be honest about my process:

I wrote the logic, routes, and file handling myself, and I also structured the project and pages on my own.

I did, however, use a bit of AI assistance for:

  • refining some CSS (choosing better dark shades & spacing)

  • getting ideas for button styles and layout adjustments

  • helping phrase descriptions & README text more clearly

I treated AI like a “pair designer” and “writing assistant”, but I made sure I understood and controlled everything I built.


🧠 What I Learned

  • How to use EJS to render data from the backend into templates

  • How to safely read and write JSON files with Node’s fs module

  • How to structure a basic CRUD-like blog flow

  • How to design a consistent dark theme UI

  • The importance of handling edge cases like empty files

This project was a great hands-on exercise in full-stack JavaScript without relying on a database.


🔗 GitHub Repository

You can find the full source code here:

👉 GitHub Repo: [Add your repo link here]
Example:
https://github.com/Nimratjotsingh/blog-app-node-express-json


💬 Final Thoughts

This app is simple, but it gave me a solid understanding of:

  • sending data from the browser → server → JSON file → back to the browser

  • rendering dynamic content with EJS

  • and structuring a small but complete full-stack project.

Next steps I’m considering:

  • Moving storage from JSON to MongoDB

  • Adding edit functionality for blogs

  • Supporting Markdown for blog content

  • User authentication for personal dashboards

If you have suggestions or feedback, I’d love to hear them! 😊

Thanks for reading!
Nimratjot Singh