DEV Community

Cover image for Microservices vs. Micro Frontends: What's the Difference?
Pavan Belagatti
Pavan Belagatti

Posted on

Microservices vs. Micro Frontends: What's the Difference?

In the ever-evolving landscape of software development, two groundbreaking architectural styles, microservices, and micro frontends, have emerged as transformative paradigms. These methodologies have been redefining the way modern applications are built and deployed. Embracing the principles of modularity, scalability, and flexibility, both microservices and micro frontends have become favored choices among development teams worldwide.

Whether you are a seasoned developer or just beginning your journey into the world of software architecture, this guide aims to equip you with a comprehensive understanding of microservices and micro frontends, and how they can elevate your application development to new heights.

What are Microservices?

Microservices is an architectural style where a monolithic application is divided into several small, loosely coupled, and independent services. All these microservices work together to form a larger system. Each service in a microservices architecture represents a specific business capability and operates as a separate unit with its own database and logic.

Microservices Tutorial

Step 1: Setting Up the Project

Create a new folder for your project and initialize a new Node.js project. Open a terminal and run the following commands:

mkdir microservices-tutorial
Enter fullscreen mode Exit fullscreen mode
cd microservices-tutorial
Enter fullscreen mode Exit fullscreen mode
npm init -y
Enter fullscreen mode Exit fullscreen mode

Step 2: Install Dependencies

We will use Express.js and Axios for this tutorial. Install them using npm:

npm install express axios
Enter fullscreen mode Exit fullscreen mode

Step 3: Create Microservices

For this tutorial, we'll create two microservices: a "users" service and an "orders" service. The "users" service will handle user-related operations, while the "orders" service will handle order-related operations.

Create two folders, "users" and "orders," inside the main project folder. Inside each folder, create an index.js file.

Step 4: Implement Microservices

Let's start by implementing the "users" service. Open the users/index.js file and add the following code:

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

app.get('/users', (req, res) => {
  const users = [
    { id: 1, name: 'John Doe' },
    { id: 2, name: 'Jane Smith' },
    { id: 3, name: 'Bob Johnson' },
  ];
  res.json(users);
});

app.listen(port, () => {
  console.log('Users service is running on port ' + port);
});
Enter fullscreen mode Exit fullscreen mode

Now, let's implement the "orders" service. Open the orders/index.js file and add the following code:

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

app.get('/orders', (req, res) => {
  const orders = [
    { id: 1, product: 'Product A' },
    { id: 2, product: 'Product B' },
    { id: 3, product: 'Product C' },
  ];
  res.json(orders);
});

app.listen(port, () => {
  console.log('Orders service is running on port ' + port);
});
Enter fullscreen mode Exit fullscreen mode

Step 5: Communicating Between Microservices

In this step, we will use Axios to make HTTP requests from one microservice to another. We'll modify the "users" service to fetch orders from the "orders" service.

Open the users/index.js file again and add the following code:

const express = require('express');
const axios = require('axios');
const app = express();
const port = 3000;
const ordersServiceURL = 'http://localhost:4000';

app.get('/users', async (req, res) => {
  try {
    const response = await axios.get(`${ordersServiceURL}/orders`);
    const orders = response.data;

    const users = [
      { id: 1, name: 'John Doe', orders: orders.slice(0, 2) },
      { id: 2, name: 'Jane Smith', orders: orders.slice(1, 3) },
      { id: 3, name: 'Bob Johnson', orders: orders.slice(0, 1) },
    ];

    res.json(users);
  } catch (error) {
    res.status(500).json({ error: 'Internal server error' });
  }
});

app.listen(port, () => {
  console.log('Users service is running on port ' + port);
});
Enter fullscreen mode Exit fullscreen mode

Step 6: Run the Microservices

To run the microservices, open two separate terminals, navigate to the project folder, and run the following commands:

For the "users" service:

cd users
Enter fullscreen mode Exit fullscreen mode
node index.js
Enter fullscreen mode Exit fullscreen mode

For the "orders" service:

cd orders
Enter fullscreen mode Exit fullscreen mode
node index.js
Enter fullscreen mode Exit fullscreen mode

Step 7: Test the Microservices

Open your web browser or use a tool like Postman to test the microservices.

