Setting Up a Spring Boot Project

Reviewed & published by Brayan K

Use Spring Initializr to scaffold a project in seconds, understand the standard layout, the @SpringBootApplication main class, and how Maven or Gradle wires it all together into a runnable app.

Part of the free Java course at LearnCodingFast — hands-on lessons with worked examples and the output they print, plus practice exercises and a quick quiz.

Before You Start

Read the Introduction to Spring & Spring Boot first, and make sure you understand annotations, since the whole setup is annotation-driven.

What You'll Learn

The Big Idea — A Pre-Furnished Apartment

💡 Analogy: Spring Initializr is like moving into a pre-furnished apartment: the rooms (folders) are already laid out, the utilities (build file, plugins) are connected, and a working light switch (the main class) is installed. You just walk in and start living — adding your own furniture (controllers, services) where it belongs.

The standard layout is a convention every Spring developer recognises, so anyone can find their way around your project instantly.

1️⃣ Generate the Skeleton with Spring Initializr

At start.spring.io you pick the build tool (Maven/Gradle), language, Boot version, project metadata and the starters you need. It downloads a zip with the build file, layout and a ready-to-run main class.

2️⃣ The @SpringBootApplication Main Class

The generated main class carries @SpringBootApplication and a main that calls SpringApplication.run(...). Keep it at the root of your package tree so component scanning discovers everything below it.

// src/main/java/com/example/demo/DemoApplication.java
package com.example.demo;

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

@SpringBootApplication        // enables config, auto-config and component scan
public class DemoApplication {
    public static void main(String[] args) {
        // ONE line bootstraps the whole application.
        SpringApplication.run(DemoApplication.class, args);
    }
}

3️⃣ The Build File — Maven or Gradle

The parent (Maven) or Boot plugin (Gradle) manages compatible versions, you declare starters as dependencies, and the Boot plugin repackages a runnable jar.

<!-- pom.xml (Maven) -->
<project>
    <parent>
        <!-- The parent manages compatible dependency versions for you. -->
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>3.3.0</version>
    </parent>

    <groupId>com.example</groupId>
    <artifactId>demo</artifactId>
    <version>0.0.1-SNAPSHOT</version>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>  <!-- REST + Tomcat -->
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>  <!-- testing -->
            <scope>test</scope>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <!-- Repackages into a runnable jar and adds spring-boot:run. -->
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
</project>
// build.gradle (Gradle alternative — same starters, different syntax)
plugins {
    id 'java'
    id 'org.springframework.boot' version '3.3.0'
    id 'io.spring.dependency-management' version '1.1.5'
}

group = 'com.example'
version = '0.0.1-SNAPSHOT'

dependencies {
    implementation 'org.springframework.boot:spring-boot-starter-web'
    testImplementation 'org.springframework.boot:spring-boot-starter-test'
}

4️⃣ The Standard Project Layout

Every Spring Boot project follows the same Maven-standard directory structure, so any developer can navigate it instantly. Code in src/main/java, config in src/main/resources, tests in src/test/java.

demo/
├── pom.xml                         (or build.gradle)
├── src/
│   ├── main/
│   │   ├── java/
│   │   │   └── com/example/demo/
│   │   │       └── DemoApplication.java   <-- @SpringBootApplication + main()
│   │   └── resources/
│   │       ├── application.properties      <-- externalised config
│   │       ├── static/                     <-- static web assets
│   │       └── templates/                  <-- view templates (if used)
│   └── test/
│       └── java/                           <-- tests mirror the main packages
└── target/                                  <-- build output (the runnable jar)

// RUN IT:  ./mvnw spring-boot:run        (Maven wrapper)
//   or:    java -jar target/demo-0.0.1-SNAPSHOT.jar
# src/main/resources/application.properties
# Externalised configuration — change behaviour WITHOUT recompiling.

server.port=8081                     # serve on 8081 instead of the default 8080
spring.application.name=demo

# Example datasource settings (used once you add a DB starter):
# spring.datasource.url=jdbc:h2:mem:testdb
# spring.jpa.hibernate.ddl-auto=update

5️⃣ What Scanning and Config Do, in Plain Java (runnable)

Two of the things SpringApplication.run(...) does at startup have no magic in them. Component scanning is a prefix match on package names, starting from the main class's package and walking down. Reading application.properties is a map lookup with a default. Modelling both in ordinary Java also explains the first Common Error below: a main class placed too deep simply does not match the classes above it.

// Two things SpringApplication.run(...) does, modelled in plain Java:
//   1. component scan — find every class under the main class's package
//   2. read application.properties, falling back to a default
// No Spring is involved; this is the mechanism, not the framework.
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

