> ## Documentation Index
> Fetch the complete documentation index at: https://hayate.shiina.xyz/llms.txt
> Use this file to discover all available pages before exploring further.

# Hayate Zstd Compression: Fast, Automatic, and Smart

> Hayate compresses transfers with Zstd level 1 by default, automatically skipping pre-compressed formats like ZIP, MP4, and JPEG to avoid wasted CPU.

Hayate compresses every transfer with Zstd level 1 by default. Compression runs on the sender before encryption, so the data travelling over the wire is both smaller and fully encrypted. For most file types — source code, logs, plain text, uncompressed archives, and raw data — this reduces transfer time noticeably even on a gigabit LAN. For files that are already compressed, Hayate detects the format from the file extension and skips Zstd entirely, so you never waste CPU cycles trying to compress data that won't shrink.

## Default Behavior

Zstd level 1 compression is **on by default** for all transfers. You do not need to pass any flag to enable it. Each payload frame is individually compressed and then encrypted before being sent, so the receiver always gets authenticated, decryptable data regardless of the compression state of any given frame.

Compression and encryption are coordinated at the frame level using a single flag byte prepended to each decrypted frame:

* `FRAME_RAW` (`0x00`) — the frame payload is uncompressed.
* `FRAME_ZSTD` (`0x01`) — the frame payload was compressed with Zstd before encryption.

This means that within a single transfer, some frames can be compressed and others raw — Hayate makes the decision per-frame based on what it knows about the file type.

## Smart Skip: Pre-Compressed Formats

Trying to Zstd-compress an already-compressed file is a waste of CPU and occasionally makes the output *larger*. Hayate detects pre-compressed formats by file extension and sends them raw (with `FRAME_RAW` frames) instead. The following extensions are automatically skipped:

<CardGroup cols={3}>
  <Card title="Archive formats" icon="file-zipper">
    `.zip` `.gz` `.bz2` `.xz` `.zst` `.7z` `.rar` `.br`
  </Card>

  <Card title="Video formats" icon="film">
    `.mp4` `.mkv` `.mov` `.m4v` `.webm`
  </Card>

  <Card title="Audio formats" icon="music">
    `.flac` `.opus`
  </Card>

  <Card title="Image formats" icon="image">
    `.jpg` `.png` `.webp`
  </Card>
</CardGroup>

For any extension not on this list, Zstd level 1 compression is applied.

## Why Zstd Level 1?

Zstd level 1 is tuned for throughput, not maximum compression ratio. At level 1, Zstd typically processes data faster than a gigabit network link can move it, which means compression adds negligible latency to your transfer while still delivering meaningful size reduction for compressible data. For a typical mix of source code, logs, and configuration files you can expect 2–4× size reduction. For already-dense binary formats (compiled objects, ML model weights), the reduction is smaller, but the CPU cost is also lower.

Higher Zstd levels (2–22) trade more CPU time for better ratios. Hayate uses level 1 because the goal is wire-speed transfers — not optimal compression ratios.

## Compression and Encryption Order

Hayate always compresses data **before** encrypting it. This ordering matters: encryption produces output that is statistically indistinguishable from random noise, which means it is incompressible. If you reversed the order and encrypted first, Zstd would find nothing to compress. By compressing first, Hayate gets the full benefit of Zstd's dictionary-based algorithms on the original data before it is encrypted.

## Controlling Compression

```bash theme={null}
# Disable compression explicitly — useful for already-compressed files
hayate send ./large-video.mp4 192.168.1.50:50001 --compress=false

# Compression is on by default — this sends ./code-archive.tar compressed
hayate send ./code-archive.tar 192.168.1.50:50001
```

The `-z` / `--compress` flag accepts `true` (default) or `false`. When `--compress=false` is set, all frames are sent as `FRAME_RAW` regardless of file extension.

## Compression in the Rust Library

When embedding Hayate in your own application, control compression with the `.compress(bool)` builder method on `HayateSender`:

```rust theme={null}
use hayate::HayateSender;

#[compio::main]
async fn main() -> Result<(), hayate::EngineError> {
    // Compression on (default)
    let sender = HayateSender::new()
        .code("forest-river-mountain".to_owned())
        .compress(true);

    let checksum = sender.send("./data-export.csv", |bytes| {
        println!("sent {bytes} bytes");
        Ok(())
    }).await?;

    println!("checksum: {checksum}");
    Ok(())
}
```

```rust theme={null}
use hayate::HayateSender;

#[compio::main]
async fn main() -> Result<(), hayate::EngineError> {
    // Compression off — for pre-compressed payloads
    let sender = HayateSender::new()
        .target("192.168.1.50:50001".parse().unwrap())
        .compress(false);

    let checksum = sender.send("./backup.tar.gz", |bytes| {
        println!("sent {bytes} bytes");
        Ok(())
    }).await?;

    Ok(())
}
```

<Tip>
  Disable compression when you are sending files that are already compressed (`.zip`, `.mp4`, `.tar.gz`, model weights, encrypted containers) or when you need to minimise CPU usage on constrained hardware. For everything else — source trees, log archives, CSV dumps, database exports, `.tar` files — leave compression on and let Zstd level 1 do its job.
</Tip>

<Info>
  Hayate uses Zstd with its **default dictionary** at level 1. No custom training data or pre-built dictionary is loaded at runtime. This keeps the binary small and startup instant while still delivering the full speed advantage of Zstd's core algorithm. If your workload involves highly repetitive data and you need better compression ratios, consider pre-processing with a higher Zstd level outside of Hayate before sending the already-compressed archive.
</Info>
