Deploy Nuxt 3 SSR WebApp with Docker

nuxt docker

Discover the process of running Nuxt 3 within Docker and configuring Dockerfiles for production and development. Learn to build and deploy Docker images through Docker Compose, utilizing Docker's capabilities for maintaining a unified environment.


Nuxt 3 was out on Nov'22 and is using the new Nitro as its server engine which helps to deploy the nuxt apps with different hosting providers without any additional configuration or packages. When it comes to Nuxt 3, Docker empowers us to specify precise Node.js and other dependency versions required for our application, effectively eliminating the "it works on my machine" issue.

With Docker, we get the advantages to cache build steps and generate compact, streamlined images for deployment. It notably minimizes the footprint of our Nuxt 3 Dockerfile steps, enabling faster and more efficient deployment to production.

For running Nuxt3 in docker, we will leverage the default preset for nitro which is the node-server. This blog is about how to create a docker file for nuxt web app and deploy the ssr web app with docker.

MultiStage Nuxt 3 Docker Build Process

The blog is written based on the following versions,

  • Nuxt: 3.7.1
  • Docker: 20.10.8
  • Node: 18

Nuxt 3 now generates artifacts in a dedicated .output folder located in the root directory. This folder includes two subfolders, namely public and server, each serving a specific purpose. To start, let's focus on the server subdirectory within the .output folder. This is where the entry point for running a Nuxt 3 server-side rendering (SSR) resides. Specifically, you can find it at .output/server/index.mjs. This entry point is crucial for deploying your Nuxt 3 application and harnessing the power of server-side rendering.

On the other hand, the public folder within .output houses all the static files required by your Nuxt 3 project. These files are readily available and can be accessed directly when serving your application. Now, let's delve into the integration of Nuxt 3 with Docker, specifically using the multistage Docker build. This approach offers numerous benefits, including a reduced final Docker image size. By leveraging the multistage build process, only the essential .output folder is retained in the final Docker image, eliminating any unnecessary bloat. This streamlined Docker image ensures efficient deployment and optimal utilization of resources.

Dockerfile for Nuxt 3 for Deployment to Production

The base image we are going to use for the docker file is node 18 alpine linux. Let's look into each line of the below docker file for the nuxtjs project and understand the various steps,

FROM node:18-alpine3.17 as build

# update and install the latest dependencies for the alpine version
RUN apk update && apk upgrade

# set work dir as app
WORKDIR /app
# copy the nuxt project package json and package json lock if available 
COPY package* ./
# install all the project npm dependencies
RUN  npm install
# copy all other project files to working directory
COPY . ./
# build the nuxt project to generate the artifacts in .output directory
RUN npx nuxt build

# we are using multi stage build process to keep the image size as small as possible
FROM node:18-alpine3.17
# update and install latest dependencies, add dumb-init package
# add a non root user
RUN apk update && apk upgrade && apk add dumb-init && adduser -D nuxtuser 
# set non root user
USER nuxtuser

# set work dir as app
WORKDIR /app
# copy the output directory to the /app directory from 
# build stage with proper permissions for user nuxt user
COPY --chown=nuxtuser:nuxtuser --from=build /app/.output ./
# expose 8080 on container
EXPOSE 8080

# set app host and port . In nuxt 3 this is based on nitro and you can read
#more on this https://nitro.unjs.io/deploy/node#environment-variables
ENV HOST=0.0.0.0 PORT=8080 NODE_ENV=production
# start the app with dumb init to spawn the Node.js runtime process
# with signal support
CMD ["dumb-init","node","/app/server/index.mjs"]

Build the project in first stage of nuxt 3 docker build process

First, we are setting the Alpine Node 18 Docker as the base image with the stage name as build. The second line updates all available packages on this Docker image to their latest versions, while the third line sets the working directory of this image to /app. Following this, package manager and lock file JSONs are copied to the working directory. Package dependencies are installed using the npm install command. This installation of package dependencies occurs before copying the entire project file. This sequencing allows Docker to efficiently check for changes in package files and, if none are detected, reuse the existing layer if it already exists on the host.

The next step involves copying the remaining content from the project directory, followed by the execution of the npx nuxt build command to generate all the artifacts. It's worth noting that for Nuxt 3 projects, these artifacts are generated under the .output directory as opposed to the dist folder used in Nuxt 2 projects.

Nuxt 3 Docker file Second Stage: Copy the .output folder and set the docker entry point

Since this is a multi-stage Docker Nuxt build, line 18 is where our next stage of the Docker image process, specifically related to Nuxt 3 Docker, begins. It pulls a new Docker Alpine base image and updates all the packages. After setting the working directory as /app, the next step involves copying the .output folder from the build stage to the current Docker image working directory (i.e., /app). This ensures only the Nuxt 3 Dockerfile steps for the artifacts folder are copied, without including any other project files or folders in the final Docker image. This optimization reduces the total Docker image size for the final Nuxt image.

Following this step, we expose port 8080 from the container to the server and set environment variables exposed by Nitro. You can learn more about the environment variables exposed by Nitro by referring to their documentation.

The last step in this Dockerfile is to initiate the Node server with the entry point being the index file under the server folder. To enhance the management of the Node process, we utilize an init system called dumb-init. You can find further details about the usage of dumb-init here.

In case there is a need to pass any public environment variables, these can be declared in the nuxt.config file under the public runtime and Dockerfile. You also have the option to extend this Dockerfile for use in Docker Compose, allowing for the combination with the API solution.

Nuxt Docker Deployment and docker compose

Once the docker image of nuxt app is built, this image can be pushed to docker hub or artifactory or other docker image repository used by the teams. This image can then be run on the stacks like ECS, or K8

Nuxt 3 Docker Sample Repo

You can check the docker file and nuxt 3 project here in this sample repo. With Vue 3 there are multiple UI libraries that helps to develop captivating web application. In the new blog, I talk about how to use Vuetify 3 with the Vue projects