Spring Boot Cheat Sheet

This Spring Boot cheat sheet covers 28 sections of Spring Boot 4: starters and application.properties, profiles and @ConfigurationProperties, beans and auto-configuration, REST controllers with validation and problem details, API versioning, Spring Data JPA, Spring Security 7, actuator, testing, Docker images and the upgrade from Boot 3. Every output comes from a real Boot 4.1.1 app. Check your properties for Boot 4 and generate build files and Dockerfiles without leaving the page.

28sections
101snippets
4.1.1Spring Boot, Aug 2026
9Spring Boot tools

Updated October 14, 2026, checked against Spring Boot 4.1.1, Spring Framework 7.0.9, Spring Security 7.1.1, the Boot 4.0 migration guide and Java 25. Print it for a PDF copy.

/
level

NoSuchBeanDefinitionException

Nothing matches that search. Try a shorter keyword such as profile, actuator or jpa. Several words are combined, so every one of them has to match. Keys: / focuses the search, Esc clears it, t switches the theme.

01

Toolbox & First App

check properties for Boot 4, convert properties and YAML, map keys to environment variables, read cron expressions

Spring Boot Toolbox: Property Check, Properties and YAML, Env Vars, Cron

core
Ctrl+Enter runs the check. It flags the 201 properties that Spring Boot 4.0 and 4.1 renamed or removed, with the replacement, plus risky settings such as ddl-auto=update or exposing every actuator endpoint. The converters accept .properties or YAML. Env vars shows each key as an environment variable, a command-line argument and SPRING_APPLICATION_JSON. Explain cron reads a Spring cron expression such as 0 0 9 * * MON-FRI and lists its next runs.
output

          
Paste application.properties, application.yml or a cron expression above, then pick an action.

Builders: Build File, REST Resource, Database Config, Dockerfile

everyday
build file

          

A First Application

core

The main class

package com.example.shop;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class ShopApplication {

    public static void main(String[] args) {
        SpringApplication.run(ShopApplication.class, args);
    }

}

Build and run it

./mvnw package
java -jar target/shop-1.0.0.jar
02

Project Setup

start.spring.io, Boot 4 starters, the parent POM and the wrappers

Generate a Project

core

From the command line

curl -s https://start.spring.io/starter.zip -d type=maven-project -d javaVersion=25 -d dependencies=web,actuator,data-jpa,validation -d artifactId=shop -o shop.zip && unzip -Z1 shop.zip | sort

Boot 4 Starters

core

Modular starters, each with a test companion

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>4.1.1</version>
</parent>

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-webmvc</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-jpa</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-webmvc-test</artifactId>
        <scope>test</scope>
    </dependency>
</dependencies>

Renamed starters

Boot 3 starterBoot 4 starter
spring-boot-starter-webspring-boot-starter-webmvc
spring-boot-starter-web-servicesspring-boot-starter-webservices
spring-boot-starter-oauth2-clientspring-boot-starter-security-oauth2-client
spring-boot-starter-oauth2-resource-serverspring-boot-starter-security-oauth2-resource-server
spring-boot-starter-oauth2-authorization-serverspring-boot-starter-security-oauth2-authorization-server
spring-boot-starter and spring-boot-starter-test, all auto-configuration at oncespring-boot-starter-classic and spring-boot-starter-test-classic

Gradle

everyday

build.gradle.kts

plugins {
    java
    id("org.springframework.boot") version "4.1.1"
    id("io.spring.dependency-management") version "1.1.7"
}

java {
    toolchain { languageVersion = JavaLanguageVersion.of(25) }
}

repositories {
    mavenCentral()
}

dependencies {
    implementation("org.springframework.boot:spring-boot-starter-webmvc")
    implementation("org.springframework.boot:spring-boot-starter-actuator")
    testImplementation("org.springframework.boot:spring-boot-starter-webmvc-test")
    testRuntimeOnly("org.junit.platform:junit-platform-launcher")
}

Everyday Commands

core

Maven and Gradle side by side

TaskMavenGradle
run the app./mvnw spring-boot:run./gradlew bootRun
run with a profile./mvnw spring-boot:run -Dspring-boot.run.profiles=dev./gradlew bootRun --args='--spring.profiles.active=dev'
build the jar./mvnw package./gradlew bootJar
skip tests./mvnw package -Dmaven.test.skip=true./gradlew bootJar -x test
container image./mvnw spring-boot:build-image./gradlew bootBuildImage
native executable./mvnw -Pnative native:compile./gradlew nativeCompile
dependency tree./mvnw dependency:tree./gradlew dependencies
03

Properties & Configuration

application.properties, YAML, precedence and relaxed binding

Where Configuration Comes From

core

application.properties and its YAML twin

spring.application.name=shop
server.port=8080
spring.datasource.url=jdbc:postgresql://localhost:5432/shop
spring.jpa.open-in-view=false
shop.currency=EUR
shop.countries=RO,DE,FR

Precedence, highest first

SourceExample
command-line argumentsjava -jar app.jar --server.port=9090
SPRING_APPLICATION_JSONSPRING_APPLICATION_JSON='{"server":{"port":9090}}'
Java system propertiesjava -Dserver.port=9090 -jar app.jar
OS environment variablesSERVER_PORT=9090
profile-specific files outside the jar./config/application-prod.properties
application files outside the jar./application.properties next to the jar
profile-specific files in the jarsrc/main/resources/application-prod.properties
application files in the jarsrc/main/resources/application.properties
@PropertySource and defaultson @Configuration classes, SpringApplication.setDefaultProperties

