A Docker image is an immutable, read-only template that contains everything needed for an application to run in isolation.
That is, a Docker image is a static “snapshot” of how your application was. It contains everything necessary, including the code, libraries, dependencies, tools, and configurations.

The keyword of this article is IMMUTABLE (Read-Only). Once an image has been created, it cannot be changed.
If you want to modify something in an image, you don’t edit it: you create a new image with the change.
Docker images are the templates that are used to create Docker containers. One image can be used to create multiple Docker containers.
Let’s delve deeper into the concept and understand why these “templates” are the foundation of your containers 👇.
The Layer System
If an image were simply a monolithic block of data (like a 2GB ISO), Docker would be extremely slow. Every time you updated a small library, you would have to download the 2GB again.
To solve this, Docker uses a Layers architecture.
Imagine a Docker image not as a single file, but as a stack of transparencies (like Photoshop layers).
Each layer represents a change in the filesystem:
Base Layer: Puts a basic Ubuntu.
Layer 2: Installs Python on top.
Layer 3: Copies your source code app.py.
Layer 4: Defines the startup command.
When Docker “looks” at the image, it overlays all these transparencies and you see the final combined result.
Storage Reusability
This is the foundation (and the clever part) of the system. Layers are shared. For example, imagine you have two different applications on your computer:
- App A: Uses Ubuntu + Python + Django.
- App B: Uses Ubuntu + Python + Flask.
In a traditional virtual machine system, you would have two copies of Ubuntu and two copies of Python. Taking up double the space.
In Docker, both images share the “Ubuntu” and “Python” layers. They are only stored once on your hard drive. Docker is smart enough to know they are identical (using a SHA256 hash) and reuses them.
This is one of the reasons why they are read-only. If apps could modify the layers they are built upon, they could break something or be a security risk.
No App (not even yours) can modify or touch your “Ubuntu layer” or your “Python layer”. We can put layers on top, but the ones below are sealed.
Image vs Container: The Writable Layer
If we said images are read-only (Read-Only), how is it possible for a container to write logs, create temporary files, or save data?
Because when you do a docker run, Docker takes the stack of layers from the image (which are untouchable) and adds an extra empty layer right on top.
This is the Container Layer and it’s the only one that is Read-Write.
When you delete a container (docker rm), the only thing that gets deleted is that thin top writable layer. The layers of the underlying image remain intact on your disk so you can create other containers with them.
Seeing it in action
Let’s see this in the terminal. When you downloaded the nginx image in the previous chapter, you probably saw something like this:
$ docker pull nginx Using default tag: latest latest: Pulling from library/nginx a2abf6c4d29d: Pull complete a9edb18c7728: Pull complete 3e731ddb2164: Pull complete …
See those weird codes (a2abf6...)? Those are the layers. Docker is downloading the image piece by piece.
If you now try to download another version of Nginx or another application based on the same Debian version that Nginx uses, you’ll see that on some lines it says:
a2abf6c4d29d: Already exists
It doesn’t download it, it reuses the block it already had.
That’s why the first time you download an image it takes a while. The second time, if it shares a base with one you already have, it’s almost instantaneous.
