Project Structure
A consistent project layout makes Spring Boot applications easy to navigate as they grow. While Spring imposes few rules, the community has converged on a layered structure that the framework’s defaults reward.
Typical layout
A standard Maven project separates source, resources, and tests.
demo/
├── pom.xml
├── mvnw
└── src
├── main
│ ├── java
│ │ └── com/devcraftly/demo
│ │ ├── DemoApplication.java
│ │ ├── controller/ # HTTP endpoints
│ │ ├── service/ # business logic
│ │ ├── repository/ # data access
│ │ └── model/ # entities & DTOs
│ └── resources
│ ├── application.yml
│ ├── static/ # served assets
│ └── templates/ # server-rendered views
└── test
└── java/...
Each layer has one job. Controllers translate HTTP to method calls, services hold business rules and transactions, repositories talk to the database, and models carry data. This separation keeps each class testable in isolation.
| Layer | Responsibility | Typical annotation |
|---|---|---|
| Controller | HTTP request/response | @RestController |
| Service | Business logic, transactions | @Service |
| Repository | Persistence | @Repository |
| Model | Data shape | @Entity / plain DTO |
The main application class
The class annotated with @SpringBootApplication is the entry point and the root of component scanning.
package com.devcraftly.demo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}
Warning: Keep this class in the top-level package (e.g.
com.devcraftly.demo). Component scanning starts at its package and descends. A class placed in a sibling or parent package will be invisible to the container.
Component scanning
@SpringBootApplication includes @ComponentScan, which discovers @Component, @Service, @Repository, and @Controller classes beneath the main package and registers them as beans. You rarely configure it explicitly, but you can widen or narrow the scan:
@SpringBootApplication
@ComponentScan(basePackages = {"com.devcraftly.demo", "com.devcraftly.shared"})
public class DemoApplication { }
Configuration files
Spring Boot reads externalized configuration from application.properties or application.yml in src/main/resources. YAML is preferred for nested structures.
server:
port: 8080
spring:
application:
name: demo
datasource:
url: jdbc:h2:mem:devdb
The same settings in properties form:
server.port=8080
spring.application.name=demo
spring.datasource.url=jdbc:h2:mem:devdb
Tip: Use
application-<profile>.ymlfiles (for exampleapplication-prod.yml) to layer environment-specific settings on top of the base file. Profiles are covered in the Configuration page.
Best Practices
- Keep the
@SpringBootApplicationclass in the root package so component scanning works without extra configuration. - Organize by layer (or by feature for larger apps), and depend downward only: controller → service → repository.
- Never let controllers touch repositories directly, route data access through a service so business rules and transactions live in one place.
- Prefer
application.ymlover.propertiesfor readable, hierarchical configuration. - Keep configuration out of code; favor properties and
@ConfigurationPropertiesover hard-coded values. - Mirror the main package structure under
src/test/javaso tests sit beside the code they exercise.