Back to Blog

How I Created a Multi-Module Spring Boot Project in IntelliJ (Step by Step)

How I Created a Multi-Module Spring Boot Project in IntelliJ (Step by Step)

I created this as a Maven multi-module Spring Boot setup in IntelliJ, with one runnable module and clear layer separation.

Actual module structure I created

SpringBootMultiModule/
  pom.xml                    (parent, packaging=pom)
  entity/
  dto/
  repository/
  services/
  controller/
  • entity: JPA entities (User.java)
  • dto: transfer objects (UserDto.java)
  • repository: Spring Data JPA repository (UserRepository.java)
  • services: business layer (UserService, UserServiceImpl)
  • controller: runnable Spring Boot app + REST (MultiModuleApplication, UserController)

Step 1: Create parent Maven project in IntelliJ

  1. Create a Maven project.
  2. Set parent packaging to pom.
  3. Use Spring Boot parent in root POM.

In my root pom.xml:

  • spring-boot-starter-parent version: 3.4.4
  • java.version: 24
  • lombok.version: 1.18.38
  • modules: entity, dto, repository, services, controller

I also kept internal modules in dependencyManagement so versions are centralized.

Step 2: Create child modules and connect to parent

For each module (entity, dto, repository, services, controller):

  1. Create Maven module under parent.
  2. Add parent reference:
<parent>
  <groupId>com.example</groupId>
  <artifactId>springboot-multimodule</artifactId>
  <version>1.0.0-SNAPSHOT</version>
</parent>
  1. Keep module-specific dependencies only.

Step 3: Build dependency chain module-by-module

I wired dependencies like this:

  • entity -> spring-boot-starter-data-jpa
  • dto -> lombok
  • repository -> depends on entity + spring-boot-starter-data-jpa
  • services -> depends on entity, dto, repository, and spring-boot-starter
  • controller -> depends on services, dto, and spring-boot-starter-web

This keeps REST concerns out of business and persistence modules.

Step 4: Keep only controller module runnable

My runnable app class is:

  • controller/src/main/java/com/example/multimodule/MultiModuleApplication.java

And only controller/pom.xml contains spring-boot-maven-plugin.

So the startup responsibility is isolated in one module.

Step 5: Add data + endpoint flow

From my project:

  • Entity: entity/.../User.java
  • DTO: dto/.../UserDto.java
  • Repository: repository/.../UserRepository.java
  • Service interface: services/.../UserService.java
  • Service implementation: services/.../impl/UserServiceImpl.java
  • Controller endpoint: controller/.../controller/UserController.java

This gave me a clean CRUD path: Controller -> Service -> Repository -> Entity.

Step 6: Configure runtime in controller module

In controller module I used:

  • spring-boot-starter-web
  • H2 runtime dependency
  • application.properties for local run settings

That made local testing quick with in-memory DB.

Step 7: Build and run commands I used

From project root:

./mvnw clean verify
./mvnw spring-boot:run -pl controller

After startup:

  • API base: http://localhost:8080/api/users
  • H2 console: http://localhost:8080/h2-console

Step 8: IntelliJ workflow that worked well

  1. Import root pom.xml as Maven project.
  2. Let IntelliJ auto-detect modules.
  3. Use Maven tool window to reload after each POM change.
  4. Run MultiModuleApplication from controller module.

Important notes from this setup

  • Keep module boundaries strict, especially around controller vs service vs repository.
  • Keep one runnable module (controller) to avoid startup confusion.
  • Put shared version configuration in parent POM.
  • If using Java 24 + Lombok, ensure compiler/plugin config is consistent across modules.

Final takeaway

For this project, multi-module was not just about splitting folders. It made responsibilities explicit:

  • web in controller
  • business in services
  • data access in repository
  • models in entity and dto

That structure made the codebase easier to evolve and reason about.

Repository

GitHub: https://github.com/arkomandal/spring-boot-multimodule