Relaxed Binding

core

One property, four spellings

WhereSpelling of shop.max-items
properties and YAMLshop.max-items, the canonical kebab case
environment variableSHOP_MAXITEMS or SHOP_MAX_ITEMS
list element in an environment variableSHOP_COUNTRIES_0_=RO
system property or argument--shop.max-items=10

An environment variable that fails validation

SHOP_MAX_ITEMS=200 java -jar target/shop-1.0.0.jar

Durations and Sizes

everyday

How Boot parses 30s and 10MB

import org.springframework.boot.convert.DurationStyle;
import org.springframework.util.unit.DataSize;
System.out.println(DurationStyle.detectAndParse("30s"));
System.out.println(DurationStyle.detectAndParse("PT1H30M"));
System.out.println(DurationStyle.detectAndParse("PT0.5S"));
System.out.println(DurationStyle.detectAndParse("250"));
System.out.println(DataSize.parse("10MB").toBytes());
System.out.println(DataSize.parse("512KB").toBytes());

Encoding

everyday

A UTF-8 é in application.properties

import java.nio.file.Files;
import java.nio.charset.StandardCharsets;
import org.springframework.boot.env.PropertiesPropertySourceLoader;
import org.springframework.core.io.FileSystemResource;

var file = Files.createTempFile("app", ".properties");
Files.writeString(file, "shop.note=café\nshop.escaped=caf\\u00e9\n", StandardCharsets.UTF_8);
var source = new PropertiesPropertySourceLoader().load("app", new FileSystemResource(file)).get(0);
for (String key : new String[] {"shop.note", "shop.escaped"}) {
    String value = (String) source.getProperty(key);
    System.out.println(key + ": " + value.length() + " chars " + value.chars().mapToObj(Integer::toHexString).toList());
}

YAML Surprises

everyday

Unquoted values YAML 1.1 rewrites

import org.springframework.boot.env.YamlPropertySourceLoader;
import org.springframework.core.io.ByteArrayResource;
import org.springframework.core.env.EnumerablePropertySource;

var yaml = """
    shop:
      file-mode: 0755
      opens-at: 8:30
      gift-wrap: on
      country: NO
      quoted-mode: "0755"
    """;
var source = (EnumerablePropertySource<?>) new YamlPropertySourceLoader().load("demo", new ByteArrayResource(yaml.getBytes())).get(0);
for (String name : source.getPropertyNames()) System.out.println(name + " = " + source.getProperty(name));
04

Typed Configuration

@ConfigurationProperties records, validation and metadata

@ConfigurationProperties

core

A record bound to shop.*

@Validated
@ConfigurationProperties("shop")
public record ShopProperties(
        @NotBlank String currency,
        @Min(1) @Max(100) int maxItems,
        @DefaultValue("50") BigDecimal freeShippingOver,
        @DefaultValue("30s") Duration paymentTimeout,
        List<String> countries) {
}

What the record receives

shop.currency=EUR
shop.max-items=10
shop.countries=RO,DE,FR

@Value or @ConfigurationProperties

everyday

Pick the right one

NeedUse
a group of related settings@ConfigurationProperties record
validation, IDE auto-completion, metadata@ConfigurationProperties with spring-boot-configuration-processor
one value in one class@Value("${shop.currency}")
a computed value@Value("#{...}") SpEL, sparingly
05

Profiles

profile files, activation, groups and @Profile

Activate a Profile

core

Three ways to switch

java -jar target/shop-1.0.0.jar --spring.profiles.active=prod
SPRING_PROFILES_ACTIVE=prod java -jar target/shop-1.0.0.jar
./mvnw spring-boot:run -Dspring-boot.run.profiles=dev

Beans for one profile

@Component
@Profile("demo")
public class DemoRunner implements ApplicationRunner {

    @Override
    public void run(ApplicationArguments args) {
        System.out.println("only in the demo profile");
    }

}

Groups and Multi-Document Files

everyday

One file, several profiles

spring.profiles.group.prod=postgres,json-logs
logging.level.root=info
#---
spring.config.activate.on-profile=json-logs
logging.structured.format.console=ecs
#---
spring.config.activate.on-profile=dev
logging.level.com.example=debug
06

Beans & Dependency Injection

components, @Bean methods, qualifiers and conditions

Declaring Beans

core

Component scanning and constructor injection

@Service
public class OrderService {

    private final OrderRepository orders;
    private final ShopProperties shop;

    public OrderService(OrderRepository orders, ShopProperties shop) {
        this.orders = orders;
        this.shop = shop;
    }

}

@Bean methods for classes you do not own

@Configuration
public class ClockConfig {

    @Bean
    Clock clock() {
        return Clock.systemUTC();
    }

}

Choosing Between Beans

everyday

Two beans of the same type

AnnotationEffect
@Primarythe default choice when several candidates exist
@Qualifier("fast")pick a specific bean by name or qualifier
List<PaymentProvider>inject all of them, in @Order order
@ConditionalOnProperty(name = "shop.payments", havingValue = "stripe")create the bean only when the property matches
@ConditionalOnMissingBeancreate a default unless the application defined its own

Scopes and lifecycle

ScopeInstances
singletonone per application context, the default
prototypea new one at every injection or getBean call
request, sessionone per HTTP request or session, in web applications
07

Auto-Configuration

how Boot decides what to configure, the conditions report and your own auto-configuration

How It Decides

core

Ask Boot why

java -jar target/shop-1.0.0.jar --debug

A positive match from the same report


        

Turn It Off

everyday

Exclude an auto-configuration

spring.autoconfigure.exclude=org.springframework.boot.security.autoconfigure.UserDetailsServiceAutoConfiguration

Write Your Own

advanced

An auto-configuration class and its registration

@AutoConfiguration
@ConditionalOnClass(AuditClient.class)
@EnableConfigurationProperties(AuditProperties.class)
public class AuditAutoConfiguration {

    @Bean
    @ConditionalOnMissingBean
    AuditClient auditClient(AuditProperties properties) {
        return new AuditClient(properties.url());
    }

}
08

REST Controllers

@RestController, mappings, request data and responses

A Controller

core

Read, list and create orders

@RestController
@RequestMapping("/api/orders")
public class OrderController {

    private final OrderService service;

    public OrderController(OrderService service) {
        this.service = service;
    }

    @GetMapping
    public PagedModel<Order> list(@RequestParam(required = false) Order.Status status,
            @PageableDefault(size = 2, sort = "id") Pageable pageable) {
        return new PagedModel<>(service.list(status, pageable));
    }

    @GetMapping("/{id}")
    public Order get(@PathVariable long id) {
        return service.find(id);
    }

    @PostMapping
    public ResponseEntity<Order> create(@Valid @RequestBody NewOrder request) {
        Order order = service.create(request);
        return ResponseEntity.created(URI.create("/api/orders/" + order.getId())).body(order);
    }

}

GET one order

curl -s localhost:8080/api/orders/1

POST returns 201 and a Location header

curl -s -i -u admin:change-me -X POST localhost:8080/api/orders -H "Content-Type: application/json" -d '{"sku":"LAMP-01","qty":2}'

Request Data

core

Where each annotation reads from

AnnotationReadsExample
@PathVariablea URI template segment/api/orders/{id}
@RequestParamthe query string or a form field?status=PAID
@RequestBodythe JSON body, via Jackson{"sku":"LAMP-01"}
@RequestHeadera request headerAPI-Version: 2
@CookieValuea cookiesession=...
Pageablepage, size and sort parameters?page=0&size=20&sort=total,desc
09

Validation

Jakarta Bean Validation on request bodies, parameters and configuration

Validate Request Bodies

core

Constraints on a record

public record NewOrder(
        @NotBlank @Pattern(regexp = "[A-Z]+-\\d+") String sku,
        @Min(1) @Max(10) int qty) {
}

An invalid request

curl -s -u admin:change-me -X POST localhost:8080/api/orders -H "Content-Type: application/json" -d '{"sku":"lamp","qty":0}'

Common Constraints

everyday

jakarta.validation.constraints

ConstraintChecks
@NotNull, @NotEmpty, @NotBlanknot null; not null and not empty; contains a non-space character
@Size(min, max)length of a string or size of a collection
@Min, @Max, @Positive, @PositiveOrZeronumeric bounds
@DecimalMin, @Digitsdecimal bounds and precision, for BigDecimal money
@Email, @Patternformat checks
@Past, @Future, @PastOrPresentdates and times
@Valid on a fieldcascade into a nested object or list elements
10

Error Handling

ProblemDetail, @RestControllerAdvice and RFC 9457 responses

Problem Details

core

Turn them on for Spring MVC exceptions

spring.mvc.problemdetails.enabled=true

Map your exceptions with @RestControllerAdvice

@RestControllerAdvice
public class ApiErrors extends ResponseEntityExceptionHandler {

    @ExceptionHandler(OrderNotFoundException.class)
    ProblemDetail notFound(OrderNotFoundException ex) {
        ProblemDetail problem = ProblemDetail.forStatusAndDetail(HttpStatus.NOT_FOUND, ex.getMessage());
        problem.setType(URI.create("https://example.com/problems/order-not-found"));
        problem.setTitle("Order not found");
        problem.setProperty("orderId", ex.getId());
        return problem;
    }

    @Override
    protected ResponseEntity<Object> handleMethodArgumentNotValid(MethodArgumentNotValidException ex,
            HttpHeaders headers, HttpStatusCode status, WebRequest request) {
        ProblemDetail problem = ex.getBody();
        Map<String, String> errors = ex.getBindingResult().getFieldErrors().stream()
                .collect(Collectors.toMap(e -> e.getField(), e -> e.getDefaultMessage(), (a, b) -> a + "; " + b));
        problem.setProperty("errors", errors);
        return handleExceptionInternal(ex, problem, headers, status, request);
    }

}

The response for a missing order

curl -s -i localhost:8080/api/orders/9

A body that is not valid JSON

curl -s -u admin:change-me -X POST localhost:8080/api/orders -H "Content-Type: application/json" -d '{"sku":"LAMP-01","qty":2'
11

API Versioning

Spring Framework 7 versioned mappings and Boot 4 properties

Versioned Endpoints

everyday

Configure how the version is read

spring.mvc.apiversion.use.header=API-Version
spring.mvc.apiversion.default=1

Two versions of one endpoint

@GetMapping(path = "/{id}", version = "1")
public Order get(@PathVariable long id) {
    return service.find(id);
}

@GetMapping(path = "/{id}", version = "2")
public OrderView getV2(@PathVariable long id) {
    return OrderView.of(service.find(id));
}

Ask for version 2

curl -s -H "API-Version: 2" localhost:8080/api/orders/1

An unsupported version

curl -s -H "API-Version: 3" localhost:8080/api/orders/1
12

HTTP Clients

RestClient, HTTP service interfaces and timeouts

RestClient

core

A fluent, synchronous client

import org.springframework.web.client.RestClient;
import org.springframework.web.client.HttpClientErrorException;
import java.util.Map;

var client = RestClient.builder().baseUrl("https://httpbingo.org").build();
Map<?, ?> body = client.get().uri("/get?shop={name}", "demo").retrieve().body(Map.class);
System.out.println(body.get("args"));

try {
    client.get().uri("/status/404").retrieve().toBodilessEntity();
} catch (HttpClientErrorException.NotFound e) {
    System.out.println(e.getStatusCode() + " " + e.getClass().getSimpleName());
}

HTTP Service Interfaces

everyday

Declare the API as an interface

@HttpExchange("/anything")
public interface EchoClient {

    @GetExchange
    Map<String, Object> echo(@RequestParam String q);

}

@Configuration
@ImportHttpServices(group = "echo", types = EchoClient.class)
public class ClientsConfig {
}

Point the group at a server and call it

spring.http.serviceclient.echo.base-url=https://httpbingo.org
spring.http.serviceclient.echo.read-timeout=5s

Which Client

everyday

RestClient, WebClient, RestTemplate

ClientUse for
RestClientblocking code in Spring MVC apps; works well with virtual threads
HTTP service interfacetyped clients for APIs you call often
WebClientreactive code with WebFlux, or streaming
RestTemplateexisting code only; Spring Framework 7.1 milestones mark it @Deprecated(forRemoval = true)
13

Data JPA

entities, repositories, derived queries and paging

Entity and Repository

core

An entity

@Entity
@Table(name = "orders")
public class Order {

    public enum Status { PENDING, PAID, SHIPPED }

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @Column(nullable = false)
    private String sku;

    private int qty;

    @Enumerated(EnumType.STRING)
    private Status status = Status.PENDING;

    private BigDecimal total;

    private Instant createdAt = Instant.now();

    protected Order() {
    }

}

A repository with derived and custom queries

public interface OrderRepository extends JpaRepository<Order, Long> {

    Page<Order> findByStatus(Order.Status status, Pageable pageable);

    long countByStatus(Order.Status status);

    @Query("select o from Order o where o.total >= :min order by o.total desc")
    List<Order> findLarge(BigDecimal min);

}

Paging and sorting from the URL

curl -s "localhost:8080/api/orders?status=PAID&page=0&size=5&sort=total,desc"

Derived Query Keywords

everyday

Method names Spring Data understands

Method nameGenerated condition
findBySkuAndStatuswhere sku = ?1 and status = ?2
findByTotalGreaterThanEqualwhere total >= ?1
findByCreatedAtBetweenwhere created_at between ?1 and ?2
findBySkuIn(Collection)where sku in (?1)
findBySkuContainingIgnoreCasewhere upper(sku) like upper('%' + ?1 + '%')
findFirst10ByStatusOrderByCreatedAtDesctop 10 rows, newest first
existsBySku, countByStatus, deleteByStatusexists, count and delete queries

Settings That Matter

everyday

application.properties for JPA

spring.jpa.open-in-view=false
spring.jpa.hibernate.ddl-auto=validate
spring.jpa.show-sql=false
logging.level.org.hibernate.SQL=debug
14

Transactions

@Transactional rules and the proxy traps

@Transactional

core

On service methods

@Transactional(readOnly = true)
public Order find(long id) {
    return orders.findById(id).orElseThrow(() -> new OrderNotFoundException(id));
}

@Transactional
public Order create(NewOrder request) {
    return orders.save(new Order(request.sku(), request.qty(), priceFor(request)));
}

Why It Did Not Roll Back

everyday

The classic traps

SituationWhat happens
calling a @Transactional method from the same classno transaction: the call skips the proxy
@Transactional on a private methodignored
a checked exception is throwncommit, unless rollbackFor = Exception.class
the exception is caught inside the methodcommit
LazyInitializationException after the method returnedthe session is closed; fetch what you need with a join fetch or an entity graph
15

Database Migrations

Flyway and Liquibase with Boot

Flyway

core

Add the starter and a first script

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-flyway</artifactId>
</dependency>
<dependency>
    <groupId>org.flywaydb</groupId>
    <artifactId>flyway-database-postgresql</artifactId>
</dependency>

src/main/resources/db/migration/V1__create_orders.sql

create table orders (
    id bigint generated by default as identity primary key,
    sku varchar(40) not null,
    qty int not null,
    status varchar(16) not null,
    total numeric(10, 2) not null,
    created_at timestamp with time zone not null
);

Rules for Migrations

everyday

What keeps deployments safe

RuleWhy
set spring.jpa.hibernate.ddl-auto=validateHibernate checks the schema but never changes it
one change per script, forward onlyrollbacks are new scripts, not edits
expand, then contractadd the new column, deploy, migrate data, then drop the old one
same scripts in testsTestcontainers runs them against the real database engine
16

Security

SecurityFilterChain, users, HTTP Basic and JWT resource servers

A SecurityFilterChain

core

Public reads, admin writes

@Configuration
public class SecurityConfig {

    @Bean
    SecurityFilterChain api(HttpSecurity http) throws Exception {
        return http
                .authorizeHttpRequests(auth -> auth
                        .requestMatchers("/actuator/health/**", "/actuator/info").permitAll()
                        .requestMatchers(HttpMethod.GET, "/api/**").permitAll()
                        .requestMatchers("/error").permitAll()
                        .anyRequest().hasRole("ADMIN"))
                .httpBasic(Customizer.withDefaults())
                .csrf(csrf -> csrf.disable())
                .sessionManagement(s -> s.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
                .build();
    }

}

An anonymous write

curl -s -i -X POST localhost:8080/api/orders -H "Content-Type: application/json" -d '{"sku":"LAMP-01","qty":2}'

Users and Tokens

everyday

Development user from properties

spring.security.user.name=admin
spring.security.user.password=change-me
spring.security.user.roles=ADMIN

A JWT resource server

spring.security.oauth2.resourceserver.jwt.issuer-uri=https://login.example.com/realms/shop

Passwords

@Bean
PasswordEncoder passwordEncoder() {
    return PasswordEncoderFactories.createDelegatingPasswordEncoder();
}
17

Actuator

health, info, metrics and exposing endpoints safely

Exposing Endpoints

core

Choose what is reachable over HTTP

management.endpoints.web.exposure.include=health,info,metrics
management.endpoint.health.show-details=when-authorized
management.info.env.enabled=true
management.info.java.enabled=true
management.info.os.enabled=true
info.app.version=@project.version@

Health for anonymous callers

curl -s localhost:8080/actuator/health

One component, with credentials

curl -s -u admin:change-me localhost:8080/actuator/health/db

Build and runtime info

curl -s localhost:8080/actuator/info

Metrics

everyday

Request timings for one URI

curl -s -u admin:change-me "localhost:8080/actuator/metrics/http.server.requests?tag=uri:/api/orders/%7Bid%7D"

Endpoints worth knowing

EndpointShows
health, infostatus and build information
metrics, prometheusMicrometer meters
loggerslog levels, changeable at runtime with POST
env, configpropsresolved properties, with values masked by default
beans, conditions, mappingsapplication context, auto-configuration report, request mappings
threaddump, heapdumpdiagnostics; heapdump can contain secrets
sbomthe software bill of materials embedded at build time
shutdownstops the app; access is none by default
18

Logging

levels, files, groups and structured JSON logs

Levels and Files

core

Common settings

logging.level.root=info
logging.level.com.example.shop=debug
logging.level.org.hibernate.SQL=debug
logging.file.name=logs/shop.log
logging.group.persistence=org.hibernate,com.zaxxer.hikari
logging.level.persistence=warn

Structured Logging

everyday

JSON logs in Elastic Common Schema

java -jar target/shop-1.0.0.jar --logging.structured.format.console=ecs
19

Observability

Micrometer, tracing and the OpenTelemetry starter

OpenTelemetry

everyday

Export traces and metrics over OTLP

management.tracing.sampling.probability=0.1
management.opentelemetry.tracing.export.otlp.endpoint=http://otel-collector:4318/v1/traces

What gets instrumented

SignalSource
HTTP server and client timingsSpring MVC, RestClient and WebClient observations
database pool and queriesHikariCP metrics, and JDBC observations with an extra library
trace and span ids in logsadded to the log pattern and to structured logs automatically when tracing is on
your own code@Observed on methods, or the ObservationRegistry API
20

Testing

test slices, MockMvcTester, @MockitoBean, RestTestClient and Testcontainers

Test Slices

core

Load only what a test needs

AnnotationLoadsStarter
@WebMvcTest(OrderController.class)MVC infrastructure and one controllerspring-boot-starter-webmvc-test
@DataJpaTestJPA, repositories, an embedded database, rollback per testspring-boot-starter-data-jpa-test
@JsonTestJackson configurationspring-boot-starter-jackson-test
@RestClientTestRestClient with a mock serverspring-boot-starter-restclient-test
@SpringBootTestthe whole application contextspring-boot-starter-test

A controller test with MockMvcTester and @MockitoBean

@WebMvcTest(OrderController.class)
@Import(SecurityConfig.class)
class OrderControllerTest {

    @Autowired
    MockMvcTester mvc;

    @MockitoBean
    OrderService service;

    @Test
    void returnsOrder() {
        given(service.find(1)).willReturn(new Order("LAMP-01", 1, new BigDecimal("39.50")));
        assertThat(mvc.get().uri("/api/orders/1"))
                .hasStatusOk()
                .bodyJson().extractingPath("$.sku").isEqualTo("LAMP-01");
    }

    @Test
    void missingOrderIsProblemJson() {
        given(service.find(9)).willThrow(new OrderNotFoundException(9));
        assertThat(mvc.get().uri("/api/orders/9"))
                .hasStatus(HttpStatus.NOT_FOUND)
                .bodyJson().extractingPath("$.title").isEqualTo("Order not found");
    }

}

A full HTTP test with RestTestClient

@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
@AutoConfigureRestTestClient
class ShopApplicationTests {

    @Autowired
    RestTestClient client;

    @Test
    void ordersEndpointWorksOverHttp() {
        client.get().uri("/api/orders/1").header("API-Version", "2")
                .exchange()
                .expectStatus().isOk()
                .expectBody().jsonPath("$.total.currency").isEqualTo("EUR");
    }

}

Run the suite

./mvnw test

Testcontainers

everyday

A real database with @ServiceConnection

@TestConfiguration(proxyBeanMethods = false)
class TestcontainersConfig {

    @Bean
    @ServiceConnection
    PostgreSQLContainer postgres() {
        return new PostgreSQLContainer("postgres:18");
    }

}
21

Scheduling & Async

@Scheduled, cron expressions and @Async

@Scheduled

core

Run a method on a schedule

@Configuration
@EnableScheduling
class SchedulingConfig {
}

@Component
class ReportJob {

    @Scheduled(cron = "0 0 9 * * MON-FRI", zone = "Europe/Bucharest")
    void dailyReport() {
    }

    @Scheduled(fixedDelayString = "${shop.sync-interval:5m}")
    void syncStock() {
    }

}

Spring cron has six fields

import org.springframework.scheduling.support.CronExpression;
import java.time.LocalDateTime;

var cron = CronExpression.parse("0 0 9 * * MON-FRI");
var t = LocalDateTime.of(2026, 10, 16, 10, 0);
for (int i = 0; i < 3; i++) {
    t = cron.next(t);
    System.out.println(t + " " + t.getDayOfWeek());
}
System.out.println(CronExpression.parse("@hourly").next(LocalDateTime.of(2026, 10, 16, 10, 20)));
22

Resilience

@Retryable and @ConcurrencyLimit in Spring Framework 7

Retries Without Extra Libraries

everyday

@Retryable with backoff

@SpringBootApplication
@EnableResilientMethods
public class ShopApplication {
}

@Component
public class InventoryClient {

