API Endpoint Map
This is the full reference for Firecracker's REST API — the entire
user-facing control surface, served over a Unix domain socket by the API
thread in the firecracker binary. Every row is method + path → purpose → example JSON body → where it's taught. Use it the way you'd use a phone book: you
know the endpoint, you want the body shape, you want where to read next.
The authoritative source is the OpenAPI spec shipped in the repo. Read it, don't trust this page blindly:
# The whole surface, from the spec on YOUR branch:
rg -n "^\s+/|operationId|swagger:" src/firecracker/swagger/firecracker.yaml | less
# A specific endpoint's exact request body:
rg -n "/machine-config" -A30 src/firecracker/swagger/firecracker.yaml
Warning: Endpoints, fields, and which are pre-boot vs runtime evolve by version. Newer endpoints (
/pmem,/serial,/hotplug/memory,/balloon/hinting/*,/vm/config) may not exist on your branch — verify. Field renames happen (enable_diff_snapshots→track_dirty_pages); deprecated aliases linger. Theswagger.yamlandCHANGELOG.mdare ground truth; this page is the map.
How to drive the API
One process is one microVM. You start firecracker listening on a socket, then
configure pre-boot resources with PUTs, then PUT /actions {InstanceStart}.
After boot, only the runtime-allowed endpoints work.
API=/tmp/firecracker.socket
sudo ./firecracker --api-sock $API & # or --config-file config.json --no-api
curl -X PUT --unix-socket $API \
--data '{"kernel_image_path":"./vmlinux-6.1.x","boot_args":"console=ttyS0 reboot=k panic=1"}' \
http://localhost/boot-source
| Column | Meaning |
|---|---|
| Method + path | What you send. {id} is a path parameter (the resource id). |
| Phase | pre-boot (only before InstanceStart), runtime (only after), or any. |
| Purpose | What it configures or does. |
| Covered in | The level / deep-dive / lab that teaches the path behind it. |
Note: A microVM can also be configured entirely from a
--config-filewith--no-api(no API thread at all). The JSON sections are kebab-case (boot-source,drives,machine-config,network-interfaces,vsock,balloon,logger,metrics,mmds-config,entropy, …) and the file boot also starts the VM. Same data, different door — see Level 3.
Instance & lifecycle
| Method + path | Phase | Purpose | Covered in |
|---|---|---|---|
GET / | any | Instance info: id, state (Not started/Running/Paused), version, app name | ../deep-dives/api-server-and-action-channel.md |
PUT /actions | any | One-shot actions: InstanceStart, FlushMetrics, SendCtrlAltDel | Lab 3.1, ../deep-dives/signals-shutdown-and-reset.md |
PATCH /vm | runtime | Pause / resume the microVM: {"state":"Paused"} / {"state":"Resumed"} | ../deep-dives/snapshotting.md, Lab 9.2 |
GET /version | any | Firecracker version | ../release-governance/release-process.md |
// PUT /actions — boot the configured microVM:
{ "action_type": "InstanceStart" }
// PUT /actions — graceful guest reboot (caught by the partial i8042):
{ "action_type": "SendCtrlAltDel" }
// PATCH /vm — pause before snapshotting:
{ "state": "Paused" }
Note:
InstanceStartis the moment the vCPU threads are created and each entersKVM_RUN. Everything before it is configuration; everything after is runtime. The pre-boot/runtime split is enforced byPrebootApiControllervsRuntimeApiController— see../deep-dives/api-server-and-action-channel.md.
Boot & machine configuration (pre-boot)
| Method + path | Phase | Purpose | Covered in |
|---|---|---|---|
PUT /boot-source | pre-boot | Kernel image path, boot args (cmdline), optional initrd | ../deep-dives/the-boot-sequence.md, Lab 6.3 |
GET/PUT/PATCH /machine-config | pre-boot (PATCH limited) | vCPU count, mem size, SMT, huge pages, CPU template, dirty-page tracking | ../deep-dives/cpu-templates-and-cpuid.md, Level 6 |
PUT /cpu-config | pre-boot | A custom CPU template (CPUID/MSR normalization) | ../deep-dives/cpu-templates-and-cpuid.md, Lab 4.3 |
// PUT /boot-source
{ "kernel_image_path": "./vmlinux-6.1.x",
"boot_args": "console=ttyS0 reboot=k panic=1 pci=off nomodule",
"initrd_path": null }
// PUT /machine-config (defaults: vcpu_count=1, mem_size_mib=128, smt=false)
{ "vcpu_count": 2, "mem_size_mib": 1024, "smt": false,
"track_dirty_pages": false, "huge_pages": "None", "cpu_template": "None" }
Warning:
track_dirty_pagesis the current field name (wasenable_diff_snapshots). It must betrueat boot for diff snapshots to work later — you cannot retrofit it. Verify the field set on your branch.
Storage & devices (pre-boot config, some runtime PATCH)
| Method + path | Phase | Purpose | Covered in |
|---|---|---|---|
PUT/PATCH /drives/{id} | PUT pre-boot, PATCH runtime | A virtio-block device; PATCH updates path / rate limiter live | ../deep-dives/virtio-block.md, Lab 7.1 |
PUT/PATCH /network-interfaces/{id} | PUT pre-boot, PATCH runtime | A virtio-net device over a host TAP; PATCH updates rate limiters | ../deep-dives/virtio-net-and-tap.md, ../masterclass/networking/lab-01-tap-and-bridges.md |
PUT /vsock | pre-boot | The single virtio-vsock device (guest CID + host Unix socket) | ../deep-dives/virtio-vsock.md, ../masterclass/virtio-devices/lab-03-vsock.md |
PUT /entropy | pre-boot | The virtio-rng device (host randomness) | ../deep-dives/virtio-rng-entropy.md |
GET/PUT/PATCH /balloon (+ GET/PATCH /balloon/statistics) | PUT pre-boot, PATCH runtime | The memory balloon (inflate/deflate); statistics polling interval | ../deep-dives/virtio-balloon.md, ../engineering/oversubscription-and-density.md |
// PUT /drives/rootfs
{ "drive_id": "rootfs", "path_on_host": "./ubuntu-24.04.ext4",
"is_root_device": true, "is_read_only": false }
// PATCH /drives/rootfs (runtime: swap the backing file or rate limiter)
{ "drive_id": "rootfs", "path_on_host": "./new-rootfs.ext4" }
// PUT /network-interfaces/net1
{ "iface_id": "net1", "guest_mac": "06:00:AC:10:00:02",
"host_dev_name": "tap0",
"rx_rate_limiter": { "bandwidth": { "size": 1048576, "refill_time": 1000 } } }
// PUT /vsock
{ "vsock_id": "vsock0", "guest_cid": 3, "uds_path": "/tmp/v.sock" }
// PUT /balloon
{ "amount_mib": 256, "deflate_on_oom": true, "stats_polling_interval_s": 1 }
Note:
/vsockis singular — exactly one vsock device per microVM. Block and net are keyed by{id}and you may have several. The rate-limiter shape (bandwidth/opstoken buckets withsize/one_time_burst/refill_time) is the same across drives and interfaces — see../deep-dives/rate-limiting-token-bucket.md.
MMDS — the metadata service
| Method + path | Phase | Purpose | Covered in |
|---|---|---|---|
PUT /mmds/config | pre-boot | MMDS version (V1/V2), the network iface(s) it answers on, IPv4 addr | ../deep-dives/mmds-metadata-service.md, ../masterclass/networking/lab-03-mmds.md |
GET/PUT/PATCH /mmds | any | Read/replace/merge the metadata document the guest will read | ../deep-dives/mmds-metadata-service.md |
// PUT /mmds/config (V2 is token/session-based, IMDSv2-like)
{ "version": "V2", "network_interfaces": ["net1"], "ipv4_address": "169.254.169.254" }
// PUT /mmds (the document the guest fetches over HTTP via the dumbo stack)
{ "latest": { "meta-data": { "instance-id": "i-abc123" } } }
Note: The guest reaches MMDS over a normal HTTP socket served by the in-VMM
dumboTCP/IP stack — there is no host-side metadata server. V2 requires the guest to obtain a session token first (like EC2 IMDSv2). V1 is deprecated.
Observability
| Method + path | Phase | Purpose | Covered in |
|---|---|---|---|
PUT /logger | pre-boot | Log destination, level, format, optional module filtering | ../deep-dives/logging-and-metrics.md |
PUT /metrics | pre-boot | The metrics sink (a FIFO/file the VMM flushes structured metrics to) | ../deep-dives/logging-and-metrics.md, ../masterclass/debugging-profiling/lab-02-tracing-and-metrics.md |
// PUT /logger
{ "log_path": "/tmp/fc.log", "level": "Info", "show_level": true, "show_log_origin": true }
// PUT /metrics (then PUT /actions {FlushMetrics} to force a flush)
{ "metrics_path": "/tmp/fc-metrics.fifo" }
Tip:
PUT /actions {"action_type":"FlushMetrics"}forces an immediate metrics flush — useful in tests and labs. Metrics are emitted as one JSON object per flush.
Snapshot / restore
| Method + path | Phase | Purpose | Covered in |
|---|---|---|---|
PUT /snapshot/create | runtime (paused) | Write the microVM state file + memory file; snapshot_type Full or Diff | ../deep-dives/snapshotting.md, ../masterclass/snapshotting/lab-01-create-and-restore.md |
PUT /snapshot/load | pre-boot (fresh process) | Restore from a state file + a mem_backend (File or Uffd); optional resume_vm | ../deep-dives/snapshotting.md, Lab 9.2 |
// Create: PATCH /vm {Paused} → PUT /snapshot/create → PATCH /vm {Resumed}
{ "snapshot_type": "Full",
"snapshot_path": "/snap/state.file",
"mem_file_path": "/snap/mem.file" }
// Load (in a fresh firecracker process): PUT /snapshot/load
{ "snapshot_path": "/snap/state.file",
"mem_backend": { "backend_type": "Uffd", "backend_path": "/tmp/uffd.sock" },
"enable_diff_snapshots": false,
"resume_vm": true }
Warning: A snapshot is two files — the state file (KVM + device state) and the memory file (guest RAM). On load,
backend_type: "Uffd"hands page faults to a userspace handler over a Unix socket for lazy loading;"File"maps the memory fileMAP_PRIVATE/COW. The standalonemem_file_pathon load is deprecated in favor ofmem_backend. Verify the exact field set on your branch — this surface has churned. See../masterclass/snapshotting/lab-02-uffd-page-fault-handler.md.
Newer / experimental endpoints — verify before relying on them
These appear on recent branches but may be absent, renamed, or feature-gated on
yours. Always confirm against swagger.yaml and CHANGELOG.md.
| Method + path | Purpose | Verify with |
|---|---|---|
PUT/PATCH /pmem/{id} | virtio-pmem persistent-memory device | rg -n "/pmem" src/firecracker/swagger/firecracker.yaml |
PUT /serial | Configure the serial console (buffering / output) explicitly | rg -n "/serial" src/firecracker/swagger/firecracker.yaml |
PUT/PATCH /hotplug/memory | Hot-add memory to a running guest (virtio-mem) | rg -n "hotplug" src/firecracker/swagger/firecracker.yaml |
PUT /balloon/hinting/* | Free-page hinting variants for the balloon | rg -n "hinting" src/firecracker/swagger/firecracker.yaml |
GET /vm/config | Read back the full effective VM configuration | rg -n "/vm/config" src/firecracker/swagger/firecracker.yaml |
# Definitive "does my branch have it?" check:
rg -n "/pmem|/serial|/hotplug|/vm/config|hinting" src/firecracker/swagger/firecracker.yaml
gh pr list --repo firecracker-microvm/firecracker --search "pmem OR hotplug" --state merged
Error shape & the request path
Every API error returns a JSON body with a fault_message; HTTP status reflects
the class (400 bad request, 405 method/phase not allowed, etc.). The path behind
every endpoint is the same: the API thread parses the HTTP into a ParsedRequest,
converts it to a VmmAction, sends it over an mpsc channel, wakes the VMM thread
with an eventfd, and reads back a VmmData or VmmActionError.
sequenceDiagram
participant C as curl (UDS)
participant A as API thread
participant V as VMM thread
C->>A: PUT /machine-config {json}
A->>A: parse → ParsedRequest → VmmAction
A->>V: mpsc send(Box<VmmAction>) + eventfd wake
V->>V: PrebootApiController dispatches
V-->>A: Box<Result<VmmData, VmmActionError>>
A-->>C: 204 No Content / 4xx {fault_message}
Trace it end to end in Lab 3.1 and
../deep-dives/api-server-and-action-channel.md.
# Find the handler for any endpoint by grepping the parser, not a line number:
rg -n "machine-config|boot-source|/snapshot/|/actions" src/firecracker/src/api_server/
# Find which VmmAction an endpoint maps to:
rg -n "enum VmmAction\b" -A80 src/vmm/src/rpc_interface.rs
Related references
- KVM ioctl Cheat-Sheet — what
InstanceStartultimately drives the vCPU threads into. - Key Types by Crate —
ApiServer,ParsedRequest,VmmAction,VmResources, and the per-resource config structs. - Glossary — every endpoint's underlying device/concept defined.
Next: KVM ioctl Cheat-Sheet — the layer beneath
InstanceStart.