public class ScanDemo {
    // Pretend this is what the classpath contains (fully qualified class names).
    static final List<String> CLASSPATH = List.of(
        "com.example.demo.DemoApplication",
        "com.example.demo.web.HelloController",
        "com.example.demo.service.GreetingService",
        "com.other.tools.StrayHelper"            // NOT under com.example.demo
    );

    // Pretend this is application.properties, already parsed.
    static final Map<String, String> PROPS = Map.of(
        "server.port", "8081",
        "spring.application.name", "demo"
    );

    // @ComponentScan starts at the main class's package and walks DOWN from it.
    static List<String> componentScan(String rootPackage) {
        List<String> found = new ArrayList<>();
        for (String cls : CLASSPATH) {
            if (cls.startsWith(rootPackage + ".")) found.add(cls);
        }
        return found;
    }

    public static void main(String[] args) {
        String root = "com.example.demo";
        System.out.println("scanning " + root + " ...");
        for (String bean : componentScan(root)) {
            System.out.println("  found " + bean);
        }
        String port = PROPS.getOrDefault("server.port", "8080");
        String name = PROPS.getOrDefault("spring.application.name", "application");
        System.out.println("Started " + name + " on port " + port);
    }
}

🎯 YOUR TURN — Scan the shop app and default the port

The main class is com.shop.ShopApplication and the properties set a name but no port. Pick the scan root that finds all three shop classes, then fall back to Spring Boot's default port. Replace each ___ with the value in its hint, then compile and run it.

// 🎯 YOUR TURN — pick the right scan root and fall back to the default port.
// This app's main class lives in com.shop, and its properties file sets a
// name but NOT a port — so the port must come from the default.
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

public class ShopApp {
    static final List<String> CLASSPATH = List.of(
        "com.shop.ShopApplication",
        "com.shop.web.CartController",
        "com.shop.data.OrderRepository",
        "org.thirdparty.Metrics"
    );

    static final Map<String, String> PROPS = Map.of("spring.application.name", "shop");

    static List<String> componentScan(String rootPackage) {
        List<String> found = new ArrayList<>();
        for (String cls : CLASSPATH) {
            if (cls.startsWith(rootPackage + ".")) found.add(cls);
        }
        return found;
    }

    public static void main(String[] args) {
        // 1) Scan from the package that holds ShopApplication (not a sub-package).
        List<String> beans = componentScan(___);          // 👉 replace ___ with "com.shop"
        System.out.println("beans found: " + beans.size());

        // 2) No server.port in PROPS, so use Spring Boot's default port.
        String port = PROPS.getOrDefault("server.port", ___);   // 👉 replace ___ with "8080"
        System.out.println("Started " + PROPS.get("spring.application.name") + " on port " + port);
    }
}

// ✅ Expected output:
// beans found: 3
// Started shop on port 8080

🧠 Quick Recall

Predict before you peek.

Answer: component scanning starts from its package, so beans in sub-packages are only found if they live below it.

Answer: in src/main/resources/application.properties with server.port=8081 — no recompile needed.

Answer: the spring-boot-maven-plugin repackages it into an executable 'fat' jar with the embedded server inside.

Common Errors

Pro Tips

📋 Quick Reference

ItemWhere / syntaxNote
scaffoldstart.spring.ioSpring Initializr
main class@SpringBootApplicationAt package root
launchSpringApplication.run()Inside main()
Maven depspom.xmlDeclare starters
Gradle depsbuild.gradleAlternative
sourcesrc/main/javaProduction code
configapplication.propertiessrc/main/resources
run (dev)mvnw spring-boot:runOr java -jar

📚 Resources / Keep Learning

🎉 Lesson Complete!

You can now scaffold a project with Spring Initializr, recognise the standard layout, understand the @SpringBootApplication main class and SpringApplication.run(), and know where dependencies and configuration live in Maven or Gradle.

Practice quiz

What is Spring Initializr (start.spring.io)?

  • A web tool that generates a starter Spring Boot project skeleton
  • A database admin console
  • A Java compiler
  • A package manager for npm

Answer: A web tool that generates a starter Spring Boot project skeleton. Spring Initializr lets you pick build tool, language, Boot version and dependencies, then downloads a ready-to-run project.

On which class do you place @SpringBootApplication?

  • Every service class
  • The main application class that contains main()
  • The pom.xml
  • Every controller

Answer: The main application class that contains main(). @SpringBootApplication goes on the single main class whose main() method calls SpringApplication.run(...).

Why should the main class live at the root of your package tree?

  • For shorter file names
  • Component scanning starts from its package, so it finds sub-package beans
  • Java requires it
  • To avoid imports

Answer: Component scanning starts from its package, so it finds sub-package beans. @ComponentScan (inside @SpringBootApplication) scans the main class's package and below, so beans must live under it.

