← Back to list

#5 of Learning DevOps Concepts as a Full Stack Developer: Optimizing My Dockerfile — Making It…

Hey folks, Amandeep here again! Remember in my last article where I mentioned I’d explore optimization techniques for Dockerfiles? Well…

Amandeep Singh · 2025-10-06 15:52 · 0 claps · 3.7 min read
#docker #optimization #full-stack-developer #security #multi-stage-dockerfile
Open on Medium ↗
Wiki topics: EDU · Education & Learning ☁️ · DevOps & Cloud

#5 of Learning DevOps Concepts as a Full Stack Developer: Optimizing My Dockerfile — Making It Production Ready

Photo by Growtika on Unsplash

Photo by Growtika on Unsplash

Hey folks, Amandeep here again! Remember in my last article where I mentioned I’d explore optimization techniques for Dockerfiles? Well, I’ve spent the past few days diving deep into this, and honestly, the difference between my first Dockerfile and what I’m writing now is night and day. It’s 09:20 PM IST on Monday, October 6, 2025, and I’m pumped to share what I’ve learned about making Dockerfiles faster, smaller, and more efficient. Let’s get into it!

Why Need Optimization ?

So after writing my first Dockerfile and getting it running (felt pretty accomplished, not gonna lie), I noticed something weird. My Docker image was like 1.2GB for a simple Node.js app. That’s HUGE! Plus, every time I changed a single line of code, rebuilding the image took forever. I started wondering if I was doing something wrong. At that time I started digging and found that my dockerfile was not optimized which was causing this issue.

The Problems I Faced with My Original Dockerfile

I ran into below issues with my initial approach:

Problem 1: Massive Image Size — My simple API was creating images over 1GB. When I tried pushing this to Docker Hub, it took ages.

Problem 2: Slow Rebuild Times — Every code change meant rebuilding everything from scratch. Changed one function? Wait 5 minutes for npm install to run again.

Problem 3: Security Concerns — I realized I was including my node_modules, .git folder, and even my .env files in the image. Which is very critical security concern when It comes to production level.

Problem 4: Layer Confusion — I didn’t really understand how Docker layers worked, so my Dockerfile structure was all over the place.

Optimization Techniques I Discovered to solve above problems

Alright, here’s what I learned and implemented, step by step:

1. Using Multi-Stage Builds to Reduce the image size

I have used multi stage builds to reduce the final image size, so few things here —

  1. Instead of using the base image to “NODE:18”, I have used alpine (Lightweight base image of Node). Furthermore you can also use the specific version of node.
  2. converted the build process to multi stage.

So this will be the Dockerfile code after implementation of above points -

# ===== Stage 1: Building stage =====
FROM node:18-alpine AS builder

WORKDIR /app

COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build

# ===== Stage 2: Running stage =====
FROM node:18-alpine AS runner

WORKDIR /app

COPY package*.json ./
RUN npm ci --only=production
COPY --from=builder /app/dist ./dist

EXPOSE 3000
CMD ["node", "dist/index.js"]

What changed? The final image only has the compiled code and production dependencies. All the TypeScript compiler stuff and dev dependencies stay in the builder stage and don’t make it to the final image. My image size dropped from 1.2GB to about 180MB.

2. Using caching to Reduce the build time

I learned that Docker caches each instruction in the Dockerfile as a layer. If nothing changes in that instruction, Docker reuses the cached layer. The Order of instructions matters!

My Mistake Before: I was copying everything first, then running npm install. So even a tiny code change invalidated the npm install cache.

What I Do Now: Copy package.json first, run npm install, then copy the rest of the code. This way, npm install only runs when dependencies actually change.

# Previous -> npm install runs on every code change
COPY . .
RUN npm install

# Current -> Dependencies cached unless package.json changes
COPY package*.json ./
RUN npm install
COPY . .

This simple reordering cut my rebuild time from 5 minutes to about 30 seconds for code-only changes. Massive time saver!

3. Solution to Security issues

To resolve security issues, what I have found is create a .dockerignore file in the project root and add all the things that you don’t want in the docker file. This will

  1. Helps to reduce the size by preventing the unnecessary things to be the part of image.
  2. protect your secrets (environment variables)
  3. Running as Non-Root User, I haven’t tried this yet, But I have checked some resources where this was mentioned and the main benefit of this is if someone hacks the app somehow, they don’t get root access.
node_modules
npm-debug.log
.git
.gitignore
.env
.env.local
dist
.vscode
.idea
*.md
.DS_Store
coverage

After adding this, my COPY operations became much faster and my image size dropped further. Plus, I’m not accidentally shipping sensitive files anymore.

Results That Made Me Happy

  • Image Size: 1.2GB → 165MB (86% smaller!)
  • Fresh Build: 5 min → 2 min
  • Code-only Rebuild: 5 min → 25 seconds
  • Security: Now running as non-root. There may have some more security risks that I will discover later.

Final Thoughts

In my opinion, when you’re starting with Docker, the first goal should simply be to get everything working smoothly without introducing any major security risks. Once things are stable, there’s always room for improvement — and that’s where the real learning begins.

During the optimization phase, you’ll discover new techniques, better workflows, and smarter ways of doing things. It’s a process that not only makes your builds faster and cleaner but also helps you grow as a developer. And honestly, that learning journey is totally worth it in the end.

Got optimization tips I missed? Drop them in the comments — always happy to learn more!

What’s Next?

I’m pumped to learn Docker Compose next for managing multiple containers together and many more.


메타데이터
post_id
7682f595d002
slug
5-of-learning-devops-concepts-as-a-full-stack-developer-optimizing-my-dockerfile-making-it-7682f595d002
url
https://medium.com/@amanbnl/5-of-learning-devops-concepts-as-a-full-stack-developer-optimizing-my-dockerfile-making-it-7682f595d002
canonical_url
https://medium.com/@amanbnl/5-of-learning-devops-concepts-as-a-full-stack-developer-optimizing-my-dockerfile-making-it-7682f595d002
author_url
https://medium.com/@amanbnl
status
ok
fetched_at
2026-07-17 00:59:37