Run SvelteKit with Node in Docker
Date: 2022-11-16 | sveltekit | node | docker |
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.
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
Dockerfile to build and serve SvelteKit on Node looks like this:
FROM node:lts-slim as build
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
COPY --from=build /app/package.json ./package.json
COPY --from=build /app/build ./build
RUN npm install --production
ENTRYPOINT [ "npm", "run", "start" ]
package.json commands look like this:
"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
- 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.
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.
- Converting my most recent SvelteKit site from single to multistage shaved off ~20% of the
slimimage size (125mb -> 105mb (20mb, 16%))
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
When choosing between
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
regular: 409 mb
slim: 105 mb
alpine: 92 mb
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
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.
- 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