Skip to content

Docker

In many cases, we build our application with Docker to enable easy hosting on external servers.

One of the most efficient ways to do this is using a technique called Multi-stage builds, which consists of multiple stages that prepare the application and produce a final image containing only the production code. Here’s an example:

# Phase 1: Build the application
FROM node:22-alpine AS builder
WORKDIR /app
COPY package.json package-lock.json ./
RUN npm ci
COPY . .
RUN npm run build
# Phase 2: Prepare the production image
FROM node:22-alpine AS production
WORKDIR /app
ENV NODE_ENV=production
COPY package.json package-lock.json ./
RUN npm ci --include=prod
## Output from build step on builder stage
COPY --from=builder /app/dist ./dist
## Production server
COPY server.js ./
EXPOSE 5173
CMD ["node", "server.js"]

This strategy produces a much leaner image that includes only production dependencies and the bundled files.

If you are already using this approach and add layerfig, you may encounter an error like this:

Error: File "/app/config/base.json" does not exist
at ConfigBuilder.addSource (file:///app/node_modules/@layerfig/config/dist/index.js:78:46)
at file:///app/dist/server/entry-server.js:6:48
at ModuleJob.run (node:internal/modules/esm/module_job:274:25)
at async onImport.tracePromise.__proto__ (node:internal/modules/esm/loader:644:26)
at async file:///app/server.js:51:17

This error occurs because you need to include the configuration files in the final production stage:

# Phase 1: Build the application
FROM node:22-alpine AS builder
WORKDIR /app
COPY package.json package-lock.json ./
RUN npm ci
COPY . .
RUN npm run build
# Phase 2: Prepare the production image
FROM node:22-alpine AS production
WORKDIR /app
ENV NODE_ENV=production
COPY package.json package-lock.json ./
RUN npm ci --include=prod
## Output from build step on builder stage
COPY --from=builder /app/dist ./dist
## Production server
COPY server.js .
## Include configuration files
COPY ./config ./config
EXPOSE 5173
CMD ["node", "server.js"]

Now your application will include the configuration files and load them correctly.