Home / Spring Boot / Getting Started / Create Your First Spring Boot Project

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

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/...                    ← tests

Tip: 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=true

With 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)CauseFix
Web server failed to start. Port 8080 was already in useAnother process uses the portStop it, or set server.port=8081 (or 0 for a random free port)
Failed to configure a DataSource: 'url' attribute is not specifiedJPA or JDBC starter present but no database configuredSet spring.datasource.url, or add H2 for local work, or exclude DataSourceAutoConfiguration
No qualifying bean of type X availableClass is not a bean: missing @Service/@Component, or outside the scanned packageAnnotate it and keep it under the main class package
Parameter 0 of constructor required a single bean, but 2 were foundTwo beans of the same type@Primary, @Qualifier, or inject a List or Map
The dependencies of some of the beans form a cycleCircular dependencyRedesign: extract a third bean. Do not enable allow-circular-references
Whitelabel Error Page, 404URL wrong, controller not scanned, or missing context-path in the URLCheck @RequestMapping and server.servlet.context-path
Unsupported class file major version 65Java 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 3A library still uses javax packagesUpgrade the library to a jakarta version
HikariPool: Connection is not available, request timed out after 30000msPool exhausted by slow queries or leaksFind 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 use

Common 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.