Chapter 124·Intermediate·8 min read
Registries: Sharing Images
A plain-English guide to Docker registries — the shared warehouses that store and distribute images. How push and pull work, image names and tags decoded, public vs private registries, why tagging by version (not just 'latest') matters, and how registries connect building to deploying.
July 19, 2026
You can build an image and run it on your own machine. But software has to travel — from your laptop to a teammate's, from a build server to the machines that actually serve users. The thing that moves images around is a registry: a shared warehouse that stores images and hands them out on request. You've already been pulling from one since chapter two; this chapter shows the other direction — pushing your own images up — and decodes the naming and versioning that make registries reliable. It's the hand-off between building software and running it.
A registry is a warehouse for images
A registry is a server whose job is to store Docker images and distribute them. Think of it as a warehouse: you push a finished image up to it for safekeeping, and anyone with access can pull that exact image down to run it. It's the same idea as a code host like GitHub, but for built container images instead of source code — and in fact the two work hand in hand, as we'll see.
You've met one already. When you ran docker pull postgres:16 back in chapter two, you were pulling from Docker Hub, the default public registry. That was images flowing down to you. The new move here is images flowing up — taking something you built and putting it where others (or a server, or a pipeline) can reach it.
push and pull
Two commands move images in each direction. docker push uploads an image to a registry; docker pull downloads one. Pushing your own image is a three-step rhythm — log in, tag it with its registry destination, push:
$ docker login # authenticate to the registry
$ docker tag myapp raghav/myapp:1.0 # name it for its destination
$ docker push raghav/myapp:1.0 # upload itThat middle step is the one that surprises people: before you can push, the image's name has to say where it's going. docker tag gives your local myapp image a new name, raghav/myapp:1.0, that encodes its registry destination and version. Then push sends it there. On the other end, anyone can now run it:
$ docker pull raghav/myapp:1.0 # fetch it (or docker run does this automatically)The image you built on your laptop is now something a colleague, a server, or a deployment pipeline can obtain and run — byte-for-byte identical to what you built, which is the whole promise of images finally reaching across machines.
Decoding an image name
Those names aren't arbitrary — a full image name is a structured address with up to four parts, read left to right. Once you can parse it, you always know exactly what an image is and where it comes from:
ghcr.io / acme / api : 1.4
─────── ──── ─── ───
registry owner name tag
(where) (who) (what) (which version)- registry — the host storing it (
ghcr.io,registry.example.com). Omitted, it defaults to Docker Hub. - owner — the user or organisation namespace (
acme,raghav). - name — the repository, i.e. the image itself (
api,myapp). - tag — the version label (
1.4,latest).
This is why the official images look so short: postgres:16 is really docker.io/library/postgres:16 with the defaults filled in — Docker Hub, the library namespace for official images, the postgres repo, tag 16. And a company's private image might be the fully-spelled-out registry.mycompany.com/backend/payments:2.3. Same grammar, every time.
Tags are versions — and 'latest' is a trap
The tag deserves its own hard rule, because misusing it causes real production incidents. A tag labels a particular version of an image. You can have many tags in one repository — myapp:1.0, myapp:1.1, myapp:2.0 — each a distinct, frozen image.
The seductive mistake is leaning on the latest tag. It sounds like it means "the newest version," but it doesn't really mean anything reliable — latest is just the default tag Docker uses when you don't specify one. It points at whatever was last pushed without a tag, which can be anything. Deploy myapp:latest and you genuinely cannot say which build is running; pull it on two servers a week apart and you might get two different images, silently. That's how "it works on this server but not that one" comes roaring back — the very problem containers were supposed to kill.
Public and private registries
Registries come in two flavours, and real projects use both:
Public registries share images openly with the world. Docker Hub is the big one, and it's where all those base and official images live — python, node, nginx, postgres. When you build FROM node:20, you're standing on a publicly shared image. Public is perfect for open-source and for the common building blocks everyone needs.
Private registries keep images behind authentication, so only your team or infrastructure can pull them — which is exactly what you want for your company's proprietary application images. You'd never push your payments service to a public shelf. The common options include Docker Hub's private repositories, GitHub Container Registry (ghcr.io, which sits right alongside your code), and the registries built into every cloud provider (AWS ECR, Google Artifact Registry, Azure).
The bridge to production
The registry is what turns a locally-built image into shared, deployable infrastructure. You build once, tag with a real version, push to a registry (public for building blocks, private for your own code), and from there any server or pipeline pulls that precise image and runs it — identical everywhere, traceable to an exact version. It's the connective tissue between your machine and the wider world.
Which leaves the final question the whole guide has been building toward: your image is built, versioned, and sitting in a registry — now what happens when it has to run in production, serving real users, staying up around the clock, surviving crashes and traffic spikes? The last chapter is about exactly that leap — from a container on your laptop to containers running the internet — and where Kubernetes and orchestration finally enter the picture.