Spring Boot Common Module for Microservices: Best Practices
Bharat Chaudhari
Jul 16, 2026
Introduction
One of the most common failure patterns in microservice ecosystems has nothing to do with distributed systems, networking, or scalability.
It begins with copy-paste.
A team creates a User Service and implements a global exception handler. A second service needs similar behavior, so the code is copied. A third service needs localization support, so that code is copied as well. Over time, every service develops its own slightly different implementation of response handling, validation, logging, error formatting, localization, and utility functions.
Initially, this duplication appears harmless.
As the platform grows, it becomes one of the most expensive forms of technical debt.
A bug fix requires updates across multiple repositories. Error responses become inconsistent. Localization behaves differently across services. Engineering standards begin to drift.
The Common Module exists to prevent this outcome.
Rather than copying infrastructure code across services, shared concerns are centralized into a versioned library that can evolve independently while enforcing consistency across the platform.
In this article, we’ll examine how a centralized Common Module reduces duplication, improves maintainability, and establishes engineering standards across a Spring Boot microservices ecosystem.
The Hidden Cost of Copy-Paste Architecture
Microservice architectures naturally encourage service independence.
Unfortunately, many teams misinterpret independence as duplication.
Consider a platform containing:
User Service
Payment Service
Notification Service
Authorization Service
Each service requires:
Exception handling
Validation
Response formatting
Localization
Utility functions
If every service implements these concerns independently, small inconsistencies begin to appear.
One service return:
{
"message": "User not found"
}
Another return:
{
"error": "User not found"
}
A third return:
{
"status": 404,
"details": "User not found"
}
From an API consumer’s perspective, the platform no longer behaves consistently.
The Common Module eliminates this divergence by providing shared infrastructure capabilities through a centralized dependency.
Why we built a common module
The objective was never simply to reduce code duplication.
The larger goal was architectural governance.
The Common Module provides a mechanism for enforcing platform-wide standards in areas such as:
Error handling
API response structures
Localization
Validation
Shared DTOs
Utility classes
This creates a contract that every service follows.
As new services are added, they inherit these standards automatically rather than reimplementing them from scratch.
This dramatically improves consistency while reducing development effort.
Architecture Diagram
Without Common Module
User Service
├── Exception Handler
├── ApiResponse
├── i18n
Payment Service
├── Exception Handler
├── ApiResponse
├── i18n
Notification Service
├── Exception Handler
├── ApiResponse
├── i18n
Problems: Duplication, Drift, Inconsistency
With Common Module
Common Module
├── Exception Handler
├── ApiResponse
├── i18n
├── Utilities
↓
User Service
Payment Service
Notification Service
Authorization Service
Benefits: Consistency, Governance, Faster Development
What belongs in a common module?
One of the most important architectural questions is determining what should be shared.
The answer is: Infrastructure concerns.
Good candidates include:
Exception Handling: Consistent error responses across services.
API Response Models: Standardized response contracts.
Localization: Shared message resolution and language support.
Validation Utilities: Reusable validation logic.
Common Constants: Platform-wide constants and configuration helpers.
Shared Utility Classes: Date handling, formatting, string manipulation, and helper methods.
Distributed Tracing: Centralized Micrometer and Zipkin configurations.
These concerns are cross-cutting and benefit from centralization.
What Should NOT Be Shared?
Many organizations eventually create an oversized common library that becomes more problematic than duplication.
A Common Module should never contain:
Business Logic: Business rules belong within the service that owns the domain.
Domain Models: User entities should not appear in Payment Services. Payment entities should not appear in Notification Services.
Service-Specific APIs: Shared libraries should not expose functionality tightly coupled to individual services.
Database Access: Repositories and persistence logic should remain within service boundaries.
The guiding principle is simple: Share infrastructure. Do not share business capabilities.
Architecture & Tech Stack
Component
Details
Language & Framework
Java 21 & Spring Boot 4.0.3
Type
Shared Java library (.jar) — NOT a standalone service
Error handling is often implemented differently in every service.
This creates several problems:
Inconsistent error formats
Duplicate code
Difficult debugging
Different localization behavior
The GlobalExceptionHandler centralizes these concerns.
Rather than forcing every service to implement identical exception handling logic, services inherit a common implementation and extend it only when necessary.
This ensures that:
Error structures remain consistent
Localization behaves identically
Logging standards remain aligned
while still allowing service-specific customization.
public class GlobalExceptionHandler
extends ResponseEntityExceptionHandler {
@ExceptionHandler(ResourceNotFoundException.class)
public ResponseEntity
How to Use GlobalExceptionHandler in Other Services
In this setup, the GlobalExceptionHandler is intentionally not annotated with @RestControllerAdvice. This gives you better flexibility and control. Instead of letting Spring auto-detect it, we design it to be reused through inheritance.
Add the Dependency to Your Service Next, include this shared module in the service where you want to use it.
Many applications introduce localization only after international users arrive.
Retrofitting localization into an existing platform is often painful because messages become scattered across controllers, services, and exception classes.
The Common Module treats localization as a first-class capability from the beginning.
By centralizing locale resolution and message source configuration, every service automatically gains multilingual support without implementing its own localization infrastructure.
This allows teams to add additional languages with minimal application changes while maintaining consistent user experiences across the platform.
@Configuration
public class I18nConfig implements WebMvcConfigurer {
private static final List SUPPORTED_LOCALES =
Arrays.asList(new Locale("en"), new Locale("fr"));
@Bean
public LocaleResolver localeResolver() {
return new AcceptHeaderLocaleResolver() {
@Override
public Locale resolveLocale(HttpServletRequest request) {
String headerLang = request.getHeader("Accept-Language");
return headerLang == null || headerLang.isEmpty()
? Locale.getDefault()
: Locale.lookup(
Locale.LanguageRange.parse(headerLang),
SUPPORTED_LOCALES);
}
};
}
}
Centralized Distributed Tracing
A major benefit of the Common Module is centralizing distributed tracing. By including `micrometer-tracing-bridge-brave` and `zipkin-reporter-brave`, we ensure all microservices emit consistent trace headers and spans.
To bypass missing or complex Spring Boot autoconfigurations, the Common Module includes `TracingManualConfig`:
@Configuration
public class TracingManualConfig {
@Bean
@ConditionalOnMissingBean
public DefaultTracingObservationHandler tracingObservationHandler(Tracer tracer) {
return new DefaultTracingObservationHandler(tracer);
}
// ... configures Zipkin sender, Brave Tracing, and Micrometer Tracer
}
Any service depending on the Common Module will automatically start reporting distributed traces to Zipkin without writing custom configurations in every service.
Versioning Strategy
Shared libraries introduce different operational challenges upgrades.
Every service consuming in the Common Module must remain compatible with new releases.
For this reason:
Breaking changes should be minimized.
Semantic versioning should be followed.
Backward compatibility should be preserved where possible.
Typical versioning approach:
Major Version: Breaking changes.
Minor Version: New features.
Patch Version: Bug fixes.
This allows services to upgrade predictably while avoiding unexpected runtime behavior.
Production Considerations
Dependency Governance Every shared library becomes a platform of dependency.
Changes must be reviewed carefully because they can impact multiple services simultaneously.
Backward Compatibility Avoid introducing changes that require all services to upgrade immediately.
Incremental adoption is far safer.
Release Management Treat shared libraries with the same rigor as production services.
Changes should undergo:
Code review
Testing
Version tagging
Release documentation
Documentation Shared modules are only valuable when engineers understand how to use them.
Every reusable component should include:
Usage examples
Extension patterns
Migration notes
Architectural Benefits
The Common Module provides benefits beyond code reuse.
Consistency: All services behave similarly.
Faster Development: New services start with established standards.
Easier Maintenance: Bug fixes occur once instead of multiple times.
Improved Governance: Architectural standards become enforceable rather than optional.
Better Developer Experience: Teams focus on business capabilities rather than rebuilding infrastructure repeatedly.
Conclusion
The Common Module is rarely the most visible component in a microservices platform, but it is often one of the most important.
Without shared standards, microservice ecosystems gradually drift toward inconsistency. Error handling differs between services, response structures evolve independently, and infrastructure concerns are repeatedly reimplemented.
By centralizing cross-cutting concerns into a versioned shared library, teams establish a foundation of consistency without sacrificing service independence.
The result is not merely less code duplication. The result is a platform that behaves predictably, scales more effectively, and remains maintainable as the number of services and engineering teams grows.
In many ways, the Common Module acts as the architectural backbone of the platform, ensuring that every service speaks the same language even as they evolve independently.
Why not simply copy code between services? Copying infrastructure code appears faster initially but creates long-term maintenance challenges. Bug fixes, enhancements, and standards of enforcement become increasingly difficult as duplication grows.
Can a Common Module become too large? Yes.
Many organizations eventually create “God Libraries” containing unrelated functionality. Shared modules should focus on infrastructure concerns rather than business capabilities.
Should domain entities be shared?
Generally, not.
Domain ownership should remain within individual services.
How do services adopt new Common Module features?
Through versioned releases and dependency upgrades.
This allows teams to adopt changes incrementally rather than requiring platform-wide updates.
Is a Common Module required in every microservices architecture?
Not necessarily.
Smaller systems may not benefit immediately. As the number of services grows, however, shared infrastructure becomes increasingly valuable.
Bharat Chaudhari is a Java Backend Engineer with 5+ years of experience building scalable microservices using Spring Boot. He specializes in distributed systems, event-driven architecture, Spring Security, Kafka, PostgreSQL, Redis, Docker, and Kubernetes, with a passion for building production-ready backend platforms.
Delivering Engineering Excellence Across Global Markets
India
USA
UAE
Europe
Singapore
Australia
Need Help Building Enterprise Spring Boot Microservices?
We specialize in designing secure, scalable, and event-driven microservices using Spring Boot, Kafka, PostgreSQL, Redis, OAuth2/JWT, Docker, Kubernetes, and cloud-native best practices for enterprise applications.
For 12+ years, Inexture has helped global enterprises design, build, modernize, and scale secure, high-performance digital platforms. We combine deep engineering expertise with cloud, enterprise systems, backend architecture, mobile, AI, and user centric design delivering solutions that make businesses future ready.