Documentation versions (currently viewingVaadin 23)

Deploying Using Docker

A Docker container is a standalone, executable package of software that includes everything needed to run an application: code, runtime, system tools, system libraries, and settings. Building a Docker image requires creating a Dockerfile, a text document containing all the commands needed to assemble and run that image.

Creating a Dockerfile for New Vaadin Applications

For a new Vaadin application, you can easily generate a Dockerfile by selecting the Docker option in Vaadin Start. This approach makes building and running your container as simple as running the following two commands:

  1. To build your container (assuming your project name is myapp), run

    docker build . -t myapp:latest

  2. To run your container on localhost

    docker run -p 8080:8080 myapp:latest

You need to install Docker Desktop or Docker Server on your machine first, before you can run the above commands.

Adding a Dockerfile to Existing Vaadin Applications

If your Vaadin project was not generated with a Dockerfile, you can copy and paste the Dockerfile from a fresh Vaadin Start project into your project.

Although we will not cover all of the commands you can use in a Dockerfile here, let us quickly inspect the Dockerfile generated by Vaadin Start to help you customize it in your application.

A typical Dockerfile from Vaadin Start should look similar to the following content.

# (1)
FROM maven:3-openjdk-17-slim as build
# (2)
RUN useradd -m myuser
# (3)
WORKDIR /usr/src/app/
# (4)
RUN chown myuser:myuser /usr/src/app/
# (5)
USER myuser
# (6)
COPY --chown=myuser pom.xml ./
# (7)
RUN mvn dependency:go-offline -Pproduction
# (8)
COPY --chown=myuser:myuser src src
COPY --chown=myuser:myuser frontend frontend
COPY --chown=myuser:myuser package.json ./
COPY --chown=myuser:myuser package-lock.json* pnpm-lock.yaml* webpack.config.js* ./
# (9)
RUN mvn clean package -DskipTests -Pproduction
# (10)
FROM openjdk:17-jdk-slim
# (11)
COPY --from=build /usr/src/app/target/*.jar /usr/app/app.jar
# (12)
RUN useradd -m myuser
# (13)
USER myuser
# (14)
# (15)
CMD java -jar /usr/app/app.jar
  1. Use the official Maven image as the base image. The variant used is the slim version as specified by the maven:<version>-slim syntax.

  2. Add a new user called myuser, which will be used to execute the container. We do this to prevent the container from running as root (the default), which could lead to security issues.

  3. Change the current working directory using the WORKDIR instruction.

  4. Give the user myuser the ownership of the directory /usr/src/app/ in the container volume.

  5. Switch to the myuser unix user.

  6. Copy the pom.xml file with the optional chown feature.

  7. Ensure that all Maven dependencies are installed locally in the container, so that the app build can occur fully offline if needed.

  8. Copy project files.

  9. Use mvn to build the production package.

  10. Set the image for running the application. In this case, the Dockerfile specifies the openjdk:17-jdk-slim image.

  11. Copy the generated JAR file.

  12. Add myuser user.

  13. Switch to myuser.

  14. Highlight that the application should be accessed at port 8080. Note that exposing ports using the EXPOSE instruction in a Dockerfile is a way of documenting which ports are used, but does not actually map or open any ports. You need to explicitly expose the port when running the container, for example by using the -p flag in the docker run command.

  15. Runs the packaged JAR file.

Once you have a Dockerfile in the project directory, you can build and run your container using the docker build and docker run commands given earlier.

You can find more information on Dockerfile and its available instructions at

Building a Docker Image With Restricted Internet Access

In the Dockerfile example provided earlier, creating a production build of the application involves an implicit step by which Vaadin automatically downloads and installs a suitable Node.js distribution. In restricted environments with no (or limited) internet access, this automatic Node installation might fail. In such environments, make sure to install Node from a secured server as a separate step inside the Dockerfile. For example (and depending on your setup), the first few lines of your Dockerfile could look something like the following:

FROM maven:3-openjdk-17-slim as build
curl https//my-internal-url/nodejs/custom_setup_16.x
RUN apt-get update -qq && apt-get install -qq --no-install-recommends nodejs