Dockerizing a React and Spring Boot application

Spring Boot (via Maven) Dockerfile

FROM maven:3.8.4-openjdk-17 AS MAVEN_BUILD
COPY pom.xml /build/
COPY mvnw /build/
COPY .mvn /build/.mvn
COPY src /build/src/
WORKDIR /build/
RUN mvn clean install -Dmaven.test.skip=true -B --no-transfer-progress -e && mvn package -Dmaven.test.skip=true -B --no-transfer-progress -e

FROM openjdk:17-oracle
COPY --from=MAVEN_BUILD /build/target/<name>-<version>.jar /app/flow-api.jar
ENTRYPOINT [ "java", \
"-Dfile.encoding=UTF-8", \
"", \
"-jar", \
"/app/<name>.jar" \

React Dockerfile (HTML bundle, via yarn)

FROM node:17.4-alpine3.14 as builder
COPY . .
RUN rm -rf node_modules && yarn
RUN yarn run build

FROM nginx:1.21.5-alpine
COPY --chown=nginx:nginx nginx-ui.conf /etc/nginx/conf.d/default.conf
COPY --chown=nginx:nginx --from=builder /app/build /var/www/html/
# nginx-ui.conf
server {
listen 80;
listen [::]:80;
root /var/www/html/;
index index.html;
# server_name localhost;
# error_page 404 /404.html;
# error_page 500 502 503 504 /50x.html;
location / {
try_files $uri $uri/ /index.html;

Docker-compose.yaml file

  • UI: the React app. Note that I’m running on port 8080 so you can access via http://localhost:8080. Not a good practice to use port 80 as it might be already taken by another running app (e.g. docker-desktop k8s ingress, other containers or even apps like skype)
  • API: The Spring Boot app. node that I didn’t specify a profile in the entrypoint. That’s wanted as I want it to run on prod mode. In order to use this image in different envs (staging, branches env, prod), it’s better to specify vars via ENV vars. Spring has many options to do that via single ENVS or a single one (I’ll show that case in a future article with a k8s config) . Note that the database DSN host has to match the database container name (that’s how docker-compose works, read more here)
  • POSTGRES/MYSQL: I’m using another port but I can also run on the default one. I just wanted to show that the 5433 is the one used by the api container. The customised command is to log all the queries, so useful when executed locally. Note that you can use this docker-compose file to just launch Postgres when developing locally with docker-compose -d postgres.
container_name: app_ui
build: app-ui
- 8080:80

container_name: app_api
build: app-api
# note that "postgres" has to match the name of the postgres container
SPRING_DATASOURCE_URL: "jdbc:postgresql://postgres:5432/<db_name>"
- 5000:5000

container_name: app_postgres
image: postgres:13-alpine
restart: always
command: [ "postgres", "-c", "log_statement=all", "-c", "log_destination=stderr" ]
POSTGRES_USER: <db_user>
POSTGRES_DB: <db_name>
- 5433:5432




Software Engineer @ London []

Love podcasts or audiobooks? Learn on the go with our new app.

Recommended from Medium

XDV Protocol = Ancon Protocol

BART — HackTheBox WriteUp

Raspberry Pi 4 or Jetson Nano — Which One Is Better?

The dilemma of third party libraries

The psychology behind ineffective debugging

Amazon Web Services through Institute Id

Modularising the Badoo iOS app

Obtaining the CE marking for an electronic device

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store
Elvis Ciotti

Elvis Ciotti

Software Engineer @ London []

More from Medium

Spring Boot Event-Driven Programming with AWS EventBridge

Thinking in TypeScript: for the Eager Java Developer

Types of Update operations in MongoDB using Spring Boot

Deploy a Java Lambda Function and API Gateway with AWS CDK