Urgent.News

What's breaking now, across thousands of outlets.

Tech

Multi-stage Docker builds: ship the artifact, not the build shop

Most Node images I inherit are somewhere north of a gigabyte. The app inside is maybe 40 MB. The other gigabyte is the build shop: compilers, dev dependencies, the npm cache, a full copy of the source, and whatever the base image shipped with. That gigabyte costs you every day. Slower pulls on every deploy and every autoscale event. More layers for your scanner to chew through. A bigger surface…

Most Node.js images are often over a gigabyte in size, with only 40 megabytes dedicated to the application itself. The additional gigabyte contains compilers, development dependencies, an npm cache, a complete copy of the source code and more. This accumulation of unnecessary weight every day leads to slower deployment times and larger attack surfaces. Docker's multi-stage builds address these issues without altering your application code.

In a regular Dockerfile, each instruction results in an additional layer that remains in the final image. Traditional Node.js builds typically follow this pattern:

1. Start with a base image like `node:20`

2. Set the working directory to `/app`

3. Copy the `package*.json` file to the working directory

4. Run `npm ci` to install dependencies

5. Copy the entire source code to the working directory

6. Execute `npm run build` to compile the application

7. Run `node dist/server.js` to start the application

The resulting image includes not only the Node.js environment and your application but also all dependencies, the npm cache, the entire source code, and build artifacts. Multi-stage builds offer a solution by allowing you to create multiple stages within a single Dockerfile. Each stage represents a separate filesystem, enabling you to perform different tasks in each stage.

Let's walk through an example of a multi-stage Dockerfile for a Node.js application:

1. Name the first stage as `build` using the `AS` keyword. Install all dependencies, compile the application, and generate build artifacts in this stage. None of the layers created in this stage will be included in the final image.

2. In the second stage, use a smaller base image, such as `node:20-slim`, which has a smaller footprint than the original `node:20` image. Install only the production dependencies and copy the compiled application artifacts from the `build` stage into the final image.

3. Name your stages using the `AS` keyword to reference them later in the Dockerfile. For example, `FROM node:20-slim AS production` designates the production stage.

4. Do not copy `node_modules` across stages. It is common to copy `node_modules` from the build stage to the final stage, but this can introduce unnecessary baggage from development dependencies and potentially incompatible native modules. Instead, run `npm ci --omit=dev` in the final stage to ensure a clean production environment with only the necessary production dependencies.

5. Consider using a smaller base image like `node:20-slim` or `distroless/nodejs20`, which contain minimal components and no unnecessary tools. This reduces the overall image size and minimizes potential attack surfaces.

6. Run your application as a non-root user to enhance security.

7. Name your stages appropriately and keep your install layer above the source copy. This ensures that changes to your application code only invalidate the copy layer, while the dependency installation remains cached, making subsequent builds faster.

Multi-stage builds offer benefits beyond just size reduction. They allow you to create multiple Docker images from the same source code, each tailored for specific environments, such as testing or production. You can add additional stages for running tests, linting code, or pulling external tools without installing them in your final production image.

Written by urgent.news from Dev.to's reporting — not their text. Machine-written — may contain errors; check the original before relying on it.

Read the original at dev.to →

More in Tech

RIP, iPhone Ultra

For many months, tech blogs like ours used the name iPhone Ultra to refer to Apple's rumored foldable iPhone, but the device ended up being named iPhone Duo .

More from Thursday 10 September →