Fly.io’s Machines API is the underlying, lower-level API that powers Fly.io Apps. Think of the Apps API as a higher-level abstraction that makes common deployment patterns easier to manage.
Here’s a quick demo of the Machines API in action. Let’s create a simple Nginx server, attach a volume, and then update its configuration.
# Create a volume
flyctl volumes create nginx-data --size 1 --region lhr
# Create a machine
flyctl machine run --volume nginx-data=lhr:nginx-data --image nginx:latest --name my-nginx-server --region lhr --cpu 1000 --memory 512
# Check the machine status
flyctl machine status my-nginx-server
You’ll see output indicating the machine is running, likely with an IP address. Now, let’s update the Nginx configuration. We’ll create a simple nginx.conf file locally:
worker_processes 1;
events { worker_connections 1024; }
http {
server {
listen 80;
location / {
root /usr/share/nginx/html;
index index.html index.htm;
try_files $uri $uri/ /index.html;
}
location /hello {
return 200 "Hello from updated Nginx!\n";
}
}
}
And then update the machine with this new configuration. We’ll mount it as a read-only volume.
# Create a config volume
flyctl volumes create nginx-config --size 1 --region lhr --image alpine
# Copy the config into the volume
flyctl cp nginx.conf nginx-config:/etc/nginx/nginx.conf
# Update the machine to use the new config volume
flyctl machine update my-nginx-server --volume nginx-config=lhr:nginx-config --mount-opt ro
Now, if you curl the my-nginx-server IP address on the /hello path, you’ll get the "Hello from updated Nginx!" message. This demonstrates the granular control the Machines API offers: direct volume mounting, image specification, and resource allocation per machine.
The core problem the Machines API solves is providing a direct, imperative interface to the underlying virtual machine infrastructure on Fly.io. While the Apps API abstracts away much of the complexity of managing multiple instances, load balancing, and rolling updates, the Machines API exposes the fundamental building blocks: individual compute instances, their storage, networking, and lifecycle. This allows for fine-grained control over a single machine’s state and configuration, which is crucial for specific use cases.
Internally, when you deploy an App, Fly.io is orchestrating multiple Machines behind the scenes. It manages their lifecycles, ensures they are healthy, and directs traffic to them based on your App’s configuration. The Apps API translates your declarative deployment instructions (e.g., "run this Docker image, scale to 3 instances, expose port 80") into a series of imperative commands on individual Machines.
The key levers you control with the Machines API are:
image: The Docker image to run.name: A unique identifier for the machine.region: The Fly.io region to deploy the machine to.cpu/memory: The compute resources allocated to the machine.volumes: Attaching persistent storage volumes.mounts: How volumes are mounted (read-only, read-write, path).env: Environment variables.services: Network services exposed by the machine.metadata: Key-value pairs for custom identification.
The Apps API provides a more declarative and opinionated way to manage these concepts for typical web applications. It handles tasks like automatically creating volumes for persistent data, managing multiple replicas for high availability, and orchestrating zero-downtime deployments. You specify your desired state ("I want N replicas of this app running"), and the Apps API works to achieve and maintain that state by managing underlying Machines.
One common pattern where the Machines API shines is managing stateful services that don’t neatly fit the stateless web application model. For instance, you might want a single, dedicated machine for a database replica, a cache with specific performance tuning, or a background worker that needs direct access to a particular hardware feature or a very specific, non-standard setup. With the Machines API, you can define the exact configuration of that single instance, including its storage, network access, and resource limits, without the overhead of the Apps API’s replication and load balancing abstractions. You can also use it to run single-instance applications or to manage infrastructure components that aren’t part of your main application fleet.
Understanding the Machines API is also key to debugging and understanding the behavior of your Apps. When an App isn’t behaving as expected, you can often dive into the underlying Machines to see their individual status, logs, and configurations, which can reveal the root cause more directly.
The next step after mastering the Machines API for single-instance control is exploring how to orchestrate multiple Machines for more complex distributed systems, or how to integrate Machines into CI/CD pipelines for automated deployments.