Creating a Project with Spring Initializr

Generate a working Spring Boot project at start.spring.io, choose the build tool, Java version and starters, and know what each choice commits you to.

Syntaxcurl https://start.spring.io/starter.zip \ -d type=maven-project -d javaVersion=25 \ -d dependencies=web,validation \ -o app.zip

Spring Initializr at start.spring.io generates a ready-to-build project: build file, wrapper scripts, main class, a first test and an empty configuration file. IntelliJ IDEA, VS Code and Eclipse call the same service from their "new project" wizards, so the result is identical wherever you start.

The choices that matter

  • Project: Maven or Gradle (Groovy or Kotlin DSL). Both are fully supported. Maven is more common in Spring examples; Gradle builds faster on large projects. Pick what your team already runs in CI.
  • Spring Boot version: choose the latest release without a suffix. SNAPSHOT and milestone versions are previews and do not belong in a project you will deploy.
  • Group, Artifact and Package name: the group is usually a reversed domain (com.example), the artifact becomes the jar name. Check the package name: a dash in the artifact is turned into something legal, and the result may not be what you want.
  • Packaging: Jar. War is only for deploying into an existing external servlet container.
  • Java: the version your servers and containers actually run. A project compiled for 25 will not start on a 21 runtime.

Picking dependencies

For a typical REST API: Spring Web, Validation, Spring Data JPA, a database driver such as PostgreSQL, and optionally Spring Boot DevTools, Docker Compose Support and Spring Boot Actuator. Initializr adds the matching test starters for you. Resist ticking everything: each starter switches on auto-configuration, and a starter for a database or broker you do not run either stops the application starting or leaves it logging connection errors and reporting itself unhealthy.

What you get

Unzip and run ./mvnw spring-boot:run (or ./gradlew bootRun). The wrapper downloads the right Maven or Gradle version, so nothing needs installing except a JDK. Commit the wrapper scripts and the .mvn or gradle folder: CI and every developer then build with the same tool version.

The first failure most people hit

Add Spring Data JPA and a PostgreSQL driver, and the generated contextLoads test fails straight away: there is no database URL, and no database. For running the application, Docker Compose Support starts the database from compose.yaml. It is skipped in tests by default (spring.docker.compose.skip.in-tests is true), so give tests their own database with Testcontainers, or point spring.datasource.url at one. The failure is useful; it means auto-configuration found the driver and tried to build a connection pool.

Example

Example · bash

# Generate the same project the website would, from a script or CI job.
curl https://start.spring.io/starter.zip \
  -d type=maven-project \
  -d language=java \
  -d javaVersion=25 \
  -d groupId=com.example \
  -d artifactId=orders \
  -d packageName=com.example.orders \
  -d dependencies=web,validation,data-jpa,postgresql,docker-compose,actuator,devtools \
  -o orders.zip

unzip orders.zip -d orders && cd orders
# Docker Compose Support starts PostgreSQL from the generated compose.yaml (Docker must be running).
./mvnw spring-boot:run

When to use it

  • Bootstrap a new REST service with web, validation, JPA and PostgreSQL in under a minute.
  • Script project generation in a platform team's template so every service starts with the same Java version and starters.
  • Compare what a dependency adds to the build file before adding it to an existing project.

More examples

The dependencies section it generates

None of the Spring dependencies carry a version; the starter parent supplies them. The driver is runtime scope because your code talks to JDBC and JPA interfaces, never to PostgreSQL classes directly. Each starter has a matching test starter in Boot 4, which brings the slice test annotations for that technology.

Example · xml
<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-webmvc</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-validation</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-jpa</artifactId>
    </dependency>
    <dependency>
        <groupId>org.postgresql</groupId>
        <artifactId>postgresql</artifactId>
        <scope>runtime</scope>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-webmvc-test</artifactId>
        <scope>test</scope>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-jpa-test</artifactId>
        <scope>test</scope>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-validation-test</artifactId>
        <scope>test</scope>
    </dependency>
</dependencies>

The same project with the Gradle Kotlin DSL

The toolchain block makes Gradle compile with Java 25 even if the shell's default JDK is older, which removes a whole class of "works on my machine" failures. The dependency-management plugin applies Boot's managed versions, the same job the parent POM does for Maven, so the starters need no versions. Keep useJUnitPlatform(): without it the test task silently runs nothing.

Example · kotlin
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-validation")
    implementation("org.springframework.boot:spring-boot-starter-data-jpa")
    runtimeOnly("org.postgresql:postgresql")
    testImplementation("org.springframework.boot:spring-boot-starter-webmvc-test")
    testImplementation("org.springframework.boot:spring-boot-starter-validation-test")
    testImplementation("org.springframework.boot:spring-boot-starter-data-jpa-test")
    testRuntimeOnly("org.junit.platform:junit-platform-launcher")
}

tasks.withType<Test> {
    // Without this Gradle finds no JUnit Jupiter tests and the build passes with zero tests run.
    useJUnitPlatform()
}

The test it generates, and why it fails

An empty test that starts the whole application is a cheap smoke test: it catches missing configuration and broken bean wiring before anything is deployed. Keep it, but give it a database, for example a Testcontainers PostgreSQL container, rather than deleting it to make the build pass. Docker Compose Support does not help here: it is skipped in tests by default.

Example · java
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;

@SpringBootTest
class OrdersApplicationTests {

    @Test
    void contextLoads() {
        // Passes only if every auto-configured bean can be created,
        // including the DataSource. With JPA on the classpath and no
        // database URL, this is where the build first turns red.
    }
}

Discussion

  • Be the first to comment on this lesson.