Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Binary Footprint

Compiled Seq programs include a runtime — green threads, channels, an arena allocator, signal handling, panic backtrace machinery. This document explains what’s in the binary you ship, why each piece is there, and which size choices you can adjust.

Production binary size

The size that matters is the stripped, release-optimized binary you actually ship — for examples/basics/hello-world.seq. These figures are regenerated by just footprint and recorded in footprint-measurements.md:

PlatformRustSeqGoMeasured
Linux x86_64305 KB732 KB1.50 MB2026-05-26 · rustc 1.95.0 · seqc 7.5.6 · go 1.25.9
Darwin arm64303 KB1.38 MB1.66 MB2026-05-26 · rustc 1.95.0 · seqc 7.5.6 · go 1.26.3

Seq’s shipped binary runs from a few hundred KB up to ~1.4 MB depending on platform, and it lands below Go — another runtime-bearing language — for perspective. Bare Rust is the floor: the cost of being a compiled native binary at all.

The default seqc build output is much larger (e.g. ~6.7 MB on Linux) because it embeds DWARF debug info. That is metadata you strip before shipping, not code — see the DWARF tradeoff below.

Programs that don’t reference HTTP, regex, crypto, or compression do not pay for those subsystems’ code. The runtime archive contains all of them; the link removes what’s unreferenced. See Batteries Included.

What’s in the binary

Excluding DWARF and the symbol table, the stripped code splits into four groups. The sizes below are for Linux x86_64, where the stripped hello-world binary is ~730K; a macOS arm64 binary is larger (~1.4 MB) because its toolchain and strip retain more, but the categories are the same:

Backtrace symbolizer (~250K)

Rust’s std::panic machinery includes an in-process DWARF parser (gimli, addr2line, rustc_demangle, plus a deflate decompressor for compressed DWARF sections). When a Seq program panics, this is what reads the binary’s own debug info to print a .seq:line trace. A pure Rust --release binary often skips this — Seq keeps it so panics from generated code can point back at the source.

This category disappears entirely under panic = "abort", at the cost of useful panic backtraces.

Seq runtime essentials (~150–250K)

The always-on infrastructure that defines a Seq program:

  • may — green-thread scheduler
  • arena allocator
  • channels (via crossbeam)
  • signal handlers (SIGQUIT diagnostic dump, watchdog)
  • the at-exit SEQ_REPORT KPI emitter
  • sync primitives (parking_lot) used by the above

These are reachable from seq_main itself, so they stay in every binary. They are what makes a Seq program a Seq program rather than a thin wrapper around printf.

Float formatting (~30–50K)

std::fmt’s float-to-string machinery (core::num::flt2dec::dragon::*, the POW10_SIGNIFICANDS table). Pulled in via std::fmt’s monomorphized formatters. Present even in programs that don’t print floats, because the formatter trait machinery touches it.

Rust standard library baseline (~200–300K)

The allocator, panic infrastructure (the core parts), and common slice/string operations that any Rust binary carries. Not Seq-specific — this is the cost of being a Rust-built program at all.

DWARF and the backtrace tradeoff

seqc build passes -g to clang on every build, embedding DWARF debug sections. On Linux that DWARF lives inside the binary and dominates the default artifact — about 6 MB of the ~6.7 MB hello-world build. On macOS the debug info goes into a separate .dSYM bundle instead, so the default binary is already small (~1.7 MB) and stripping it barely changes the size.

The DWARF is what lets a panic from generated Seq code resolve back to a source line in your .seq file rather than a hex address. It’s metadata only — no runtime cost — but it is large.

If a deployment target is size-constrained and you don’t need .seq:line resolution in panic traces, strip removes the symbol table (and, on Linux, the embedded DWARF):

seqc build prog.seq -o prog
strip prog

A strip’d binary still runs and still panics; it just prints addresses where it would otherwise print source locations. There is no recommended default here — the tradeoff between debuggability and artifact size depends on what you’re shipping.

Programs that go further and don’t want backtrace machinery at all can configure the workspace’s release profile with panic = "abort". That removes the ~250K backtrace symbolizer category in addition to the DWARF data. Panics then terminate the process without a backtrace.

Inspecting your own binaries

Standard Linux binutils are enough for a quick breakdown:

size -A ./prog | sort -k2 -rn | head -20
nm --print-size --size-sort --reverse-sort ./prog | head -30

bloaty (where available) gives a much better view, especially the compileunits mode that buckets bytes by source file:

bloaty ./prog -d compileunits -n 25

On macOS the equivalents are size -m, nm, and bloaty (via Homebrew). The shape of a Seq macOS binary is similar to Linux modulo a small ring-crate residue that survives ld64’s -dead_strip — it’s a few KB of unused AES and SHA assembly kernels and is inert at runtime.