
Overview
Fly.io apps run on Firecracker microVMs we call Machines. Each Machine capturesstdout/stderr, ships those logs over NATS, and stores them for a period of time in a VictoriaLogs-backed search index. Most users consume logs via fly logs or by setting up log shipping to an external sink.
But sometimes you want to grab logs directly, without a CLI or setting up an exporter, because you’re building a tool, automating something, or you just want to pipe logs into your own system.
Options for fetching logs programmatically
You can get logs programmatically via:- Undocumented HTTP API: What
fly logsuses under the hood. - NATS proxy: Subscribe to real-time logs at the message level.
- Log shipper to external sink: Ingest logs elsewhere, then query them via that system.
curl something now, use the HTTP API.
1. HTTP API (same as fly logs)
The Fly CLI hits an internal API to stream logs. You can use it too:
data array of log entries and a meta.next_token cursor for paging. By default, the most recent 100 logs from the last 24 hours are returned. You can pass these query params to filter logs or set a starting timestamp:
region: three-letter region code. Returns only logs from this region.instance: a Machine ID. Returns only logs from this instance.next_token: a nanosecond Unix timestamp (e.g.1779235200000000000). Returns logs after this time, used either as a paging cursor or to backfill from a specific moment. Each response includes ameta.next_tokenthat you can pass in your next request to page forward.next_tokenreplaces the previously documentedstart_time(ISO 8601) param.
flyctl depends on it.
Use this for quick fetches or simple polling scripts. If you hit rate limits or auth issues, check that your token has read access to the app.
Importantly, this is the only option that gives you access to historical logs going back to the current retention window (about 7 days). The other options only start streaming from the moment they’re connected.
2. Subscribe to logs via NATS (experimental)
Logs are streamed through NATS under subjects like:Note: The NATS proxy is an internal transport without a versioned API or stability guarantee. It works, but may change as we evolve our logging infrastructure. If you’re building something serious, we recommend exporting logs via the log shipper instead.
- You’ll need to handle reconnections: if the network drops or the proxy restarts, your subscriber needs to reconnect and resume without losing messages.
- You’ll need to handle backpressure: if your app can’t process logs fast enough, messages might pile up and get dropped. Design your consumer to either keep up or fail gracefully.
- If you want to dedupe across subscribers, use NATS queue groups.
- NATS only streams logs from starting from the moment you connect. You won’t get any history unless you’ve been subscribed the whole time.
3. Log Shipper to External Sink
If you want durable, queryable logs, export them. We maintain a small app called the Fly Log Shipper that listens to NATS and forwards logs to sinks like Loki, Datadog, Elastic, Honeycomb, or even S3. The log shipper is a prebuilt Fly app running Vector, with configuration you can customize via TOML. It subscribes to log subjects and streams data wherever you want. Example config:SUBJECT environment variable when deploying:
Summary: So what should I use?
- Want to grep logs from a script? Try the HTTP API.
- Want real-time stream into your own system? NATS (with caveats).
- Want reliable search and dashboards? Export logs via shipper.