To test the "users" service, navigate to http://localhost:3000/users. It should return a list of users along with their associated orders.

To test the "orders" service, navigate to http://localhost:4000/orders. It should return a list of orders.

Congratulations! You've successfully created a basic microservices architecture using Node.js, Express.js, and Axios, where two microservices communicate with each other to fulfill a user request.

What are Micro Frontends?

Micro Frontends is a web development architectural pattern that extends the principles of microservices to the frontend of web applications. It involves breaking down the user interface of a web application into smaller, loosely coupled, and independently deployable frontend modules. Each module represents a distinct feature or functionality of the application and can be developed, tested, and deployed independently.

Micro Frontends Tutorial

Let's see how micro frontends work practically with a simple tutorial.

In this example, we will use Express.js to create a server that serves the individual microfrontends as static files. We also use the http-proxy-middleware library to proxy requests to the appropriate microfrontend based on the URL path. Let's get going!!!

Step 1: Set Up the Microfrontend Architecture

Create a new directory for your project and initialize a new Node.js project:

mkdir microfrontend-example
Enter fullscreen mode Exit fullscreen mode
cd microfrontend-example

Enter fullscreen mode Exit fullscreen mode
npm init -y

Enter fullscreen mode Exit fullscreen mode

Step 2: Install Dependencies

Install the required dependencies for your microfrontend project:

npm install express
Enter fullscreen mode Exit fullscreen mode
npm install express-http-proxy
Enter fullscreen mode Exit fullscreen mode

Step 3: Create the Microfrontends

In this tutorial, we'll create two microfrontends: frontend1 and frontend2.

Inside the project directory, create a frontend1 directory with an index.html file:

<!-- frontend1/index.html -->
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Frontend 1</title>
</head>
<body>
  <h1>Frontend 1</h1>
</body>
</html>

Enter fullscreen mode Exit fullscreen mode

Similarly, create a frontend2 directory with an index.html file:

<!-- frontend2/index.html -->
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Frontend 2</title>
</head>
<body>
  <h1>Frontend 2</h1>
</body>
</html>
Enter fullscreen mode Exit fullscreen mode

Step 4: Create the Microfrontend Server

Create a new file named server.js in the project root directory:

// server.js
const express = require('express');
const { createProxyMiddleware } = require('http-proxy-middleware');

const app = express();

// Serve frontend1
app.use('/frontend1', express.static('frontend1'));

// Serve frontend2
app.use('/frontend2', express.static('frontend2'));

// Proxy requests to the appropriate microfrontend
app.use('/microfrontend1', createProxyMiddleware({ target: 'http://localhost:3000/frontend1', changeOrigin: true }));
app.use('/microfrontend2', createProxyMiddleware({ target: 'http://localhost:3000/frontend2', changeOrigin: true }));

// Start the server
app.listen(3000, () => {
  console.log('Microfrontend server started on port 3000');
});
Enter fullscreen mode Exit fullscreen mode

Step 5: Start the Microfrontend Server
In the terminal, run the following command to start the microfrontend server:

node server.js
Enter fullscreen mode Exit fullscreen mode

Step 6: Access the Microfrontends
Open your browser and visit http://localhost:3000/microfrontend1 to see frontend1, and http://localhost:3000/microfrontend2 to see frontend2.

Congratulations! You have successfully created a simple microfrontend setup using Node.js.

When to use Micro Frontends?

Micro frontends and microservices are architectural patterns used to build scalable and modular applications, but they address different concerns and are suitable for different scenarios.

  • Micro frontends are used when you have a complex web application that requires multiple teams to work independently on different parts of the user interface. By breaking the frontend into smaller, self-contained modules, each team can develop and deploy their features separately, enabling faster development cycles and easier maintenance. This approach is particularly useful in large organizations with multiple frontend teams or when dealing with legacy codebases that need to be incrementally modernized.

  • On the other hand, microservices are employed when designing the backend architecture of an application. With microservices, the backend is split into small, autonomous services, each responsible for a specific business capability. This promotes better scalability, fault isolation, and independent deployment of services. Microservices are a better fit for applications with complex business logic, requiring flexibility in technology choices, and the ability to scale different components independently.

Below is the chart that shows the differences between microservices and micro frontends.

differences between microservices and micro frontends

In summary, use micro frontends when dealing with frontend complexity and multiple development teams, and opt for microservices when you need to create a scalable and modular backend architecture. Both patterns can complement each other in building a comprehensive, decoupled, and flexible system.

Note: I have taken the help of OpenAI in some parts of this tutorial.

Top comments (26)

Collapse
 
janhommes profile image
Jan Hommes • Edited

Sorry, but your example is for me not a microfrontend. Your example is a simple static web server. There is no difference in your example then having two html files called microfrontend1.html and microfrontend2.html.

You can say, that a classic webserver is kind of a microfrontend if it shares stuff. But your exampele isn't even sharing stuff. Also your proxy is not needed at all, you could simply serve the staic files from the root folder and it call the folder microfrontend1 and microfrontend2 and it would work the same way as described.

The main goal of microfrontends is to have it in one view. So you usually have one shell application and multiple remotes. The shell applications host those remotes (maybe one at a time, or multiple at a time) and they are mostly loaded on runtime. You then share certain dependencies (like a common framework) and can load it from different servers. Main goal for me, is to have more losley coupled deployments, espacially when you have big teams or if you want an extension concept for your forntend. We just integrated later into our product (while having classic static file hosting for nearly 10 years). I wrote something about it here:
tech.forums.softwareag.com/t/the-p...

Collapse
 
gyurmatag profile image
György Márk Varga

Can you please make a second part of this tutorial where you make the micro frontends with React - Next for example.

Collapse
 
pavanbelagatti profile image
Pavan Belagatti

Sure:)

Collapse
 
zhshqzyc profile image
Hui Zhao

Also micro frontends with Angular. Hopefully....

Collapse
 
windyaaa profile image
Windya Madushani

Great article.

Collapse
 
pavanbelagatti profile image
Pavan Belagatti

Thank you!

Collapse
 
joneskleber3 profile image
Jones Kleber

Great article!
Thank You!

Collapse
 
nyangweso profile image
Rodgers Nyangweso

good stuff and illustration

Collapse
 
getsetgopi profile image
GP

This does not look like micro front-end from any angle. Your frontend1 and frontend2 are two separate and they are not sharing anything between them nor the implementation is right. You need to read about Webpack Module Federation, Single-SPA, BFF, Open Component, Bit etc., to understand micro front-end.

Collapse
 
upendra-allagadda profile image
Upendra-Allagadda

A great blog with good hands on examples. I liked it.

Collapse
 
pavanbelagatti profile image
Pavan Belagatti

Thanks for the support!

Collapse
 
srshifu profile image
Ildar Sharafeev

Great article! If you want to learn more about micro-frontends recommend to go through my series of articles: thesametech.com/micro-frontend-mig...

Collapse
 
pavanbelagatti profile image
Pavan Belagatti

Sure. I'll go through your articles.

Collapse
 
mickmister profile image
Michael Kochell

Frontends are usually a little more complicated than one HTML file 🙂 Given that the frontends are React applications, do you suggest having separate node projects for each of them? Dependencies could differ between them.

Sharing code between local npm projects in the same repo can work well, though there are many wrong ways to do this. Any thoughts on this?

Collapse
 
derick1530 profile image
Derick Zihalirwa

I suggest you read this: turbo.build/repo/docs/handbook

Collapse
 
mickmister profile image
Michael Kochell

Amazing, thanks Derick!

Collapse
 
tobiobeck profile image
Tobi Obeck

Nice practical article, thanks for writing it!

Could you explain Step 4 about the Microfrontend Server in more detail?

I am not sure what ProxyMiddleware in server.js is exactly doing. What is the purpose of the middleware route /microfrontend1 if it is redirected to the same server, just to another route (/frontend1)?

So why not directly name the static app.use route /microfrontend1 instead of /frontend1 (app.use('/microfrontend1', express.static('frontend1'));)?

Also, the generic example of frontend1 and frontend2 doesn't really make clear for what business use case this architecture makes sense, meaning the benefit of it. I would have expected an example of the interplay between the microfrontends and microservices. E.g. frontend1 fetches products/orders and frontend2 fetches users (including products orders).