Create Your First Spring Boot Project
This page shows how to create a project, what every folder means, how to run it and how to package it. You will finish with a working REST endpoint.
Step 1: Generate the project
- Open start.spring.io (Spring Initializr).
- Choose Maven or Gradle, Java 21 (or 17), packaging Jar.
- Add dependencies: Spring Web, Validation, Spring Data JPA, H2 Database, Actuator, DevTools.
- Click Generate, unzip the file and open it in IntelliJ IDEA, Eclipse or VS Code.
Project structure
demo/
├── pom.xml ← dependencies and build plugin
├── mvnw, mvnw.cmd ← Maven wrapper (no need to install Maven)
└── src/
├── main/
│ ├── java/com/example/demo/
│ │ ├── DemoApplication.java ← main class with @SpringBootApplication
│ │ ├── controller/ ← REST controllers
│ │ ├── service/ ← business logic
│ │ ├── repository/ ← database access
│ │ ├── model/ (entity, dto) ← data classes
│ │ └── config/ ← configuration classes
│ └── resources/
│ ├── application.properties ← configuration
│ ├── static/ ← css, js, images
│ └── templates/ ← Thymeleaf pages
└── test/java/... ← testsTip: Keep the main class in the root package (com.example.demo). Component scanning starts from that package and includes all sub-packages. A class outside this package is not found.
pom.xml (Spring Boot 3.5.x style)
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.5.10</version>
</parent>
<properties>
<java.version>21</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>In Spring Boot 4 some starters were renamed because the code base became modular. For example the web starter is called spring-boot-starter-webmvc. Always generate your pom from start.spring.io for the version you choose.
Step 2: Write a controller
package com.example.demo.controller;
import java.util.Map;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class GreetingController {
@GetMapping("/greet/{name}")
public Map<String, String> greet(@PathVariable String name) {
return Map.of("message", "Hello, " + name);
}
}Step 3: Run it
./mvnw spring-boot:run # run from source
./mvnw clean package # build the jar
java -jar target/demo-0.0.1-SNAPSHOT.jar # run the jar
curl http://localhost:8080/greet/Ram # {"message":"Hello, Ram"}application.properties basics
spring.application.name=demo
server.port=8081
server.servlet.context-path=/api
spring.devtools.restart.enabled=trueWith context-path=/api the URL becomes http://localhost:8081/api/greet/Ram.
Spring Boot DevTools
DevTools restarts the application automatically when a class changes, and enables LiveReload for the browser. It is disabled automatically when you run the packaged jar, so it is safe to keep in the project (as an optional runtime dependency).
What is inside the executable jar?
shop-0.0.1-SNAPSHOT.jar
├── META-INF/MANIFEST.MF Main-Class: org.springframework.boot.loader.launch.JarLauncher
│ Start-Class: com.example.shop.ShopApplication
├── org/springframework/boot/loader/ the launcher classes (read jars inside a jar)
└── BOOT-INF/
├── classes/ YOUR compiled classes and application.properties
├── lib/ ALL dependency jars (spring-*.jar, tomcat-embed-*.jar, jackson-*.jar ...)
├── classpath.idx order of the jars on the classpath
└── layers.idx which files belong to which Docker layer
java -jar shop.jar ─► JarLauncher ─► builds a class loader over BOOT-INF/classes + BOOT-INF/lib/*.jar
─► reads Start-Class ─► calls its main() ─► SpringApplication.run(...)A normal jar cannot contain other jars on its classpath. Spring Boot's launcher adds this ability, which is why one file contains the application, all libraries and the embedded server. Inspect it with: jar tf target/shop.jar | head -50.
Common startup errors and how to read them
| Message (short) | Cause | Fix |
|---|---|---|
| Web server failed to start. Port 8080 was already in use | Another process uses the port | Stop it, or set server.port=8081 (or 0 for a random free port) |
| Failed to configure a DataSource: 'url' attribute is not specified | JPA or JDBC starter present but no database configured | Set spring.datasource.url, or add H2 for local work, or exclude DataSourceAutoConfiguration |
| No qualifying bean of type X available | Class is not a bean: missing @Service/@Component, or outside the scanned package | Annotate it and keep it under the main class package |
| Parameter 0 of constructor required a single bean, but 2 were found | Two beans of the same type | @Primary, @Qualifier, or inject a List or Map |
| The dependencies of some of the beans form a cycle | Circular dependency | Redesign: extract a third bean. Do not enable allow-circular-references |
| Whitelabel Error Page, 404 | URL wrong, controller not scanned, or missing context-path in the URL | Check @RequestMapping and server.servlet.context-path |
| Unsupported class file major version 65 | Java version older than the class files (compiled with Java 21, running on 17) | Use the same or a newer Java at runtime |
| ClassNotFoundException javax.* after upgrading to Boot 3 | A library still uses javax packages | Upgrade the library to a jakarta version |
| HikariPool: Connection is not available, request timed out after 30000ms | Pool exhausted by slow queries or leaks | Find slow queries and long transactions, then tune the pool |
Package by layer or package by feature?
BY LAYER (simple, common in tutorials) BY FEATURE (better for bigger systems)
com.example.shop com.example.shop
├── controller/ ├── ShopApplication.java
│ ├── ProductController ├── product/
│ └── OrderController │ ├── ProductController
├── service/ │ ├── ProductService
│ ├── ProductService │ ├── ProductRepository
│ └── OrderService │ └── Product (entity), ProductDto
├── repository/ ├── order/
└── model/ │ ├── OrderController ... OrderService ... Order
└── shared/ (config, security, exceptions)Package by feature keeps everything about one business capability together, allows package-private classes (real encapsulation) and makes it easy to split into modules or services later. Spring Modulith can even verify the boundaries.
First checks after the app starts
curl -s localhost:8080/actuator/health # {"status":"UP"} (needs the Actuator starter)
curl -s localhost:8080/actuator/mappings | head # all URL mappings
curl -s localhost:8080/actuator/beans | head # all beans
jcmd | grep shop # find the java process id
jcmd <pid> VM.flags # JVM flags in useCommon mistake: Placing the main class in a deep sub-package such as com.example.demo.app. Controllers in com.example.demo.web are then not scanned and you get 404 errors.
Interview questions
Why does my application start on port 8080?
8080 is the default port of the embedded Tomcat. Change it with server.port in application.properties.
What does the Maven wrapper (mvnw) do?
It downloads the correct Maven version automatically, so everybody builds the project with the same Maven.
How do I run the application in the IDE?
Run the main method of the class that has @SpringBootApplication.
What is the Maven wrapper folder .mvn?
It holds the wrapper properties that decide the Maven version, so every developer and the CI use the same Maven without installing it.
How do I run the application on a random port for tests?
Set server.port=0 (or @SpringBootTest(webEnvironment = RANDOM_PORT)) and read the real port from the local.server.port property or WebServerInitializedEvent.