{"id":2287,"date":"2026-07-20T12:43:14","date_gmt":"2026-07-20T10:43:14","guid":{"rendered":"https:\/\/kindsonthegenius.com\/blog\/introduction-to-multi-stage-dockerfile-with-springboot-and-postgresql-example\/"},"modified":"2026-08-26T21:14:11","modified_gmt":"2026-08-26T19:14:11","slug":"introduction-to-multi-stage-dockerfile-with-springboot-and-postgresql-example","status":"publish","type":"post","link":"https:\/\/kindsonthegenius.com\/blog\/introduction-to-multi-stage-dockerfile-with-springboot-and-postgresql-example\/","title":{"rendered":"Introduction to Multi-stage Dockerfile with SpringBoot and PostgreSQL Example"},"content":{"rendered":"<p><!-- ktg-updated-banner --><\/p>\n<p><em>Updated August 2026 \u2014 full tutorial restored for this URL.<\/em><\/p>\n<p>A <strong>multi-stage Dockerfile<\/strong> builds your Spring Boot JAR in a JDK image, then copies only the JAR into a slim JRE image. Here we pair it with <strong>PostgreSQL<\/strong>.<\/p>\n<p>Companion: <a href=\"https:\/\/kindsonthegenius.com\/blog\/how-to-deploy-spring-boot-application-with-mysql-database-with-docker\/\">Spring Boot + MySQL with Docker<\/a>.<\/p>\n<ol>\n<li><a href=\"#t1\">Why multi-stage<\/a><\/li>\n<li><a href=\"#t2\">Multi-stage Dockerfile<\/a><\/li>\n<li><a href=\"#t3\">Spring datasource for Postgres<\/a><\/li>\n<li><a href=\"#t4\">Compose with PostgreSQL<\/a><\/li>\n<li><a href=\"#t5\">Tips<\/a><\/li>\n<\/ol>\n<p><strong id=\"t1\">1. Why multi-stage<\/strong><\/p>\n<ul>\n<li>Final image has no Maven\/Gradle caches or source<\/li>\n<li>Smaller attack surface and faster pulls<\/li>\n<li>Same Dockerfile works in CI<\/li>\n<\/ul>\n<p><strong id=\"t2\">2. Multi-stage Dockerfile<\/strong><\/p>\n<pre><code>FROM eclipse-temurin:21-jdk AS build\nWORKDIR \/workspace\nCOPY mvnw pom.xml .\/\nCOPY .mvn .mvn\nRUN .\/mvnw -q -DskipTests dependency:go-offline\nCOPY src src\nRUN .\/mvnw -q -DskipTests package\n\nFROM eclipse-temurin:21-jre AS runtime\nWORKDIR \/app\nRUN useradd -r spring\nUSER spring\nCOPY --from=build \/workspace\/target\/*.jar app.jar\nEXPOSE 8080\nENTRYPOINT [\"java\",\"-XX:+UseContainerSupport\",\"-jar\",\"\/app\/app.jar\"]\n<\/code><\/pre>\n<p><strong id=\"t3\">3. Spring datasource for Postgres<\/strong><\/p>\n<pre><code>spring.datasource.url=jdbc:postgresql:\/\/postgres:5432\/appdb\nspring.datasource.username=app\nspring.datasource.password=secret\nspring.jpa.hibernate.ddl-auto=update\nspring.jpa.properties.hibernate.dialect=org.hibernate.dialect.PostgreSQLDialect\n<\/code><\/pre>\n<p><strong id=\"t4\">4. Compose with PostgreSQL<\/strong><\/p>\n<pre><code>services:\n  postgres:\n    image: postgres:16\n    environment:\n      POSTGRES_DB: appdb\n      POSTGRES_USER: app\n      POSTGRES_PASSWORD: secret\n    ports: [\"5432:5432\"]\n    volumes: [\"pgdata:\/var\/lib\/postgresql\/data\"]\n  api:\n    build: .\n    ports: [\"8080:8080\"]\n    depends_on: [postgres]\nvolumes:\n  pgdata:\n<\/code><\/pre>\n<p><strong id=\"t5\">5. Tips<\/strong><\/p>\n<ul>\n<li>Layer dependency download before copying <code>src<\/code> for faster rebuilds.<\/li>\n<li>Pass secrets via env \/ Compose secrets, not baked into the image.<\/li>\n<li>Add a healthcheck on Postgres before starting Flyway-heavy apps.<\/li>\n<\/ul>\n","protected":false},"excerpt":{"rendered":"<p>Updated August 2026 \u2014 full tutorial restored for this URL. A multi-stage Dockerfile builds your Spring Boot JAR in a JDK image, then copies only &hellip; <\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"pagelayer_contact_templates":[],"_pagelayer_content":"","footnotes":""},"categories":[85],"tags":[],"class_list":["post-2287","post","type-post","status-publish","format-standard","hentry","category-java"],"acf":[],"_links":{"self":[{"href":"https:\/\/kindsonthegenius.com\/blog\/wp-json\/wp\/v2\/posts\/2287","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/kindsonthegenius.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/kindsonthegenius.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/kindsonthegenius.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/kindsonthegenius.com\/blog\/wp-json\/wp\/v2\/comments?post=2287"}],"version-history":[{"count":2,"href":"https:\/\/kindsonthegenius.com\/blog\/wp-json\/wp\/v2\/posts\/2287\/revisions"}],"predecessor-version":[{"id":2450,"href":"https:\/\/kindsonthegenius.com\/blog\/wp-json\/wp\/v2\/posts\/2287\/revisions\/2450"}],"wp:attachment":[{"href":"https:\/\/kindsonthegenius.com\/blog\/wp-json\/wp\/v2\/media?parent=2287"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/kindsonthegenius.com\/blog\/wp-json\/wp\/v2\/categories?post=2287"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/kindsonthegenius.com\/blog\/wp-json\/wp\/v2\/tags?post=2287"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}