DEV Community

Cover image for Understanding Server-Side Composition and Client-Side Composition in Microservices
Daniel Azevedo
Daniel Azevedo

Posted on

Understanding Server-Side Composition and Client-Side Composition in Microservices

Hi devs,

When building microservices-based applications, choosing how to structure and compose the user interface (UI) can significantly impact scalability, modularity, and performance. Two common design patterns in this space are Server-Side Composition and Client-Side Composition. Let’s dive into what each approach entails, their benefits, and when to use them.

Why Composition Patterns Matter in Microservices

In monolithic architectures, the UI is often tightly coupled with the backend, making it easier to render views with data from a single source. In microservices architectures, however, data and logic are distributed across multiple services, creating a need to aggregate information from different sources. This is where composition patterns come in:

  • Server-Side Composition: Aggregates content at the server level.
  • Client-Side Composition: Aggregates content directly in the user’s browser or application.

Each has its strengths, and the choice often depends on the complexity, performance needs, and architecture of the application.


Server-Side Composition

Server-Side Composition involves aggregating data from multiple microservices on the server before sending it to the client. Essentially, a central service (often called a "composition service" or "aggregator") collects data from other services, merges it, and sends a single, unified response to the client.

How It Works

  1. Client Request: The client makes a request to the composition service.
  2. Data Aggregation: The composition service then fetches data from various microservices (e.g., user profile, product recommendations, recent orders).
  3. Response Assembly: The service aggregates the responses, builds a unified response, and sends it back to the client.

Benefits of Server-Side Composition

  • Better Performance: Server-Side Composition reduces the number of network requests made by the client, which can improve loading times, especially on slower networks.
  • Centralized Control: Since aggregation is centralized, it’s easier to maintain and control the UI structure and response data.
  • Consistent Data Format: The composition service can ensure that responses are consistent in format, which simplifies the client-side logic.

Drawbacks of Server-Side Composition

  • Increased Server Load: Since the server is responsible for aggregating responses, it can become a bottleneck.
  • Reduced Flexibility: Client applications have less control over the data, which can be restrictive for highly interactive or dynamic UIs.
  • Single Point of Failure: If the composition service fails, it can disrupt the entire user experience.

Example Use Case in C

Let's consider an e-commerce application where a user’s dashboard includes data from multiple services (order history, recommended items, and user profile). Here’s a simplified example of how a Server-Side Composition might look in C#:

public class DashboardService
{
    private readonly IOrderService _orderService;
    private readonly IRecommendationService _recommendationService;
    private readonly IUserService _userService;

    public DashboardService(IOrderService orderService, IRecommendationService recommendationService, IUserService userService)
    {
        _orderService = orderService;
        _recommendationService = recommendationService;
        _userService = userService;
    }

    public async Task<DashboardData> GetDashboardData(int userId)
    {
        var orderHistory = await _orderService.GetOrderHistory(userId);
        var recommendations = await _recommendationService.GetRecommendations(userId);
        var userProfile = await _userService.GetUserProfile(userId);

        return new DashboardData
        {
            Orders = orderHistory,
            Recommendations = recommendations,
            Profile = userProfile
        };
    }
}
Enter fullscreen mode Exit fullscreen mode

Here, the DashboardService aggregates data from three separate services and sends a single response to the client.


Client-Side Composition

Client-Side Composition involves the client aggregating data from multiple microservices. Instead of a central composition service on the server, the client sends multiple requests directly to the relevant services and composes the final UI.

How It Works

  1. Multiple Client Requests: The client sends requests to each microservice independently.
  2. Data Aggregation: The client processes each response as it arrives and assembles the UI.
  3. Rendering: The client renders the UI components based on the aggregated data.

Benefits of Client-Side Composition

  • Decoupled Services: Microservices are more loosely coupled, allowing for easier maintenance and deployment.
  • Better Scalability: Load is distributed across the client and various services, reducing server bottlenecks.
  • Greater Flexibility: Client applications have more control over how data is displayed, allowing for more dynamic and interactive UIs.

Drawbacks of Client-Side Composition

  • Higher Latency: The client has to make multiple network requests, which can slow down the UI, especially on mobile networks.
  • Increased Client Complexity: The client is responsible for handling the logic of aggregating and rendering data, which can add complexity to the client code.
  • Cross-Origin Issues: Direct client requests to multiple microservices may run into cross-origin resource sharing (CORS) issues.

Example Use Case in JavaScript

Consider the same e-commerce dashboard, but this time with Client-Side Composition. In this case, we can use JavaScript to fetch data from each microservice and render the UI once all data is retrieved.

async function getDashboardData(userId) {
    const orderHistoryPromise = fetch(`/api/orders/${userId}`);
    const recommendationsPromise = fetch(`/api/recommendations/${userId}`);
    const userProfilePromise = fetch(`/api/user/${userId}`);

    const [orderHistory, recommendations, userProfile] = await Promise.all([
        orderHistoryPromise,
        recommendationsPromise,
        userProfilePromise,
    ]);

    renderDashboard({
        orders: await orderHistory.json(),
        recommendations: await recommendations.json(),
        profile: await userProfile.json(),
    });
}

function renderDashboard(data) {
    console.log('Order History:', data.orders);
    console.log('Recommendations:', data.recommendations);
    console.log('User Profile:', data.profile);
}

getDashboardData(123);
Enter fullscreen mode Exit fullscreen mode

In this example, getDashboardData fetches data from three endpoints and then calls renderDashboard to display the data on the UI.


Comparing Server-Side and Client-Side Composition

Feature Server-Side Composition Client-Side Composition
Performance Lower client-side latency Higher client-side latency
Server Load Higher Lower
Flexibility Lower Higher
Complexity Server-side Client-side
Best for Monolithic UIs Dynamic, interactive UIs
Drawbacks Server bottlenecks Increased client-side complexity

Choosing the Right Composition Pattern

The choice between Server-Side and Client-Side Composition largely depends on your application’s requirements:

  • Choose Server-Side Composition if you need a centralized, consistent response with minimized client requests. It’s a good fit for applications with less dynamic UIs or where network performance is a concern.

  • Choose Client-Side Composition for applications that benefit from high flexibility, customization, and modularity. This approach is popular in single-page applications (SPAs) or progressive web apps (PWAs) where each component can update independently.


Both Server-Side and Client-Side Composition patterns have their advantages and trade-offs. By understanding these patterns and the specific needs of your application, you can design a microservices architecture that is flexible, maintainable, and scalable.

Top comments (0)