Skip to content

Dynamic format strings in Rust: why format! requires a literal

Rust’s standard format! macro does not accept a runtime String or variable as the format template. Its first format argument must be a string literal so the compiler can parse and validate the formatting syntax before the program runs.

EXAMPLE: CI-CHECKED FAILURECOMPILE-FAIL ASSERTED · examples/compile-fail/dynamic-format-string.rs#dynamic-format-string
fn main() {
    let template = String::from("value={}");
    let value = 42;

    let _output = format!(template, value);
}

The compile-fail example above is intentionally rejected by Rust CI. RustPrint checks both that compilation fails and that the compiler reports that the format argument must be a string literal.

The format template must be a literal, but the values inserted into it can be ordinary runtime values.

EXAMPLE: CI-CHECKEDTEST ASSERTED · examples/format-output/src/format_pages.rs#format-runtime-values
let value = 42;
let label = String::from("answer");
assert_eq!(format!("{label}={value}"), "answer=42");

That distinction is the important one: the format language is known at compile time, while the values being formatted can come from runtime state.

Rust’s formatting macros are compiler-supported. The compiler parses the literal format string and checks that its fields and arguments make sense together.

A runtime string cannot receive that same compile-time validation because its contents are not known when the program is compiled. format_args! does not bypass this rule; it also operates on a literal formatting string.

If the template itself must change at runtime

Section titled “If the template itself must change at runtime”

If users, configuration, files, or another runtime source determine the formatting template, you need a runtime formatting or templating layer rather than the standard format! syntax.

RustPrint does not recommend a crate on this page yet. Crate choices change independently of the language and need their own current maintenance, compatibility, and security review. This page documents the standard-library boundary only.

If the format template is fixed and only argument selection, width, or precision varies, stay with the standard formatting system. See arguments and captured variables and Rust format strings.