Zum Inhalt springen

📦 Industry-Wide Folder & Packaging Structures in Spring Boot

Spring Boot is one of the most popular Java frameworks for building scalable web applications. But writing good code isn’t enough—structuring your project properly is equally crucial. The right folder/package structure:

  • Enhances code readability and maintainability
  • Helps teams scale and collaborate
  • Aligns with domain modeling and microservices architecture

In this blog, we’ll explore the most commonly adopted folder structures across the industry, with examples, pros & cons, and when to use what.

🧱 1. Standard Layered Architecture

👤 Best For: Monoliths, small-to-mid web apps

This is the most traditional structure used by most teams starting with Spring Boot.

com.example.myapp
├── controller         // REST Controllers
├── service            // Business logic
├── repository         // Spring Data Repositories
├── model              // JPA Entities or POJOs
├── dto                // Request/Response DTOs
├── config             // Spring Boot Configs
├── exception          // Custom exceptions, handlers
├── mapper             // MapStruct or manual mappers
└── MyAppApplication.java

✅ Pros

  • Easy to learn and organize
  • Aligned with typical 3-tier architecture

❌ Cons

  • Can get bloated in large projects
  • Tightly couples layers

🧠 Example

@RestController
@RequestMapping("/users")
public class UserController {
    private final UserService userService;
    @GetMapping("/{id}")
    public UserDto getUser(@PathVariable Long id) {
        return userService.getUserById(id);
    }
}

🧩 2. Feature-Based Modular Structure (Vertical Slice)

🚀 Best For: Medium to large modular apps

Organized by feature instead of layers. Ideal when teams work on distinct modules.

com.example.myapp
├── features
│   ├── user
│   │   ├── controller
│   │   ├── service
│   │   ├── repository
│   │   ├── dto
│   │   ├── model
│   │   └── mapper
│   └── product
│       ├── controller
│       ├── service
│       ├── repository
│       └── dto
├── config
├── exception
└── MyAppApplication.java

✅ Pros

  • Scales well with multiple teams
  • Each feature is self-contained

❌ Cons

  • Slight learning curve
  • Shared logic must be carefully managed

🧱 3. Hexagonal Architecture (Ports & Adapters / Clean Architecture)

🏛️ Best For: Domain-Driven, long-lived enterprise systems

Separates domain, application logic, and infrastructure clearly.

com.example.myapp
├── domain
│   ├── model
│   └── service
├── application
│   └── usecases
├── infrastructure
│   ├── persistence
│   └── rest
├── web
│   └── controller
├── config
└── MyAppApplication.java

✅ Pros

  • Testable and decoupled
  • Clean separation of concerns

❌ Cons

  • More boilerplate and upfront design
  • Not suited for trivial apps

🔌 Example:

public interface UserRepository {
    Optional<User> findById(Long id);
}

Implemented by an adapter in infrastructure.persistence.

🧳 4. Multi-Module Maven Structure

🧬 Best For: Microservices, shared modules

Each feature is an independent module, often maintained in different repos.

project-root/
├── common/                   // Shared DTOs, utils
│   └── src/main/java/...
├── user-service/
│   └── src/main/java/com/example/user
├── product-service/
│   └── src/main/java/com/example/product
└── pom.xml                   // Parent POM

✅ Pros

  • Clear modular boundaries
  • Reusable components

❌ Cons

  • Maven complexity
  • Shared versioning can be tricky

🌊 5. Reactive Structure (WebFlux / Handler-Based)

⚛️ Best For: Reactive, async applications

Uses functional routing over MVC annotations.

com.example.myapp
├── handler             // Functional endpoint handlers
├── router              // RouterFunction configs
├── service
├── repository
├── model
└── MyAppApplication.java

Example Router

@Bean
public RouterFunction<ServerResponse> route(UserHandler handler) {
    return RouterFunctions
           .route(GET("/users/{id}"), handler::getUser);
}

✅ Pros

  • Non-blocking, high throughput
  • Lightweight functional style

❌ Cons

  • Functional style is less familiar
  • Debugging stack traces is harder

⚔️ 6. CQRS-Oriented Structure

🧠 Best For: High-scale systems, Event Sourcing

Separates read and write logic.

com.example.myapp
├── command
│   ├── handler
│   ├── service
│   ├── controller
├── query
│   ├── service
│   ├── controller
├── events
│   └── listeners
└── MyAppApplication.java

✅ Pros

  • Optimized for scale
  • Clear boundaries

❌ Cons

  • Higher complexity
  • Eventual consistency challenges

🕸️ 7. GraphQL-Driven Structure

🔍 Best For: GraphQL-first APIs

com.example.myapp
├── graphql
│   ├── resolver
│   ├── schema
│   ├── dto
│   └── service
├── repository
└── MyAppApplication.java

✅ Pros

  • Logical schema-based grouping
  • Supports GraphQL-first development

❌ Cons

  • Requires GraphQL learning
  • Less RESTful structure

📊 Comparison Table

Structure Type Use Case Pros Cons
Layered Monoliths Easy, traditional Bloated in large apps
Feature-Based Modular, team-split projects Scalable, modular Shared code management
Hexagonal Clean DDD applications Decoupled, testable Design-heavy
Multi-Module Microservices, shared libs Isolated, reusable Maven/Gradle complexity
Reactive WebFlux-based async apps Lightweight, fast Less IDE-friendly
CQRS Event-based systems High throughput Complex to maintain
GraphQL GraphQL-first BFF or APIs Schema-aligned Requires schema tooling

🛠️ Which Structure Should You Use?

Your Need Recommended Structure
Building a quick CRUD API Layered
Multi-team, large-scale product Feature-based
Long-term investment, strong domain logic Hexagonal / Clean
Need shared libraries or services Multi-module
Reactive WebSockets / streaming Reactive
Split reads and writes cleanly CQRS
GraphQL-first application GraphQL-based

📁 Final Thoughts

There’s no one-size-fits-all. The right structure depends on your:

  • Team size
  • Codebase complexity
  • Domain modeling
  • Delivery expectations

Start simple, and evolve your structure as the system grows.

🧰 Bonus: Generate Feature Skeleton with Spring Boot CLI

spring init --dependencies=web,data-jpa --build=maven --package-name=com.example.user user-service

Want a GitHub Starter Template?

👉 Drop a comment or message, and I’ll share a starter repo matching your preferred structure—layered, modular, reactive, or clean architecture.

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert