# Rust output macros: print!, eprintln!, write!, and format!

> Choose the right Rust output macro for stdout, stderr, an owned String, or an existing writer, including newline, flushing, and buffering behavior.

HTML: https://rustprint.com/output/output-macros/

Rust's formatting macros use the same format-string language, but they send the result to different destinations. Use `format!` for a new `String`, `print!` or `println!` for stdout, `eprint!` or `eprintln!` for stderr, and `write!` or `writeln!` for an existing writer.

If you know the destination and whether you want a newline but do not remember the macro, use the [Rust Output Macro Chooser](/tools/output-macro-chooser/).

| Macro                   | Destination                   | Newline  | Return                        |
| ----------------------- | ----------------------------- | -------- | ----------------------------- |
| `format!`               | new `String`                  | no       | `String`                      |
| `print!` / `println!`   | stdout                        | no / yes | `()`                          |
| `eprint!` / `eprintln!` | stderr                        | no / yes | `()`                          |
| `write!` / `writeln!`   | `fmt::Write` or `io::Write`   | no / yes | `fmt::Result` or `io::Result` |
| `format_args!`          | deferred formatting arguments | no       | `fmt::Arguments`              |

## stdout and stderr

Use stdout for a program's primary output. Use stderr for errors and progress that should remain separate from piped data.

**Standard output and standard error**

```rust
println!("result={}", 42);
eprintln!("warning: retrying");
```

`print!` does not append a newline. Because stdout is frequently line-buffered, call `flush()` when text must be visible immediately.

**Flushing a prompt**

```rust
use std::io::{self, Write};

print!("Continue? [y/N] ");
io::stdout().flush().unwrap();
```

See [flush stdout in Rust](/output/flush-stdout/index.md) for the `std::io::Write` import, prompt pattern, and the common "no method named flush" error.

## Lock repeated output

The standard documentation notes that `print!` locks stdout on every call. For a hot loop, lock once and write through the handle.

**Locking stdout for repeated writes**

```rust
use std::io::{self, Write};

let stdout = io::stdout();
let mut output = stdout.lock();
for value in 0..3 {
    writeln!(output, "{value}").unwrap();
}
```

## Write without an intermediate String

`write!` targets either `std::fmt::Write` for Unicode strings or `std::io::Write` for byte-oriented output.

**Writing into a String**

```rust
use std::fmt::Write;

let mut output = String::new();
write!(&mut output, "{:#06x}", 42).unwrap();
assert_eq!(output, "0x002a");
```

## Choose the destination

- [`print!` vs `println!`](/output/print-and-println/index.md) for stdout and newline behavior
- [flush stdout](/output/flush-stdout/index.md) when output must appear before the next newline
- [`eprint!` and `eprintln!`](/output/stderr-eprint-eprintln/index.md) for stderr
- [`write!` and `writeln!`](/output/write-and-writeln/index.md) for an existing writer or buffer
- [`format!`](/output/format-macro/index.md) when you need an owned `String`
- [`format_args!`](/output/format-args/index.md) when an API accepts `fmt::Arguments`

## Sources

- [std::fmt](https://doc.rust-lang.org/std/fmt/)
- [print!](https://doc.rust-lang.org/std/macro.print.html)

## Related RustPrint guides

- [Flush stdout in Rust](/output/flush-stdout/index.md): Flush Rust stdout after print! so prompts appear immediately, and fix flush() by importing std::io::Write.
- [Rust format strings - syntax, width, precision, and traits](/format/format-strings/index.md): Read Rust format strings from {} through argument capture, width, precision, alignment, escaping, and formatting traits.
- [Rust dbg! macro: inspect values with Debug](/debug/inspect-values/index.md): Use Rust dbg! to print expressions to stderr, understand its return and move behavior, and compare compact {:?} with pretty {:#?} Debug output.