    @Retryable(includes = IllegalStateException.class, maxRetries = 3, delay = 100, multiplier = 2)
    public int stockFor(String sku) {
        return callInventoryService(sku);
    }

}

Two failures, then success

java -jar target/shop-1.0.0.jar --spring.profiles.active=demo

Limit concurrent calls

@ConcurrencyLimit(10)
public Report render(long id) {
    return renderer.render(id);
}
23

Virtual Threads

one property for Tomcat, executors and schedulers

Virtual Threads

everyday

Turn them on

spring.threads.virtual.enabled=true

What to watch

ConcernAdvice
connection poolsthe database pool, not threads, becomes the limit; size it deliberately
pinningsince Java 24, synchronized no longer pins a virtual thread to its carrier, so the old advice to avoid it is mostly obsolete
ThreadLocal-heavy librariesmany short-lived threads multiply per-thread caches
CPU-bound workgains nothing; virtual threads help with waiting, not computing
24

Packaging & Docker

executable jars, layers, Dockerfiles and buildpacks

The Executable Jar

core

Build it and look inside

./mvnw -q package -Dmaven.test.skip=true
ls -l --block-size=M target/shop-1.0.0.jar

The tools jar mode

java -Djarmode=tools -jar target/shop-1.0.0.jar help

Layers for container images

java -Djarmode=tools -jar target/shop-1.0.0.jar list-layers

Dockerfile

core

Multi-stage build with extracted layers

FROM eclipse-temurin:25-jre AS builder
WORKDIR /builder
COPY target/*.jar application.jar
RUN java -Djarmode=tools -jar application.jar extract --layers --destination extracted

FROM eclipse-temurin:25-jre
WORKDIR /application
COPY --from=builder /builder/extracted/dependencies/ ./
COPY --from=builder /builder/extracted/spring-boot-loader/ ./
COPY --from=builder /builder/extracted/snapshot-dependencies/ ./
COPY --from=builder /builder/extracted/application/ ./
ENTRYPOINT ["java", "-XX:MaxRAMPercentage=75", "-jar", "application.jar"]

No Dockerfile at all

./mvnw spring-boot:build-image -Dspring-boot.build-image.imageName=shop:1.0.0
25

Native Images & AOT

GraalVM native executables and their trade-offs

GraalVM Native Image

advanced

Build a native executable

./mvnw -Pnative native:compile
./target/shop

JVM or native

TraitJVM jarNative executable
startupsecondstens of milliseconds
peak throughputhigher, thanks to the JIT compilerlower without profile-guided optimization
build timesecondsminutes, with several GB of RAM
profiles and @Conditionalevaluated at startupfixed at build time
reflection and dynamic proxiesworkneed hints for code Spring cannot see
26

Upgrading to Boot 4

from Spring Boot 3.5 to 4.x, step by step

Before and After

core

The changes most applications hit

AreaSpring Boot 4
baselineJava 17+, Jakarta EE 11, Servlet 6.1, Spring Framework 7, Kotlin 2.2+
JSONJackson 3, packages tools.jackson; JsonMapper replaces ObjectMapper beans; @JsonComponent is now @JacksonComponent
startersmodular, with -test companions; spring-boot-starter-web is now spring-boot-starter-webmvc
tests@MockBean and @SpyBean removed; MockMvc and TestRestTemplate need explicit @AutoConfigure... annotations
serversTomcat 11 or Jetty 12.1; Undertow support removed
actuatormanagement.endpoint.<id>.enabled replaced by .access
packagingembedded launch scripts removed; layertools jar mode removed in 4.1
null safetyJSpecify annotations across the Spring portfolio

Let Boot report renamed properties

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-properties-migrator</artifactId>
    <scope>runtime</scope>
</dependency>

Jackson 2 as a stop-gap

spring.jackson.use-jackson2-defaults=true
27

Troubleshooting

the startup failures and errors people search for

Startup Failures

core

Port already in use

java -jar target/shop-1.0.0.jar

Messages and fixes

MessageCause and fix
Failed to configure a DataSource: 'url' attribute is not specifieda JDBC or JPA starter without a database URL or embedded database; set spring.datasource.url or add H2 for development
Parameter 0 of ... required a bean of type '...' that could not be foundthe class is outside the scanned package, missing @Component, or its auto-configuration's condition failed; run with --debug
The dependencies of some of the beans in the application context form a cycletwo beans inject each other; move shared logic to a third bean
Binding to target ... faileda property has the wrong type or fails validation; the report names its origin
Whitelabel Error Pageno controller matched and no error view exists; check the URL and the HTTP method
Web server failed to start. Port 8080 was already in usesee above

Runtime Surprises

everyday

401 for a URL that does not exist

curl -s localhost:8080/nope

A primary key conflict after seeding data.sql


        

More symptoms

SymptomUsual cause
LazyInitializationExceptionentity fields loaded after the transaction ended; fetch them in the query
changes in application.properties ignoredthe file is in the wrong folder, a profile file overrides it, or an environment variable wins
@Transactional, @Async or @Retryable does nothingthe method is called from the same class, or is private
JSON field names or dates look different after upgradingJackson 3 defaults; try spring.jackson.use-jackson2-defaults=true while migrating
slow startupcomponent scanning a large package, eager JPA validation, or too many auto-configurations; check the startup endpoint
28

Versions

Spring Boot releases, support dates and managed dependencies

Release Line

core

Generations and open-source support

VersionFirst releaseOSS support until
4.2planned for November 2026; 4.2.0-M2 on September 24, 2026December 31, 2027
4.1June 10, 2026; 4.1.1 on August 20, 2026July 31, 2027
4.0November 20, 2025; 4.0.8 on August 21, 2026December 31, 2026
3.5May 2025; 3.5.16 on June 25, 2026ended June 30, 2026

Inside Boot 4.1.1

everyday

Managed versions in the shop app

ComponentVersion
Spring Framework7.0.9
Spring Security7.1.1
Spring Data JPA4.1.1
Hibernate ORM7.4.5.Final
Hibernate Validator9.1.3.Final
Jackson3.1.5
Tomcat11.0.24
HikariCP7.0.2
Micrometer1.17.1
JUnit Jupiter6.0.3
H22.4.240

What Is a Spring Boot Cheat Sheet

A Spring Boot cheat sheet is a compact reference to the parts of Spring Boot developers use every day: the starters and build setup, application.properties and profiles, the annotations behind dependency injection and REST controllers, Spring Data JPA, security, actuator and testing. People also search for a Spring Boot annotations cheat sheet or a Spring Boot quick reference; they usually want the same thing while building a service or upgrading one.

This cheat sheet covers 28 sections and 101 snippets for Spring Boot 4. The output under the examples comes from a real shop service built from start.spring.io on Spring Boot 4.1.1 and Java 25 and run on October 14, 2026: the startup log, every curl response, the failure messages, the conditions report and the test results.

The toolbox at the top checks an application.properties or application.yml file against the 201 properties that Spring Boot 4.0 and 4.1 renamed or removed, and flags risky settings. It also converts between properties and YAML, shows each key as an environment variable and a command-line argument, and explains Spring cron expressions with their next run times. The builders write a Maven or Gradle build file with the Boot 4 starters, an entity with its repository and REST controller, database configuration for six databases and a layered Dockerfile. Nothing you paste is sent anywhere.

How It Differs From the Reference Documentation

The Spring Boot reference documentation explains every feature in depth. This page puts the parts you look up during real work side by side and marks what changed in Boot 4, from the modular starters to the removal of @MockBean. For the API design side, see the REST API cheat sheet and the HTTP status codes cheat sheet; for the language itself, the Java cheat sheet.


What This Spring Boot Cheat Sheet Covers

The 28 sections follow the life of a service, and each link jumps to that section above.


Spring Boot Quick Reference

The annotations and settings people look up most often, one line each.

TaskUse
Main class@SpringBootApplication
REST endpoint@RestController, @GetMapping("/{id}")
Read the request@PathVariable, @RequestParam, @RequestBody
Validate input@Valid plus @NotBlank, @Min
Typed settings@ConfigurationProperties("shop") on a record
Change the portserver.port=8081 or SERVER_PORT=8081
Activate a profile--spring.profiles.active=prod
Repositoryinterface OrderRepository extends JpaRepository<Order, Long>
Transaction@Transactional on a public service method
Error bodyProblemDetail from @RestControllerAdvice
Mock a bean in tests@MockitoBean
Health checkGET /actuator/health

What Spring Boot Is

Spring Boot is an open-source framework from the Spring team, now part of Broadcom, for building production-ready Java and Kotlin applications on top of the Spring Framework. Version 1.0 shipped in 2014; Spring Boot 4.0 followed on November 20, 2025, and the current release, 4.1.1, on August 20, 2026.

Boot makes three decisions for you. Auto-configuration sets up components based on what is on the classpath, such as a DataSource when a JDBC driver is present. Starters bundle compatible dependency versions. And the build plugins package the application with an embedded server into one jar that runs with java -jar, in a container or as a native executable.

Spring Boot is the most common choice for Java back-end development, from monoliths to microservices, and a frequent target of API integration work in enterprises.

Where It Fits

Spring Boot suits teams that want a mature, well-documented stack with first-class support for databases, security, messaging and observability. Lighter frameworks such as Quarkus and Micronaut compete on startup time and memory, a gap that Boot's native image support and virtual threads narrow considerably.


How a Request Flows Through Spring Boot

Following one request through the shop service explains where each part of this page applies.

  1. Tomcat accepts the connection and, with virtual threads enabled, hands the request to a new virtual thread.
  2. The Spring Security filter chain authenticates the caller and checks the rules, answering 401 or 403 when they fail.
  3. The DispatcherServlet picks a controller method by path, HTTP method and API version.
  4. Arguments are bound from the path, query and JSON body, and @Valid runs Bean Validation.
  5. The controller calls a service; @Transactional opens a transaction around the repository calls.
  6. Spring Data JPA runs the query through Hibernate and HikariCP.
  7. Jackson 3 writes the result as JSON, or @RestControllerAdvice turns an exception into a problem detail, and Micrometer records the timing.

Common Spring Boot Mistakes

The same problems show up in most code reviews of Spring Boot services.

In Configuration

  • Leaving spring.jpa.open-in-view at its default of true.
  • Using ddl-auto=update against a shared database instead of Flyway or Liquibase.
  • Exposing every actuator endpoint with exposure.include=* on a public port.
  • Committing passwords in application.properties instead of reading them from the environment.
  • Field injection with @Autowired, which hides dependencies and complicates tests.

In Code

  • Calling a @Transactional, @Async or @Retryable method from the same class and expecting the annotation to apply.
  • Returning JPA entities straight from controllers, which couples the API to the table and triggers lazy-loading errors.
  • Catching exceptions in controllers instead of mapping them once in @RestControllerAdvice.
  • HTTP clients without timeouts.
  • Testing everything with @SpringBootTest instead of faster slices such as @WebMvcTest and @DataJpaTest.

How to Build Good Spring Boot Services

Keep the Layers Honest

Controllers translate HTTP, services hold business rules and transactions, repositories talk to the database. Keep configuration typed with @ConfigurationProperties records, validate it at startup, and let every environment override only what differs. Run the build and tests in continuous integration on every change.

Then Test and Watch It

Use test slices for speed and Testcontainers for the database you run in production, as the guide to types of software testing describes. Expose health and metrics through actuator, ship structured logs and traces, and check them after each deployment. The Docker cheat sheet and Kotlin cheat sheet cover the container and language side.


How This Spring Boot Cheat Sheet Is Maintained

This page is written and maintained by Bogdan Sandu for TMS Outsource, a software development company. It was checked on October 14, 2026 against the Spring Boot reference documentation, the Spring Boot 4.0 migration guide, the 4.0 and 4.1 release notes and configuration changelogs, and Spring's support timeline. The output of the examples was produced by running a Spring Boot 4.1.1 application on Eclipse Temurin 25 with Maven 3.10, curl and jshell. If a snippet is wrong or out of date, the date in the byline shows when it was last reviewed.


Spring Boot Questions People Actually Ask

The questions developers search for most about Spring Boot, answered in a few sentences each.

What is Spring Boot?

Spring Boot is a framework for building Java and Kotlin applications on top of the Spring Framework with almost no setup. It configures components automatically based on the libraries on the classpath, embeds a web server such as Tomcat, and packages the application as one executable jar, so a REST service runs with java -jar.

What is new in Spring Boot 4?

Spring Boot 4.0, released on November 20, 2025, moved to Spring Framework 7, Jakarta EE 11 and Jackson 3, split auto-configuration into modular starters with test companions, added API versioning, HTTP service client configuration, RestTestClient and an OpenTelemetry starter, and removed Undertow support and @MockBean. Spring Boot 4.1 followed on June 10, 2026.

Which Java version does Spring Boot 4 need?

Spring Boot 4 requires Java 17 or later and recommends the latest LTS release, which is Java 25. Kotlin 2.2 or later is supported, and native images need GraalVM 25 or later.

What is the difference between application.properties and application.yml?

Both hold the same configuration; YAML nests keys and suits lists, while .properties is flat and simpler to override. Boot reads either, and if both exist in the same location, the .properties file takes precedence.

How do I change the port in Spring Boot?

Set server.port=8081 in application.properties, pass --server.port=8081 on the command line, or set the SERVER_PORT environment variable. server.port=0 picks a random free port, which is useful in tests.

What does @SpringBootApplication do?

It combines @Configuration, @EnableAutoConfiguration and @ComponentScan. The class is the configuration root, auto-configuration is switched on, and every component in its package and subpackages is registered as a bean.

What replaced @MockBean in Spring Boot 4?

@MockBean and @SpyBean were removed in Spring Boot 4. Use @MockitoBean and @MockitoSpyBean from Spring Framework, which work on test class fields and can also be placed on the test class with a types attribute.

How do I upgrade from Spring Boot 3 to 4?

Upgrade to the latest 3.5.x and remove deprecation warnings, then switch to Boot 4, rename starters such as spring-boot-starter-web to spring-boot-starter-webmvc, add the test starters, migrate Jackson code to the tools.jackson packages, replace @MockBean, and add spring-boot-properties-migrator to find renamed properties.

Is this Spring Boot cheat sheet up to date?

Yes. It was checked on October 14, 2026 against Spring Boot 4.1.1, Spring Framework 7.0.9, Spring Security 7.1.1, the Boot 4.0 migration guide and the 4.0 and 4.1 configuration changelogs. The example outputs come from a real Boot 4.1.1 application running on Java 25.

Can I download this Spring Boot cheat sheet as a PDF?

Yes. The page has a print stylesheet, so your browser's print command with Save as PDF produces a clean copy with every output and explanation expanded and the navigation left out. The print core button prints only the core snippets for a short reference.