How to Shrink Docker Images from 1.16 GB to 22 MB: Step‑by‑Step Optimization
This article explains Docker fundamentals, outlines why containers are popular, and walks through a practical example of reducing a React app's Docker image size from 1.16 GB to 22 MB using a lightweight Alpine base, multi‑stage builds, and an Nginx final stage.
Docker Introduction
Docker is a platform that lets developers and system administrators build, run, and share applications using containers. A container runs as an isolated process with its own filesystem built from a Docker image that contains everything needed to run the application, defined by a Dockerfile.
The terms dockerization or containerization refer to the process of creating Docker containers.
Containers are popular because they offer several advantages:
Flexibility – even the most complex applications can be containerized.
Lightweight – containers share the host kernel, making them far more efficient than virtual machines.
Portability – build locally, run anywhere.
Loose coupling – a container is self‑contained; replacing or upgrading one container does not disrupt others.
Security – containers enforce strict isolation without additional configuration.
This article focuses on optimizing Docker images to make them lightweight.
Optimization Process
We start with a sample React application. After running
npx create-react-app app --template typescriptand creating a Dockerfile, the initial image size is 1.16 GB.
<code>FROM node:10<br/>WORKDIR /app<br/>COPY app /app<br/>RUN npm install -g webserver.local<br/>RUN npm install && npm run build<br/>EXPOSE 3000<br/>CMD webserver.local -d ./build</code>Step 1: Use a Lightweight Base Image
Switching the base image from the default to an Alpine‑based image reduces the size dramatically. Alpine images contain only the minimal required packages.
<code>FROM node:10-alpine<br/>WORKDIR /app<br/>COPY app /app<br/>RUN npm install -g webserver.local<br/>RUN npm install && npm run build<br/>EXPOSE 3000<br/>CMD webserver.local -d ./build</code>Resulting image size: ~330 MB.
Step 2: Multi‑Stage Build
Multi‑stage builds allow us to compile the application in one stage and copy only the compiled output to a final, minimal image, discarding source files,
node_modules, and
package.json.
<code>FROM node:10-alpine AS build<br/>WORKDIR /app<br/>COPY app /app<br/>RUN npm install && npm run build<br/>FROM node:10-alpine<br/>WORKDIR /app<br/>RUN npm install -g webserver.local<br/>COPY --from=build /app/build ./build<br/>EXPOSE 3000<br/>CMD webserver.local -d ./build</code>Resulting image size: ~91.5 MB.
Step 3: Use Nginx for Static Content
Serving static files with Nginx is more efficient than using a Node container. The final Dockerfile builds the React app in the first stage and copies the built assets into an
nginx:stable-alpineimage.
<code>FROM node:10-alpine AS build<br/>WORKDIR /app<br/>COPY app /app<br/>RUN npm install && npm run build<br/>FROM nginx:stable-alpine<br/>COPY --from=build /app/build /usr/share/nginx/html<br/>EXPOSE 80<br/>CMD ["nginx", "-g", "daemon off;"]</code>Resulting image size: ~22.4 MB, and the container serves the React application correctly.
macrozheng
Dedicated to Java tech sharing and dissecting top open-source projects. Topics include Spring Boot, Spring Cloud, Docker, Kubernetes and more. Author’s GitHub project “mall” has 50K+ stars.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.