Which line actually launches the application inside main()?

  • new Application();
  • System.out.println(...)
  • SpringApplication.run(App.class, args);
  • Application.start();

Answer: SpringApplication.run(App.class, args);. SpringApplication.run(App.class, args) creates the context, runs auto-configuration and starts the server.

What is a Spring Boot 'starter' dependency?

  • A single jar with no transitive dependencies
  • A curated bundle of compatible dependencies for a use case
  • A test framework only
  • An IDE plugin

Answer: A curated bundle of compatible dependencies for a use case. A starter such as spring-boot-starter-web pulls in a coherent set of libraries so you don't hand-pick versions.

In a Maven Spring Boot project, where are dependencies declared?

  • build.gradle
  • package.json
  • pom.xml
  • settings.xml

Answer: pom.xml. Maven projects declare dependencies in pom.xml; Gradle projects use build.gradle instead.

Which build tools does Spring Initializr support out of the box?

  • Only Maven
  • Maven and Gradle
  • Only Gradle
  • Only Ant

Answer: Maven and Gradle. Initializr lets you choose either Maven or Gradle as the build tool for the generated project.

Where do non-code settings like server.port usually go?

  • pom.xml
  • src/main/resources/application.properties (or .yml)
  • The main method
  • README.md

Answer: src/main/resources/application.properties (or .yml). Externalised configuration lives in application.properties or application.yml under src/main/resources.

What does the spring-boot-maven-plugin enable?

  • Building a runnable 'fat' jar and running the app with the plugin
  • Compiling TypeScript
  • Generating UML
  • Encrypting passwords

Answer: Building a runnable 'fat' jar and running the app with the plugin. The Boot Maven plugin repackages the app into an executable jar and provides the spring-boot:run goal.

In the standard layout, where does application code live?

  • src/test/java
  • src/main/java
  • target/
  • src/main/resources

Answer: src/main/java. Production Java source lives under src/main/java; tests go in src/test/java and resources in src/main/resources.

Continue this course

Frequently asked questions

How do I create a new Spring Boot project?

The standard way is Spring Initializr at start.spring.io. You choose the build tool (Maven or Gradle), the language (Java), the Spring Boot version, your project metadata (group, artifact, package name), the Java version, and a set of dependencies (starters) such as Spring Web, Spring Data JPA or Validation. Initializr then generates a downloadable zip containing the build file, the standard directory layout, and a ready-to-run main class annotated with @SpringBootApplication. Most IDEs (IntelliJ IDEA, Spring Tools for Eclipse, VS Code) embed Initializr so you can generate the same project without leaving the editor.

What does the @SpringBootApplication main class do?

It is the bootstrap of the whole application. The annotation @SpringBootApplication combines @Configuration, @EnableAutoConfiguration and @ComponentScan, and the main method calls SpringApplication.run(DemoApplication.class, args). That single call creates the ApplicationContext (the IoC container), scans the main class's package and sub-packages for your beans, runs auto-configuration to wire sensible defaults from the classpath, and — for a web application — starts the embedded server. Because component scanning begins at the main class's package, you should keep this class at the root of your package tree so all your sub-package beans are discovered.

What is the difference between Maven and Gradle here?

Both are build tools that compile your code, manage dependencies, run tests and package the app; Spring Initializr supports either. Maven uses an XML file (pom.xml) and is highly conventional and widely documented. Gradle uses a Groovy or Kotlin script (build.gradle) and tends to be more concise and faster for incremental builds. The Spring concepts are identical regardless of choice: you declare the same starters, place @SpringBootApplication on the main class, and run the app the same way. Pick whichever your team already uses; for learning, Maven's verbose XML can be easier to read while Gradle's brevity is appealing once you're comfortable.

Where do I put configuration like the server port or database URL?

In an externalised configuration file under src/main/resources — application.properties (key=value) or application.yml (YAML). For example, server.port=8081 changes the HTTP port, and spring.datasource.url configures the database once you add a data starter. Keeping these out of code means you can change behaviour without recompiling, and you can supply environment-specific values via profiles (application-dev.properties), environment variables, or command-line arguments. Spring Boot reads these automatically at startup as part of its relaxed, layered configuration model.

How do I actually run the generated project?

There are two common ways. During development, use the build tool: ./mvnw spring-boot:run for Maven or ./gradlew bootRun for Gradle (the wrapper scripts mean you don't even need the tool installed globally). For deployment, build the executable 'fat' jar with ./mvnw package, then launch it with java -jar target/demo-0.0.1-SNAPSHOT.jar. Because Spring Boot embeds the server inside that jar, this single command starts the entire application — no external Tomcat needed. The spring-boot-maven-plugin (or the Gradle Boot plugin) is what repackages the jar to make it runnable.

Related lessons