Dockerize a SvelteKit SSR WebApp

svelte docker

Learn how to containerize your SvelteKit SSR WebApp with our comprehensive guide. Our step-by-step tutorial covers everything you need to know to optimize your app for containerization, including setting up a Dockerfile, configuring your app for production, and running it in a Docker container.


Svelte is a popular javascript framework with the backing of Vercel and there are a lot of interest in this framework in the last few years. Similar to Vue or React, svelte allows developers to build web applications in a declarative style and SvelteKit is a meta framework for rapidly developing robust, performant web applications using Svelte.

SvelteKit provides routing, SSR, build optimizations, preloading pages, client-side rendering and many other features similar to other meta frameworks like Nuxtjs and Nextjs. In this blog post, we are going to cover how we can use the node adapter for sveltekit and dockerize the svelte web app for server-side rendering. We will look into how to write a svelte docker file and the best practices for production deployment of sveltekit in a docker.

SvelteKit Node Adapter for Docker

Sveltekit adapters are plugins that take the built app as input and generate output for the deployment target. To dockerize a sveltekit web application for server-side rendering, we need to use node adapter. This adapter needs to be configured on svelte.config.js for us to use as a node server. The blog is written based on the following versions,

  • Svelte Kit: 1.0
  • Docker: 20.10.8
  • Node: 18

MultiStage Docker Image Build for Svelte Kit WebApp for SSR

To minimize the docker image size, we are going to use the multistage docker image for the sveltekit. This ensures only the required files are available on the docker image and keep the image size less.

Sveltekit Dockerfile: Build the SvelteKit WebApp

Below is the first stage of the svelte kit web app docker file. In this stage, it is going to generate the artifacts in the build directory. Let's review this stage of the dockerfile,

# Build the first stage with alpine node image and name as build
FROM node:18-alpine3.17 as build

# update and install the latest dependencies on docker base image
# Add non root user to the docker image and set the user
RUN apk update && apk upgrade && adduser -D svelteuser
USER svelteuser

# set work dir as app
WORKDIR /app

# copy the sveltkit project content with proper permission for the user svelteuser
COPY --chown=svelteuser:svelteuser . /app

# install all the project npm dependencies and 
# build the svelte project to generate the artifacts in build directory
RUN npm install && npm run build

In the first step, we are setting the alpine node 18 docker as the base image with the stage name as build. The second line updates all the packages available on this alpine node image to the latest version along with setting a non-root user svelteuser. All the remaining steps in this stage is executed using this user.

On the fifth line, we set the workdir for this image as app which ensures all the files are copied to this directory. Next step in this process is to copy the project contents to app directory with proper permissions for the user svelteuser.Finally, we run the npm install and npm run build command to generate all the artifacts. We must use only one RUN command by combining these two commands which help to reduce the layers for the docker container. All the artifacts are generated in a new folder build and the contents from this folder are copied in the next stage of this multi stage docker file.

Second Stage: Copy Artifacts from Build and start the node server

In this stage the build directory is copied from the first stage. The first step of this stage is to set the base image to be used which is node alpine 18. After this step, all the packages are updated along with setting the user as svelteuser. The fourth and fifth lines of the docker file set the user as svelteuser and the working directory as app.

The next step is to copy the content of build directory and package.json to the working directory with proper permissions for the user. It is important to copy the package.json otherwise the import statements on the artifacts javascript files won't work.

# 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 and set non root user
RUN apk update && apk upgrade && apk add dumb-init && adduser -D svelteuser
USER svelteuser

# set work dir as app
WORKDIR /app

# copy the build directory to the /app directory of second stage 
COPY --chown=svelteuser:svelteuser --from=build /app/build /app/package.json ./

# expose 8080 on container
EXPOSE 8080

# set app host and port and env as production
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","index.js"]

After this step, we are exposing the port as 8080 from the container to the server and then set the environment variables HOST, PORT and NODE_ENV. The last step in this docker file is to start the node server with the entry point as an index file under the server folder. We are also using an init system dumb-init to handle the node process better. You can read more about the dumb-init here.

MultiStage Docker file for SvelteKit

# Build the first stage with alpine node image and name as build
FROM node:18-alpine3.17 as build

# update and install the latest dependencies on docker base image
# Add non root user to the docker image and set the user
RUN apk update && apk upgrade && adduser -D svelteuser
USER svelteuser

# set work dir as app
WORKDIR /app

# copy the sveltkit project content with proper permission for the user svelteuser
COPY --chown=svelteuser:svelteuser . /app

# install all the project npm dependencies and 
# build the svelte project to generate the artifacts in build directory
RUN npm install && npm run 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 and set non root user
RUN apk update && apk upgrade && apk add dumb-init && adduser -D svelteuser
USER svelteuser

# set work dir as app
WORKDIR /app

# copy the build directory to the /app directory of second stage 
COPY --chown=svelteuser:svelteuser --from=build /app/build /app/package.json ./

# expose 8080 on container
EXPOSE 8080

# set app host and port and env as production
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","index.js"]

Sveltekit Docker Sample Repo

You can check the docker file and sveltekit sample project here in this sample repo