When you deploy to Fly.io, you’re essentially telling it to run a container image. But where does that image live, and how does it get to Fly.io’s machines? That’s where "push and store" comes in.
Let’s see it in action. Imagine you’ve built a simple Go app and want to deploy it.
# First, build your Docker image locally
docker build -t your-fly-app .
# Now, tag it specifically for Fly.io's registry
docker tag your-fly-app registry.fly.io/your-fly-app:latest
# Push it to Fly.io's registry
docker push registry.fly.io/your-fly-app:latest
# Finally, tell your Fly.io app to use this image
fly deploy --image registry.fly.io/your-fly-app:latest
This sequence isn’t just about getting your code onto a server; it’s about managing the immutable artifact that is your application. Fly.io, like many modern platforms, uses container registries to store these images. Think of it as a central library for all your application versions. When you fly deploy, you’re telling Fly.io to pull a specific image from this library and run it.
The problem this solves is efficiency and reproducibility. Instead of shipping your entire application code every time, you ship a pre-built, self-contained image. This makes deployments faster and ensures that what you tested locally is exactly what runs in production.
Internally, docker build creates your image layers. docker tag is just an alias, like giving a book a second title so it’s easier to find. docker push uploads these layers to the specified registry – in this case, registry.fly.io. Fly.io’s infrastructure then has direct access to this image, ready to be deployed to any of its edge machines.
The flyctl command, specifically fly deploy, orchestrates this. When you run fly deploy, it checks your fly.toml file. If it finds an image key, it uses that. If not, or if you override it with --image, it instructs the Fly.io platform to pull that specific image from registry.fly.io. The platform then handles the pulling and running on the appropriate machines.
The most surprising thing is how much of the "deployment" is actually just a pointer. When you fly deploy --image registry.fly.io/your-fly-app:latest, Fly.io doesn’t re-download the entire image from scratch every single time if it already has it cached on the machine you’re targeting. It checks its local cache first. If the image layers are present, it can start the container almost instantaneously. This layer-caching mechanism is fundamental to the speed of containerized deployments.
Beyond registry.fly.io, you can use any OCI-compliant container registry like Docker Hub, GHCR, or ECR. Fly.io can be configured to pull from these as well, although using registry.fly.io is often the simplest path.
The next step in managing your deployments is understanding how to automate this push-and-deploy cycle with CI/CD pipelines.