# Spring Boot Basics — Auto-configuration, Starters, application.properties and Profiles

Source: https://skills101.in/learn/spring-boot/spring-boot-basics — Skills101 free tutorial (Advanced Java & Spring Boot). Updated 2026-11-09.

Plain Spring needs a lot of setup: configure a web server, a database connection pool, JSON conversion, transactions… **Spring Boot** does all of that for you with sensible defaults, so you write only your own code.

## 1. What Spring Boot gives you

- **Starters** — one dependency brings a whole feature with compatible versions (lesson 1).
- **Auto-configuration** — Boot looks at your classpath and properties and creates the beans you'd otherwise write by hand. H2 on the classpath? A `DataSource` is configured. `spring-boot-starter-webmvc`? Tomcat and JSON are set up.
- **Embedded server** — your app *contains* Tomcat; you run it with `java -jar`, no separate server install.
- **Production features** — health checks, metrics and externalised configuration.

You can always override a default by defining your own bean or setting a property.

![Layers of a Spring Boot REST API: client, @RestController, @Service, repository, database, with JSON DTOs at the top and SQL entities at the bottom](https://skills101.in/learn-img/spring-boot/layers.svg)

We'll build the Course API in these **layers**: controllers handle HTTP, services hold business rules, repositories talk to the database.

## 2. application.properties

All settings live in `src/main/resources/application.properties`. Here is our Course API's file:

```properties
# File: course-api/src/main/resources/application.properties
spring.application.name=course-api
server.port=8081
eureka.client.service-url.defaultZone=http://localhost:8761/eureka

# H2 in-memory database (swap for MySQL/PostgreSQL in production)
spring.datasource.url=jdbc:h2:mem:courses
spring.jpa.hibernate.ddl-auto=create-drop
spring.jpa.open-in-view=false

# JWT signing secret (base64, at least 32 bytes). In production read it from an environment variable.
app.jwt.secret=c2tpbGxzMTAxLWRlbW8tc2VjcmV0LWtleS0zMi1ieXRlcy1sb25nIQ==
app.jwt.ttl-minutes=60

management.endpoints.web.exposure.include=health,info
```

| Property | Meaning |
|---|---|
| `server.port` | HTTP port (default 8080) |
| `spring.datasource.url` | which database to connect to |
| `spring.jpa.hibernate.ddl-auto` | create tables from entities (`create-drop` for learning; `validate` or `none` with real migrations in production) |
| `spring.jpa.open-in-view=false` | close the database session when the service layer finishes (avoids hidden slow queries) |
| `app.jwt.*` | our own settings, read with `@Value("${app.jwt.ttl-minutes}")` |
| `management.endpoints…` | which Actuator endpoints are exposed |

You can also use `application.yml` (same keys, YAML format) — pick one.

**Never commit real secrets.** Any property can be overridden by an environment variable: `APP_JWT_SECRET=…` overrides `app.jwt.secret` (dots become underscores, upper-case).

## 3. Profiles

Different settings per environment: create `application-dev.properties` and `application-prod.properties`, then start with `--spring.profiles.active=prod` (or `SPRING_PROFILES_ACTIVE=prod`). Profile files override the main file. A bean can be limited to a profile with `@Profile("dev")`.

## 4. Running code at startup

`CommandLineRunner` beans run once the app has started — handy for sample data:

```java
// File: course-api/src/main/java/com/skills101/courses/DataSeeder.java
package com.skills101.courses;

import com.skills101.courses.course.Course;
import com.skills101.courses.course.CourseRepository;
import com.skills101.courses.student.Student;
import com.skills101.courses.student.StudentRepository;
import org.springframework.boot.CommandLineRunner;
import org.springframework.stereotype.Component;

// Puts sample data in the in-memory database when the app starts
@Component
public class DataSeeder implements CommandLineRunner {

    private final CourseRepository courses;
    private final StudentRepository students;

    public DataSeeder(CourseRepository courses, StudentRepository students) {
        this.courses = courses;
        this.students = students;
    }

    @Override
    public void run(String... args) {
        if (courses.count() > 0) {
            return;
        }
        courses.save(new Course("Java Full Stack", 4999, 30));
        courses.save(new Course("DSA in Python", 2999, 1));
        students.save(new Student("Asha Verma", "asha@skills101.in"));
        students.save(new Student("Ravi Kumar", "ravi@skills101.in"));
    }
}
```

(For real databases use a migration tool such as **Flyway** or **Liquibase** instead — versioned SQL scripts that run once.)

## 5. Actuator: is the app healthy?

With `spring-boot-starter-actuator`, `GET /actuator/health` returns the app's status — load balancers and Kubernetes call it to decide whether to send traffic. When we ran the built jar:

```text
$ curl http://localhost:8081/actuator/health
{"groups":["liveness","readiness"],"status":"UP"}
```

Expose only what you need (`health`, `info`); endpoints like `env` or `heapdump` can leak secrets.

## Common mistakes

- Two apps on the same port → "Port 8081 was already in use". Change `server.port` or stop the other app.
- `ddl-auto=create-drop` on a real database — it deletes your tables on shutdown.
- Hard-coding passwords and API keys in `application.properties` that gets committed to Git.

## Quick recap

- Spring Boot = Spring + starters + auto-configuration + embedded server.
- Configure with `application.properties` (or `.yml`); override with environment variables and profiles.
- `CommandLineRunner` runs code at startup; use Flyway/Liquibase for real schema changes.
- Actuator's `/actuator/health` reports whether the app is up.


Practice quiz and free certificate: https://skills101.in/learn/spring-boot/spring-boot-basics