Skip to content

How Do I Start Spring Boot for Backend Development?

Purpose

I wanted to start building Java backends, but I wasn’t sure where to begin. Spring Boot is the industry-standard framework for Java backend development - most Java backend positions require it. In this post, I’ll show you how to get started by building a simple REST API.

Environment

  • Java 17 (LTS version)
  • IntelliJ IDEA Community (free) or VS Code
  • Maven 3.9+
  • Spring Boot 3.x

Why Spring Boot?

Spring Boot simplifies Java backend development. It handles the complexity of setting up a Spring application, letting you focus on writing business logic.

Key benefits:

  • Auto-configuration reduces boilerplate
  • Embedded server (Tomcat) - no deployment needed
  • Production-ready features built-in
  • Massive ecosystem and community support

Prerequisites

Before starting with Spring Boot, you should know:

  • Basic Java syntax (variables, methods, classes)
  • Object-oriented programming concepts
  • Basic HTTP and REST concepts

Tools to install:

  • JDK 17 or later
  • An IDE (IntelliJ IDEA Community or VS Code)
  • Maven or Gradle (included in most IDEs)

Step 1: Create Your First Project

The easiest way to create a Spring Boot project is using Spring Initializr.

Go to start.spring.io and configure:

Project Configuration
Project: Maven
Language: Java
Spring Boot: 3.2.x (latest stable)
Packaging: Jar
Java: 17
Dependencies to add:
- Spring Web (build REST APIs)
- Spring Data JPA (database access)
- H2 Database (in-memory for development)
- Validation (input validation)
- Lombok (reduce boilerplate code)

Click “Generate” to download the project, then extract and open it in your IDE.

The project structure looks like:

Project Structure
my-project/
├── src/
│ ├── main/
│ │ ├── java/com/example/myproject/
│ │ │ └── MyProjectApplication.java
│ │ └── resources/
│ │ └── application.properties
│ └── test/
└── pom.xml

Step 2: Build a REST Controller

A REST controller handles HTTP requests and returns JSON responses.

I created a simple controller:

src/main/java/com/example/demo/HelloController.java
package com.example.demo;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class HelloController {
@GetMapping("/hello")
public String hello() {
return "Hello, Spring Boot!";
}
}

Run the application:

Run Spring Boot application
./mvnw spring-boot:run

Then visit http://localhost:8080/hello in your browser. You should see:

Browser response
Hello, Spring Boot!

The @RestController annotation tells Spring this class handles web requests. The @GetMapping annotation maps HTTP GET requests to the /hello path.

Step 3: Connect to a Database

Now I’ll add database persistence using Spring Data JPA.

First, create an entity class:

src/main/java/com/example/demo/Movie.java
package com.example.demo;
import jakarta.persistence.*;
import jakarta.validation.constraints.NotBlank;
@Entity
@Table(name = "movies")
public class Movie {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@NotBlank
private String title;
private Integer releaseYear;
private String genre;
// Default constructor required by JPA
public Movie() {}
public Movie(String title, Integer releaseYear, String genre) {
this.title = title;
this.releaseYear = releaseYear;
this.genre = genre;
}
// Getters and setters
public Long getId() { return id; }
public void setId(Long id) { this.id = id; }
public String getTitle() { return title; }
public void setTitle(String title) { this.title = title; }
public Integer getReleaseYear() { return releaseYear; }
public void setReleaseYear(Integer releaseYear) { this.releaseYear = releaseYear; }
public String getGenre() { return genre; }
public void setGenre(String genre) { this.genre = genre; }
}

Next, create a repository interface:

src/main/java/com/example/demo/MovieRepository.java
package com.example.demo;
import org.springframework.data.jpa.repository.JpaRepository;
import java.util.List;
public interface MovieRepository extends JpaRepository<Movie, Long> {
// Spring Data automatically implements these query methods
List<Movie> findByGenre(String genre);
List<Movie> findByReleaseYear(Integer year);
List<Movie> findByTitleContainingIgnoreCase(String title);
}

Spring Data JPA generates the implementation automatically. I just define the interface, and Spring handles the SQL queries behind the scenes.

Configure H2 database in application.properties:

src/main/resources/application.properties
spring.datasource.url=jdbc:h2:mem:testdb
spring.datasource.driverClassName=org.h2.Driver
spring.datasource.username=sa
spring.datasource.password=
spring.h2.console.enabled=true
spring.jpa.database-platform=org.hibernate.dialect.H2Dialect
spring.jpa.hibernate.ddl-auto=create-drop

H2 is an in-memory database - great for learning. Data is lost when you restart the application.

Step 4: Implement CRUD Operations

Now I’ll create a full REST controller with CRUD operations:

