DEV Community

Cover image for Dockerizing Spring Boot for Local and Production Environments — The Setup You’ll Rebuild Every Time
Yadrs
Yadrs

Posted on

Dockerizing Spring Boot for Local and Production Environments — The Setup You’ll Rebuild Every Time

Running a Spring Boot application locally is straightforward.

But production introduces different requirements.

A real deployment usually needs:

  • consistent runtime environments
  • database containers for local development
  • smaller production images
  • environment-based configuration
  • faster rebuilds
  • secure containers
  • repeatable deployments

This is where Docker becomes a common part of modern Spring Boot projects.

Docker is not just about putting a JAR file inside a container.

The goal is creating a predictable way to build, run, and deploy your application.


The Basic Docker Approach

The simplest Spring Boot Docker setup usually looks like this:

Copy project
       ↓
Build application
       ↓
Run JAR
Enter fullscreen mode Exit fullscreen mode

A basic image might:

  • install Java
  • copy the source code
  • build the application
  • start the application

This works.

But it also introduces problems:

Large images

Slow rebuilds

Build tools inside production containers

Unnecessary files copied into images
Enter fullscreen mode Exit fullscreen mode

For learning, that approach is fine.

For long-running applications, there are better patterns.


Multi-Stage Docker Builds

A common production approach is using separate stages:

Build Stage
     ↓
Runtime Stage
Enter fullscreen mode Exit fullscreen mode

Build Stage

The build stage contains everything needed to create the application.

For example:

JDK
Gradle
source code
build tools
Enter fullscreen mode Exit fullscreen mode

After compilation finishes:

build/libs/application.jar
Enter fullscreen mode Exit fullscreen mode

is created.

Then only that artifact moves forward.

Runtime Stage

The runtime container only needs:

Java Runtime
       +
Spring Boot JAR
Enter fullscreen mode Exit fullscreen mode

It does not need:

source code

Gradle cache

compiler tools

temporary build files
Enter fullscreen mode Exit fullscreen mode

This produces:

  • smaller images
  • cleaner containers
  • reduced attack surface

The container should contain what is required to run the application — nothing more.


Docker Layer Caching

One of the biggest Docker performance improvements comes from understanding layers.

A common mistake:

Copy everything
      ↓
Build everything
Enter fullscreen mode Exit fullscreen mode

Every code change invalidates the cache.

That means:

Change one controller
↓ 
Download dependencies again
Enter fullscreen mode Exit fullscreen mode

A better approach:

Copy dependency files
↓
Download dependencies
↓
Copy source code
↓
Build application
Enter fullscreen mode Exit fullscreen mode

Now dependency layers remain cached until dependencies actually change.

The result:

Dependency change:
Full rebuild

Code change:
Only application rebuild
Enter fullscreen mode Exit fullscreen mode

Small ordering decisions can save minutes over hundreds of builds.


Local Development with Docker Compose

Docker is not only for production.

Most Spring Boot applications depend on services like:

PostgreSQL
MySQL
MongoDB
Redis
Enter fullscreen mode Exit fullscreen mode

Instead of installing everything manually:

Install database locally
Create users
Configure ports
Manage versions
Enter fullscreen mode Exit fullscreen mode

Docker Compose defines the environment.

A typical local setup contains:

Application container
Database container
Network configuration
Environment variables
Enter fullscreen mode Exit fullscreen mode

The goal:

A new developer can run:

docker compose up
Enter fullscreen mode Exit fullscreen mode

and get the same environment.


Environment-Based Configuration

Local and production environments usually should not share the same configuration.

Example:

Local:
database container

Production:
managed database service
Enter fullscreen mode Exit fullscreen mode

Spring Boot commonly separates this using profiles:

application.yml
application-prod.yml
Enter fullscreen mode Exit fullscreen mode

Local values might point to:

localhost database
Enter fullscreen mode Exit fullscreen mode

Production values usually come from:

environment variables
deployment secrets
cloud configuration
Enter fullscreen mode Exit fullscreen mode

Avoid:

database passwords inside source code
Enter fullscreen mode Exit fullscreen mode

Configuration should change without rebuilding the application.


Protecting the Docker Build Context

A small but important detail is .dockerignore.

