Run SvelteKit with Node in Docker
Date: 2022-11-16 | sveltekit | node | docker |
Overview
SvelteKit is my favorite frontend framework. I containerize most of my projects for ease of development and the ability to run anywhere.
In this post we'll walk through how to build and serve SvelteKit with Node in a Docker container.
Requirements
In order to follow along with this tutorial, we're going to assume you already have a few things installed / available to you:
- SvelteKit app using node-adapter - SvelteKit is built to be platform agnostic, leveraging configurable adapters for platform compatibility. The node-adapter allows SvelteKit to build and run with Node.
- More info: SvelteKit - Adapters
- Docker - In order to run Docker containers on a machine, it will need to have Docker installed.
Containerize SvelteKit with Node
A typical Dockerfile
to build and serve SvelteKit on Node looks like this:
Dockerfile
FROM node:lts-slim as build
WORKDIR /app
COPY package*.json ./
RUN rm -rf node_modules
RUN rm -rf build
COPY . .
RUN npm install
RUN npm run build
FROM node:lts-slim as run
WORKDIR /app
COPY --from=build /app/package.json ./package.json
COPY --from=build /app/build ./build
RUN npm install --production
EXPOSE 8080
ENTRYPOINT [ "npm", "run", "start" ]
The package.json
commands look like this:
package.json
"scripts": {
"build": "vite build",
"start": "export PORT=8080 && node ./build",
},
This Dockerfile is split into two sections:
- Build - Installs all necessary dependencies and builds the optimized app executable utilizing
vite
- Run - Copies the app executable into a new container and serve it via Node
Note: This is the same Dockerfile / package.json I use to build and serve all my SvelteKit sites (including this one). You can get your hands on a full-stack, fully-Dockerized SvelteKit project with CloudSeed.
FAQ
I think the Dockerfile itself is pretty straightforward but there are likely a lot of open questions about why some decisions were made. As such I'm going to use the rest of this post to cover some common questions I've received / I researched during my build.
Q: Why a multistage Dockerfile?
We can save a decent chunk of storage by going multistage. This is because most SvelteKit sites will have some dependencies that are needed for dev / building the site but not actually for running it. By going multistage we omit those dependencies in the final image.
Anecdata:
- Converting my most recent SvelteKit site from single to multistage shaved off ~20% of the
slim
image size (125mb -> 105mb (20mb, 16%))
Q: Why node:slim
vs alpine
/ regular
?
slim
and alpine
provide much smaller image sizes than regular
(~75% smaller). In most cases, there's no reason to have a full on OS running your image (this is what regular
provides) so in most cases you should go with a slim
or alpine
.
When choosing between slim
and alpine
it becomes a harder tradeoff. slim
is typically a bit heavier than alpine
(~20%) but it uses more common libraries which leaves less performance pitfalls. Whether or not the extra image savings is worth the potential performance pitfalls will depend on your workflow but I tend to go with slim
to maximize savings and minimize risk.
alpine
performance pitfalls references:
- Choosing the best Node.js Docker image
- Moving to Ubuntu for our Docker image
- Why is the Alpine Docker image over 50% slower than the Ubuntu image
Anecdata:
regular
: 409 mbslim
: 105 mbalpine
: 92 mb
Q: Why lts
vs latest
?
This is a harder one. lts
(long-term support) is pretty behind in Node versions when compared to latest
(currently at lts
= 16 vs latest
= 19). This likely means that latest
is going to have much faster, more updated software.
That said, I typically think building on lts
versions of software is better for your projects as it provides a much more stable base with more community support and less breaking changes.
If you do not specifically need some feature from a later release, I'd recommend sticking with lts
. It will get these features eventually and when it does they will be well tested.
Q: Serving with node
vs vite preview
?
So most SvelteKit example projects will ship with a serve script utilizing vite preview
. That said vite preview
is specifically not meant for serving production traffic. From the official documentation:
It is important to note that vite preview is intended for previewing the build locally and not meant as a production server.
To be fair - this is fine in most cases. There are plenty of examples of frameworks not meant for production being used in production for years at high scale companies with little fanfare.
But if we're trying to do it "right" then we'll follow best practices and just serve with node.
Anecdotally I haven't really seen much of a difference in my sites' performance but I also don't serve much traffic so ymmv.
More resources
- Get a fully-Dockerized SvelteKit project boilerplate with CloudSeed
- Svelte is better than React
- The best tech stack for building modern SaaS apps in 2022
Want more like this?
The best / easiest way to support my work is by subscribing for future updates and sharing with your network.