How to Deploy Scala to Docker Without Writing a Dockerfile
You can containerize any Scala application without writing a Dockerfile using migetpacks. It auto-detects your Scala and sbt versions from build.sbt and project/build.properties, supports Play Framework and sbt-native-packager, and produces an optimized Eclipse Temurin JRE image. One command, zero configuration.
Why Is Writing a Dockerfile for Scala So Complicated?
A production-ready Scala Dockerfile requires:
- Multi-stage builds to separate sbt from runtime
- Matching sbt, Scala, and JDK versions
- Play Framework stage output handling
- sbt-assembly for fat JARs
- sbt-native-packager for staged builds
- Proper sbt memory settings (
SBT_OPTS) - Coursier and Ivy cache handling
The Scala toolchain with its many version combinations and build plugins makes Docker configuration complex.
How Do I Containerize a Scala App Without a Dockerfile?
Open your terminal, navigate to your Scala project, and run:
cd ~/projects/my-scala-api
docker run --rm \
-v "$PWD":/workspace/source \
-v /var/run/docker.sock:/var/run/docker.sock \
-e OUTPUT_IMAGE=my-scala-api:latest \
miget/migetpacks:latest
That's it. migetpacks will:
- Detect Scala from
build.sbtorproject/directory - Read versions from
build.sbtandproject/build.properties - Detect Play Framework or sbt-native-packager
- Run the appropriate build command
- Output a slim JRE-based production image
How Are Versions Detected?
Scala Version
| Source | Example |
|---|---|
.scala-version | 3.5.2 |
build.sbt (scalaVersion) | scalaVersion := "3.5.2" |
project/build.properties (scala.version) | scala.version=3.5.2 |
| Default | Latest stable |
sbt Version
| Source | Example |
|---|---|
project/build.properties | sbt.version=1.10.6 |
| Default | 1.10.6 |
Java Version
| Source | Example |
|---|---|
system.properties | java.runtime.version=21 |
| Default | 21 |
What Build Command Is Used?
migetpacks detects the application type and adjusts the build:
| Detection | Build Command | Output |
|---|---|---|
Play Framework (PlayScala/PlayJava in build.sbt) | sbt compile stage | target/universal/stage/ |
sbt-native-packager (in project/plugins.sbt) | sbt compile stage | target/universal/stage/ |
| Standard sbt project | sbt compile assembly | target/scala-*/app.jar |
What Does the Generated Dockerfile Look Like?
# Build stage
FROM sbtscala/scala-sbt:eclipse-temurin-21.0.6_7_1.11.7_3.5.2 AS builder
WORKDIR /build
ENV JAVA_TOOL_OPTIONS="-Dfile.encoding=UTF-8"
ENV SBT_OPTS="-Xmx2G -XX:MaxMetaspaceSize=512m"
COPY build.sbt ./
COPY project/ project/
RUN sbt update || true
COPY . .
RUN sbt compile assembly \
&& rm -rf src/ project/ build.sbt
# Runtime stage
FROM eclipse-temurin:21-jre
WORKDIR /app
COPY --from=builder --chown=1000:1000 /build /app
You never write or maintain this file - migetpacks handles it automatically.
What Run Command Is Used?
| Project Type | Default Command |
|---|---|
| Standard (assembly) | java -jar target/scala-*/app.jar |
| Play Framework | target/universal/stage/bin/{app-name} |
| sbt-native-packager | target/universal/stage/bin/{app-name} |
How Do I Build a Play Framework App?
Play Framework works out of the box:
cd ~/projects/my-play-app
docker run --rm \
-v "$PWD":/workspace/source \
-v /var/run/docker.sock:/var/run/docker.sock \
-e OUTPUT_IMAGE=my-play:latest \
-e RUN_COMMAND="target/universal/stage/bin/myapp -Dhttp.port=5000" \
miget/migetpacks:latest
How Do I Build Secure Distroless Images?
Enable Docker Hardened Images for minimal containers:
docker run --rm \
-v "$PWD":/workspace/source \
-v /var/run/docker.sock:/var/run/docker.sock \
-e OUTPUT_IMAGE=my-app:latest \
-e USE_DHI=true \
miget/migetpacks:latest
Scala uses a hybrid approach: the official sbtscala build image for building, and DHI distroless Eclipse Temurin for runtime.
Next Steps
- Full Scala documentation - version detection, Play, sbt-native-packager
- Deploy on Miget - unlimited apps, one price
- Star on GitHub - migetpacks is open source
- Related guides: Java, Kotlin, Clojure