<!-- mobian-agent-page publisher="dailydev" canonical="https://daily.dev/posts/why-to-use-a-multi-stage-dockerfile-ripe33vzt" -->

---
title: Why To Use A Multi-Stage Dockerfile | daily.dev
description: Multi-stage Dockerfiles separate build-time tooling from the final production image, so compilers like gcc and make, plus dev dependencies like RSpec, never...
canonical: https://daily.dev/posts/why-to-use-a-multi-stage-dockerfile-ripe33vzt
twitter:card: summary_large_image
twitter:site: @dailydotdev
og:type: website
og:site_name: daily.dev
og:title: Why To Use A Multi-Stage Dockerfile | daily.dev
og:description: Multi-stage Dockerfiles separate build-time tooling from the final production image, so compilers like gcc and make, plus dev dependencies like RSpec, never...
og:url: https://daily.dev/posts/why-to-use-a-multi-stage-dockerfile-ripe33vzt
og:image: https://api.daily.dev/og/posts/RIPe33vzt.png
og:image:alt: Why To Use A Multi-Stage Dockerfile
og:image:width: 1200
og:image:height: 630
og:locale: en
---

> ## Documentation Index
> Fetch the complete documentation index at: https://daily.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# Why To Use A Multi-Stage Dockerfile

**[RUBYLAND](https://daily.dev/sources/rubyla)** · 8 min read · 0 upvotes · 0 comments

## Summary

Multi-stage Dockerfiles separate build-time tooling from the final production image, so compilers like gcc and make, plus dev dependencies like RSpec, never ship to production. The piece walks through a real multi-stage Dockerfile from the latest Rails release, explains the performance benefits (smaller images, better layer caching) and security benefits (smaller attack surface, fewer CVEs), and closes with a list of practical tips and common pitfalls: naming stages, matching base image libc (glibc vs musl), remembering runtime dependencies like libpq5, avoiding secret leakage between stages via BuildKit secrets, and considering distroless images for even tighter production images.

## Full article

daily.dev links to this article rather than hosting it. Read it at the original source: <https://www.fastruby.io/blog/why-to-use-a-multi-stage-dockerfile.html>

## Questions this post answers

### Why should I use a multi-stage Dockerfile instead of a single-stage one for a Ruby app?

Multi-stage Dockerfiles produce smaller, more secure production images by separating build tools from the runtime environment. Compilers like gcc and make, along with dev dependencies such as RSpec, get discarded after the build stage instead of shipping to production, reducing both image size and the number of packages that could carry vulnerabilities.

_daily.dev surfaces practical Docker patterns for teams shrinking production image attack surface._

### Why does my compiled Ruby gem crash at runtime in a multi-stage Docker build even though it compiled fine?

A common cause is forgetting to install the runtime system libraries that a compiled gem depends on. For example, the pg gem needs libpq-dev to compile but requires libpq5 at runtime; copying only the compiled gem into the final stage without that runtime library causes the app to build successfully but crash when it runs.

_developers debugging Ruby container crashes can find these Docker gotchas gathered on daily.dev._

### Can I mix a glibc-based Ruby builder image with an Alpine-based final image in a multi-stage Docker build?

No, mismatching base image C libraries causes native gem extensions to fail at runtime. If the builder stage compiles gems on a glibc-based image like ruby:4.0 or ruby:4.0-slim but the final stage switches to a musl-based image like ruby:4.0-alpine, those extensions may break; either match the bases or compile gems inside an Alpine builder stage.

_daily.dev helps developers track base-image compatibility issues before they ship Alpine Docker builds._

## Similar posts on daily.dev

- [Building smaller Docker images faster](https://daily.dev/posts/building-smaller-docker-images-faster-pkye16mw7) · Lobsters · 3 upvotes · 0 comments
- [Containerizing Java, Python, and JavaScript Apps - Multi-Stage Docker Builds, Non-Root Users, and Docker Hub Tagging](https://daily.dev/posts/containerizing-java-python-and-javascript-apps---multi-stage-docker-builds-non-root-users-and-do-ancbrg46f) · Medium · 22 upvotes · 0 comments
- [adam bien's blog](https://daily.dev/posts/adam-bien-s-blog-0nd2pyi2a) · Adam Bien · 2 upvotes · 1 comments

---

Tags: [#docker](https://daily.dev/tags/docker), [#containers](https://daily.dev/tags/containers), [#ruby](https://daily.dev/tags/ruby), [#rails](https://daily.dev/tags/rails)

[View this post on daily.dev](https://daily.dev/posts/why-to-use-a-multi-stage-dockerfile-ripe33vzt)

```json
{"@context":"https://schema.org","@graph":[{"@type":"Organization","@id":"https://daily.dev/#organization","name":"daily.dev","url":"https://daily.dev","logo":{"@type":"ImageObject","url":"https://daily.dev/apple-touch-icon.png","width":180,"height":180},"sameAs":["https://twitter.com/dailydotdev","https://github.com/dailydotdev","https://www.linkedin.com/company/daily-dev-ltd"]},{"@type":"WebSite","@id":"https://daily.dev/#website","url":"https://daily.dev","name":"daily.dev","publisher":{"@id":"https://daily.dev/#organization"},"potentialAction":{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https://daily.dev/search?q={search_term_string}"},"query-input":"required name=search_term_string"}}]}
{"@context":"https://schema.org","@type":"TechArticle","headline":"Why To Use A Multi-Stage Dockerfile","url":"https://daily.dev/posts/why-to-use-a-multi-stage-dockerfile-ripe33vzt","mainEntityOfPage":{"@type":"WebPage","@id":"https://daily.dev/posts/why-to-use-a-multi-stage-dockerfile-ripe33vzt"},"datePublished":"2026-08-13T17:53:43.044Z","dateModified":"2026-09-14T06:29:40.677Z","description":"Multi-stage Dockerfiles separate build-time tooling from the final production image, so compilers like gcc and make, plus dev dependencies like RSpec, never...","image":"https://media.daily.dev/image/upload/f_auto,q_auto/v1/posts/e0a5ece4c12f4fa934eed4902e2e58a8?_a=AQAEuop","thumbnailUrl":"https://media.daily.dev/image/upload/f_auto,q_auto/v1/posts/e0a5ece4c12f4fa934eed4902e2e58a8?_a=AQAEuop","isAccessibleForFree":true,"articleSection":"RUBYLAND","inLanguage":"en","publisher":{"@type":"Organization","name":"daily.dev","url":"https://daily.dev","logo":{"@type":"ImageObject","url":"https://daily.dev/apple-touch-icon.png","width":180,"height":180}},"author":{"@type":"Organization","name":"RUBYLAND","logo":"https://media.daily.dev/image/upload/t_logo,f_auto/v1/logos/rubyla","url":"https://daily.dev/sources/rubyla"},"commentCount":0,"discussionUrl":"https://daily.dev/posts/why-to-use-a-multi-stage-dockerfile-ripe33vzt","interactionStatistic":[{"@type":"InteractionCounter","interactionType":{"@type":"LikeAction"},"userInteractionCount":0},{"@type":"InteractionCounter","interactionType":{"@type":"CommentAction"},"userInteractionCount":0}],"keywords":"docker,containers,ruby,rails","timeRequired":"PT8M"}
{"@context":"https://schema.org","@type":"BreadcrumbList","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https://daily.dev"},{"@type":"ListItem","position":2,"name":"RUBYLAND","item":"https://daily.dev/sources/rubyla"},{"@type":"ListItem","position":3,"name":"Why To Use A Multi-Stage Dockerfile"}]}
{"@context":"https://schema.org","@type":"FAQPage","@id":"https://daily.dev/posts/why-to-use-a-multi-stage-dockerfile-ripe33vzt#faq","mainEntity":[{"@type":"Question","name":"Why should I use a multi-stage Dockerfile instead of a single-stage one for a Ruby app?","acceptedAnswer":{"@type":"Answer","text":"Multi-stage Dockerfiles produce smaller, more secure production images by separating build tools from the runtime environment. Compilers like gcc and make, along with dev dependencies such as RSpec, get discarded after the build stage instead of shipping to production, reducing both image size and the number of packages that could carry vulnerabilities. daily.dev surfaces practical Docker patterns for teams shrinking production image attack surface."}},{"@type":"Question","name":"Why does my compiled Ruby gem crash at runtime in a multi-stage Docker build even though it compiled fine?","acceptedAnswer":{"@type":"Answer","text":"A common cause is forgetting to install the runtime system libraries that a compiled gem depends on. For example, the pg gem needs libpq-dev to compile but requires libpq5 at runtime; copying only the compiled gem into the final stage without that runtime library causes the app to build successfully but crash when it runs. developers debugging Ruby container crashes can find these Docker gotchas gathered on daily.dev."}},{"@type":"Question","name":"Can I mix a glibc-based Ruby builder image with an Alpine-based final image in a multi-stage Docker build?","acceptedAnswer":{"@type":"Answer","text":"No, mismatching base image C libraries causes native gem extensions to fail at runtime. If the builder stage compiles gems on a glibc-based image like ruby:4.0 or ruby:4.0-slim but the final stage switches to a musl-based image like ruby:4.0-alpine, those extensions may break; either match the bases or compile gems inside an Alpine builder stage. daily.dev helps developers track base-image compatibility issues before they ship Alpine Docker builds."}}]}
```

