Skip to content
Latchkey

CI/CD for Spring Boot (Maven) with GitHub Actions

A Spring Boot service with JPA needs integration tests against real Postgres before the jar is packaged and shipped.

This recipe builds a GitHub Actions pipeline for a Maven-based Spring Boot app. It runs mvn verify against a Postgres service, packages the jar, and deploys on main.

What the pipeline does

  • Set up JDK with Maven cache
  • mvn verify (compile, test, integration test)
  • Run against Postgres
  • Package the jar
  • Deploy on main

The workflow

setup-java caches the Maven repository so dependency resolution is fast.

.github/workflows/ci.yml
name: CI
on: [push, pull_request]
jobs:
  test:
    runs-on: ubuntu-latest
    services:
      postgres:
        image: postgres:16
        env:
          POSTGRES_PASSWORD: postgres
          POSTGRES_DB: app_test
        ports: ["5432:5432"]
        options: >-
          --health-cmd "pg_isready -U postgres"
          --health-interval 10s
          --health-timeout 5s
          --health-retries 5
    env:
      SPRING_DATASOURCE_URL: jdbc:postgresql://localhost:5432/app_test
      SPRING_DATASOURCE_USERNAME: postgres
      SPRING_DATASOURCE_PASSWORD: postgres
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-java@v4
        with:
          distribution: temurin
          java-version: '21'
          cache: maven
      - run: mvn -B verify
  deploy:
    needs: test
    if: github.ref == 'refs/heads/main'
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-java@v4
        with:
          distribution: temurin
          java-version: '21'
          cache: maven
      - run: mvn -B package -DskipTests
      - run: ./deploy.sh target/app.jar

Testing against a database

Spring Boot reads SPRING_DATASOURCE_* env vars, so point them at the postgres service at localhost:5432. For @SpringBootTest integration tests you can use the service container directly, or use Testcontainers - Docker is preinstalled on the runner, so Testcontainers works without extra setup. Flyway or Liquibase runs migrations at boot.

Deploying

mvn package produces an executable jar in target/. Deploy it as a container image, copy it to a VPS over SSH and run it under systemd, or push to a PaaS. Externalize secrets via environment variables, not application.properties.

Key takeaways

  • cache: maven on setup-java caches ~/.m2 for fast resolution.
  • mvn verify runs unit and integration tests; point the datasource at Postgres.
  • Testcontainers works on the runner since Docker is preinstalled.

Related guides

Run this faster and cheaper on Latchkey managed runners. Start free →