Skip to main content

Building a Microservice Architecture with Node.js and MongoDB

 As your application grows, a single backend often turns into a tangled mess — harder to scale, test, and deploy.

That’s where microservice architecture comes in.

Instead of one large codebase, you split your app into independent, loosely coupled services — each handling one specific business function (like users, products, or orders).


In this blog, we’ll build a simple microservice-based system using:

  • 🟒 Node.js + Express — for APIs

  • πŸƒ MongoDB — as individual service databases

  • 🐳 Docker Compose — to run them together

🧠 What Are Microservices?

Microservices are small, autonomous services that communicate over APIs.
Each service:

  • Has its own database

  • Runs independently

  • Can be scaled or deployed separately


Example: A shopping app might have:

  • πŸ‘€ User Service → handles signup/login

  • πŸ“¦ Product Service → manages items

  • πŸ›’ Order Service → processes purchases

Instead of one app handling all three, you split them like this:

[User Service][Order Service][Product Service] ↘ ↘ MongoDB MongoDB

⚙️ Step 1 — Project Setup

Let’s create a folder structure:

microservices-demo/ │ ├── user-service/ ├── product-service/ ├── order-service/ └── docker-compose.yml

Each service is its own Express + MongoDB app.


πŸ‘€ Step 2 — Creating the User Service

Inside user-service/index.js:

import express from "express"; import mongoose from "mongoose"; const app = express(); app.use(express.json()); mongoose.connect("mongodb://localhost:27017/users"); const UserSchema = new mongoose.Schema({ name: String, email: String, }); const User = mongoose.model("User", UserSchema); app.post("/users", async (req, res) => { const user = await User.create(req.body); res.json(user); }); app.listen(4001, () => console.log("User Service running on port 4001"));

What’s happening:

  • A small API that creates users in a separate database.

  • Runs on port 4001.


πŸ“¦ Step 3 — Product Service

product-service/index.js:

import express from "express"; import mongoose from "mongoose"; const app = express(); app.use(express.json()); mongoose.connect("mongodb://localhost:27017/products"); const ProductSchema = new mongoose.Schema({ name: String, price: Number, }); const Product = mongoose.model("Product", ProductSchema); app.post("/products", async (req, res) => { const product = await Product.create(req.body); res.json(product); }); app.listen(4002, () => console.log("Product Service running on port 4002"));

Each service has its own database and API — completely independent.


πŸ›’ Step 4 — Order Service & Service Communication

In order-service/index.js:

import express from "express"; import mongoose from "mongoose"; import axios from "axios"; const app = express(); app.use(express.json()); mongoose.connect("mongodb://localhost:27017/orders"); const OrderSchema = new mongoose.Schema({ userId: String, productId: String, status: String, }); const Order = mongoose.model("Order", OrderSchema); app.post("/orders", async (req, res) => { const { userId, productId } = req.body; // Communicate with other services const user = await axios.get(`http://localhost:4001/users/${userId}`); const product = await axios.get(`http://localhost:4002/products/${productId}`); const order = await Order.create({ userId, productId, status: "Created", }); res.json({ message: "Order created successfully", order, user: user.data, product: product.data, }); }); app.listen(4003, () => console.log("Order Service running on port 4003"));

Key concept:
Services communicate via HTTP. Later, you could upgrade this to message queues (RabbitMQ, Kafka) for better scalability.


πŸ”— Step 5 — Adding an API Gateway (Optional but Recommended)

Instead of calling each service directly, create an API Gateway.

gateway/index.js:

import express from "express"; import { createProxyMiddleware } from "http-proxy-middleware"; const app = express(); app.use("/users", createProxyMiddleware({ target: "http://localhost:4001", changeOrigin: true })); app.use("/products", createProxyMiddleware({ target: "http://localhost:4002", changeOrigin: true })); app.use("/orders", createProxyMiddleware({ target: "http://localhost:4003", changeOrigin: true })); app.listen(4000, () => console.log("API Gateway running on port 4000"));

Now, your frontend can just call:

http://localhost:4000/users http://localhost:4000/products http://localhost:4000/orders

🐳 Step 6 — Dockerize Everything

Create a Dockerfile for each service:

FROM node:18 WORKDIR /app COPY package*.json ./ RUN npm install COPY . . CMD ["npm", "start"]

Then a docker-compose.yml at the root:

version: "3" services: user-service: build: ./user-service ports: - "4001:4001" product-service: build: ./product-service ports: - "4002:4002" order-service: build: ./order-service ports: - "4003:4003" gateway: build: ./gateway ports: - "4000:4000"

Run it all with:

docker compose up --build

πŸ”’ Step 7 — Authentication & Security (Next Steps)

To make this production-ready:

  • Add JWT authentication via a dedicated Auth service.

  • Use service-to-service tokens for internal requests.

  • Secure your databases and API Gateway.


πŸ“ˆ Step 8 — Testing the System

Use Postman or Thunder Client:

  1. Create a user → POST /users

  2. Create a product → POST /products

  3. Create an order → POST /orders (include userId + productId)

  4. Verify responses and linked data

You’ll see independent services working together like a small distributed system.


🧭 Conclusion

Congratulations — you just built a microservice architecture using Node.js and MongoDB! πŸŽ‰

You learned:

  • How to separate services by domain

  • Communicate using REST APIs

  • Deploy with Docker Compose

  • Use an API Gateway for unified routing

πŸ’‘ Tip: For larger projects, explore message queues (RabbitMQ, Kafka), Kubernetes, and service discovery for even more scalable setups.


✍️ Final Thoughts

Microservices aren’t always necessary — for small apps, monoliths are faster to build.
But if you’re planning for growth, scalability, or team collaboration, microservices give you that flexibility.

“Build small, deploy often, scale independently.”

Comments

Popular posts from this blog

Inside the MERN Stack: How MongoDB, Express, React & Node Work Together

If you’re stepping into full-stack development, chances are you’ve heard of the **MERN stack**. It’s one of the most popular technology stacks today, powering everything from small projects to enterprise-level applications. But how do these four technologies fit together? Let’s break it down step by step.    --- ### πŸ”Ή The Four Pillars of MERN   1. MongoDB (Database Layer)    - A NoSQL database that stores data in flexible, JSON-like documents.      - Perfect for handling dynamic, unstructured data.      - Example: A user profile `{ name: "John", age: 25 }` is stored as a document in MongoDB.   2. Express.js (Backend Framework)       - A lightweight framework built on Node.js.      - Handles HTTP requests, routes, and middleware.      - Example: When a user submits a form, Express processes the request and decides what to do with the data. ...