src/main/java/com/example/demo/MovieController.java
package com.example.demo;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import jakarta.validation.Valid;
import java.util.List;
@RestController
@RequestMapping("/api/movies")
public class MovieController {
private final MovieRepository movieRepository;
public MovieController(MovieRepository movieRepository) {
this.movieRepository = movieRepository;
}
// GET all movies
@GetMapping
public List<Movie> getAllMovies() {
return movieRepository.findAll();
}
// GET single movie by ID
@GetMapping("/{id}")
public ResponseEntity<Movie> getMovieById(@PathVariable Long id) {
return movieRepository.findById(id)
.map(ResponseEntity::ok)
.orElse(ResponseEntity.notFound().build());
}
// POST - create new movie
@PostMapping
public ResponseEntity<Movie> createMovie(@Valid @RequestBody Movie movie) {
Movie savedMovie = movieRepository.save(movie);
return ResponseEntity.status(HttpStatus.CREATED).body(savedMovie);
}
// PUT - update existing movie
@PutMapping("/{id}")
public ResponseEntity<Movie> updateMovie(
@PathVariable Long id,
@Valid @RequestBody Movie movieDetails) {
return movieRepository.findById(id)
.map(movie -> {
movie.setTitle(movieDetails.getTitle());
movie.setReleaseYear(movieDetails.getReleaseYear());
movie.setGenre(movieDetails.getGenre());
return ResponseEntity.ok(movieRepository.save(movie));
})
.orElse(ResponseEntity.notFound().build());
}
// DELETE - remove movie
@DeleteMapping("/{id}")
public ResponseEntity<Void> deleteMovie(@PathVariable Long id) {
if (!movieRepository.existsById(id)) {
return ResponseEntity.notFound().build();
}
movieRepository.deleteById(id);
return ResponseEntity.noContent().build();
}
}

Test the API with curl:

Test POST endpoint
curl -X POST http://localhost:8080/api/movies \
-H "Content-Type: application/json" \
-d '{"title":"The Matrix","releaseYear":1999,"genre":"Sci-Fi"}'
Response
{"id":1,"title":"The Matrix","releaseYear":1999,"genre":"Sci-Fi"}
Test GET all movies
curl http://localhost:8080/api/movies

The controller uses dependency injection - Spring automatically provides the MovieRepository instance. This is a core Spring concept.

Step 5: Add Professional Touches

Use Docker for PostgreSQL

H2 is fine for learning, but real projects use PostgreSQL. Here’s how to set it up with Docker:

docker-compose.yml
version: '3.8'
services:
postgres:
image: postgres:15
environment:
POSTGRES_DB: movietracker
POSTGRES_USER: myuser
POSTGRES_PASSWORD: mypassword
ports:
- "5432:5432"
volumes:
- postgres_data:/var/lib/postgresql/data
volumes:
postgres_data:

Start the database:

Start PostgreSQL container
docker-compose up -d

Update application.properties for PostgreSQL:

src/main/resources/application.properties
spring.datasource.url=jdbc:postgresql://localhost:5432/movietracker
spring.datasource.username=myuser
spring.datasource.password=mypassword
spring.datasource.driver-class-name=org.postgresql.Driver
spring.jpa.database-platform=org.hibernate.dialect.PostgreSQLDialect
spring.jpa.hibernate.ddl-auto=validate

Add the PostgreSQL driver dependency to pom.xml:

pom.xml (add to dependencies)
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
<scope>runtime</scope>
</dependency>

Use Liquibase for Migrations

Liquibase tracks database schema changes over time. This is how professional teams manage databases.

Add to pom.xml:

pom.xml (add to dependencies)
<dependency>
<groupId>org.liquibase</groupId>
<artifactId>liquibase-core</artifactId>
</dependency>

Create a migration file:

src/main/resources/db/changelog/changes/001-create-movies.yaml
databaseChangeLog:
- changeSet:
id: 1
author: cowrie
changes:
- createTable:
tableName: movies
columns:
- column:
name: id
type: bigint
autoIncrement: true
constraints:
primaryKey: true
- column:
name: title
type: varchar(255)
constraints:
nullable: false
- column:
name: release_year
type: int
- column:
name: genre
type: varchar(50)

Configure Liquibase in application.properties:

src/main/resources/application.properties
spring.liquibase.change-log=classpath:db/changelog/db.changelog-master.yaml

Liquibase automatically runs migrations when the application starts.

Common Mistakes to Avoid

  1. Skipping the official documentation - Spring’s docs are excellent. Read them first.
  2. Not understanding dependency injection - This is the core of Spring. Learn how @Autowired and constructor injection work.
  3. Overcomplicating the first project - Start simple. A basic CRUD API is enough to learn the concepts.
  4. Ignoring project structure - Follow standard conventions. Controllers go in a controller package, repositories in repository, etc.

Next Steps

After you’re comfortable with the basics:

  • Add authentication with Spring Security
  • Write tests with JUnit and Mockito
  • Deploy to a cloud platform (Railway, Render, AWS)
  • Build a frontend to consume your API

Summary

In this post, I showed how to start with Spring Boot for backend development. The key points are:

  • Use Spring Initializr to create projects quickly
  • Build REST controllers with @RestController and @GetMapping
  • Connect to databases with Spring Data JPA - just define an interface
  • Implement full CRUD operations with minimal code
  • Add Docker and Liquibase for professional development practices

The framework handles most complexity automatically. Start with a simple project, then gradually add features as you learn.

Final Words + More Resources

My intention with this article was to help others share my knowledge and experience. If you want to contact me, you can contact by email: Email me

Here are also the most important links from this article along with some further resources that will help you in this scope:

Oh, and if you found these resources useful, don’t forget to support me by starring the repo on GitHub!

Comments