Without it, Docker may receive unnecessary files:

.git
local build output
IDE files
environment files
logs
Enter fullscreen mode Exit fullscreen mode

These increase build size and can accidentally expose information.

The Docker image should only receive what it actually needs.


Running Containers Securely

Another common production improvement:

Do not run containers as root.

Default container behavior often runs as:

root user
Enter fullscreen mode Exit fullscreen mode

A better setup creates:

application user
Enter fullscreen mode Exit fullscreen mode

with limited permissions.

Why?

If an application vulnerability happens:

root container user
        ↓
more permissions
Enter fullscreen mode Exit fullscreen mode

Limiting permissions reduces risk.


Container Health Checks

Production deployments need to know if your application
is actually ready to receive traffic — not just running.

Spring Boot Actuator exposes:

/actuator/health
Enter fullscreen mode Exit fullscreen mode

Docker health checks and orchestration platforms can use this endpoint to determine when a container is healthy and ready to receive traffic.

A container that starts but fails silently is harder to debug
than one that correctly reports unhealthy.


JVM Memory Inside Containers

Java applications also need container-aware memory settings.

A server might have:

16GB RAM
Enter fullscreen mode Exit fullscreen mode

but your container may only have:

512MB RAM
Enter fullscreen mode Exit fullscreen mode

The JVM should respect container limits.

Production deployments often configure JVM memory based on container allocation instead of the host machine.

This helps prevent unexpected memory failures.


Local vs Production Docker Setup

A common structure:

project/
├── Dockerfile
├── docker-compose.yml
├── docker-compose.prod.yml
├── .env
└── .env.prod
Enter fullscreen mode Exit fullscreen mode

Local:

Docker Compose
Application
Local database container
Enter fullscreen mode Exit fullscreen mode

Production:

Docker image
External database
Production secrets
Deployment automation
Enter fullscreen mode Exit fullscreen mode

In larger environments, Docker Compose may be replaced by platforms like ECS or Kubernetes, but the container foundation remains the same.

Same application.

Different environments.


Why This Setup Becomes Repetitive

Dockerizing one Spring Boot application is useful experience.

Dockerizing your fifth one feels different.

Most projects need the same decisions:

  • Dockerfile structure
  • build optimization
  • Docker Compose setup
  • environment handling
  • production configuration
  • security defaults
  • deployment compatibility

None of these pieces are impossible.

But rebuilding them repeatedly slows down actually building the application.


Automating This Setup with SpringGen

SpringGen generates Spring Boot projects with a Docker-ready foundation:

  • optimized multi-stage builds
  • local Docker Compose configuration
  • database container setup
  • production environment structure
  • deployment-ready configuration

The generated project is normal Spring Boot code:

No runtime dependency

No vendor lock-in

Fully editable source code
Enter fullscreen mode Exit fullscreen mode

Generate the foundation, then build your application on top.


Try SpringGen

Free CLI:

npm install -g springgen
Enter fullscreen mode Exit fullscreen mode

GitHub:

GitHub logo springgen-dev / springgen

Generate production-ready Spring Boot backends in minutes 🚀

SpringGen — Generate Spring Boot Backends in Minutes 🚀 npm License: MIT

Generate production-ready Spring Boot backends instantly — Authentication, Database, Docker, CI/CD, and AWS EC2 deployment included.

👉 Try Free via CLI • 🚀 Upgrade to Pro


What is SpringGen?

Every new backend service starts the same way — same structure, auth setup database config, security hardening, Docker, and CI/CD pipeline. Most developers rebuild this from scratch or copy-paste from a previous project every single time.

SpringGen is built around that repeated workflow. Whether you are a freelancer spinning up a new client backend, a founder building an MVP, or a developer starting another microservice — run the CLI or web UI, get a consistent production-ready backend, and start writing business logic.

No copy-pasting. No forgotten configs. No "how did I set this up last time."

SpringGen uses a deterministic template/module engine to assemble tested Spring Boot project structures, configurations, and production-ready…

App:


Final Thoughts

Docker is not only a deployment tool.

It is a way to make application environments repeatable.

A good Docker setup helps developers build, test, and deploy with confidence.

Understanding Docker matters.

Recreating the same setup forever does not.

Top comments (0)