# How SXO Handles Static Asset Precompression (.br/.gz) Negotiation

> Discover how SXO handles static asset precompression negotiation for .br/.gz files. SXO intelligently chooses between Brotli and Gzip based on client support and availability, optimizing load times.

- Repository: [Víctor García/sxo](https://github.com/gc-victor/sxo)
- Tags: internals
- Published: 2026-03-02

---

**S​XO automatically selects between pre‑compressed Brotli (`.br`) and Gzip (`.gz`) static assets by parsing the `Accept‑Encoding` header, preferring Brotli when available, and falling back to Gzip or uncompressed files based on client support and file existence.**

The SXO framework (`gc‑victor/sxo`) serves static files from `dist/client/` through a shared static handler that implements intelligent **static asset precompression negotiation**. By examining incoming request headers and checking for pre‑generated compressed variants at runtime, the server minimizes transfer sizes without incurring the CPU cost of on‑the‑fly compression.

## The Negotiation Decision Flow

When a request hits the static handler, the server executes a deterministic four‑step algorithm to decide which file variant to serve.

### 1. Parsing the Accept-Encoding Header

The handler first reads the `Accept‑Encoding` header from the incoming request to determine client capabilities. In `src/js/server/shared/static‑handler.js` at line 102, the code uses regular expressions to detect support for Brotli and Gzip:

```javascript
const acceptEncoding = request.headers.get("Accept-Encoding") || "";
const canBrotli = /\bbr\b/.test(acceptEncoding);
const canGzip = /\bgzip\b/.test(acceptEncoding);

```

These boolean flags (`canBrotli`, `canGzip`) drive the remainder of the selection logic.

### 2. Bypassing Compression in Development Mode

If the request is served from the development server, the negotiation is skipped entirely. The `skipCompression` flag (documented at line 43 in the same file) forces the handler to serve the original uncompressed asset, ensuring faster iteration during local development without the overhead of encoding checks.

### 3. Preferring Brotli (`.br`)

When the client advertises Brotli support (`br`) and a corresponding `.br` file exists next to the original asset, the handler rewrites the file path and sets the appropriate encoding header. This logic appears at lines 113‑114:

```javascript
if (canBrotli && (await fileReader.exists(`${absPath}.br`))) {
  sendPath = `${absPath}.br`;
  contentEncoding = "br";
}

```

The `sendPath` variable is updated to point to the pre‑compressed variant, and `Content-Encoding: br` is prepared for the response headers.

### 4. Falling Back to Gzip (`.gz`)

If Brotli is unavailable or the `.br` file is missing, the handler checks for Gzip support and a `.gz` counterpart. Lines 116‑118 implement this fallback:

```javascript
else if (canGzip && (await fileReader.exists(`${absPath}.gz`))) {
  sendPath = `${absPath}.gz`;
  contentEncoding = "gzip";
}

```

If neither compressed variant exists, `sendPath` remains set to the original uncompressed file.

## Core Implementation Details

The complete selection logic resides in `src/js/server/shared/static‑handler.js`. After determining the appropriate file path, the handler stats the file (line 124) and reads its contents (line 180), attaching the `Content‑Encoding` header only when serving a compressed variant:

```javascript
let sendPath = absPath;
let contentEncoding = undefined;

// Prefer Brotli
if (canBrotli && (await fileReader.exists(`${absPath}.br`))) {
  sendPath = `${absPath}.br`;
  contentEncoding = "br";
// Fallback to Gzip
} else if (canGzip && (await fileReader.exists(`${absPath}.gz`))) {
  sendPath = `${absPath}.gz`;
  contentEncoding = "gzip";
}

// ... stat and read operations ...

if (contentEncoding) responseHeaders.set("Content-Encoding", contentEncoding);

```

When a pre‑compressed variant is selected, the handler derives `Cache‑Control` and `ETag` headers from the compressed file’s stats (size and modification time), ensuring accurate client‑side caching behavior.

## Build‑Time Precompression

The precompression negotiation relies on assets being compressed during the build phase rather than at runtime. SXO’s esbuild pipeline automatically generates `.br` and `.gz` variants for all eligible static assets in `dist/client/`. This zero‑runtime‑cost approach means the server never performs on‑the‑fly compression, reducing latency and CPU utilization for every request.

You can verify the generated files exist alongside your assets:

```bash
ls -la dist/client/app.js*

# app.js

# app.js.br

# app.js.gz

```

## Testing the Negotiation Behavior

The test suite in `src/js/server/shared/static‑handler.test.js` validates the negotiation logic with explicit assertions. When `Accept‑Encoding: br, gzip` is sent and a `.br` file exists, the test expects `Content‑Encoding: br` (lines 282‑288). Conversely, when Brotli is absent from the header but a `.gz` file is present, the server responds with `Content‑Encoding: gzip` (lines 301‑321).

To manually verify the behavior in a running application:

```bash
curl -I -H "Accept-Encoding: br, gzip" http://localhost:3000/dist/client/app.js

```

The response headers will indicate which variant was selected:

```

Content-Encoding: br
Content-Type: application/javascript

```

## Summary

- **Header Inspection**: SXO parses `Accept‑Encoding` using regex patterns (`/\bbr\b/` and `/\bgzip\b/`) to determine client capabilities.
- **Brotli Preference**: The algorithm prioritizes `.br` files when available, falling back to `.gz` only if Brotli is unsupported or missing.
- **Zero Runtime Cost**: Compression occurs during the build step; the server only negotiates and serves existing files.
- **Development Bypass**: The `skipCompression` flag disables negotiation in dev mode to speed up local iteration.
- **Cache Accuracy**: Headers like `ETag` and `Cache‑Control` are computed from the selected compressed file’s metadata.

## Frequently Asked Questions

### Does SXO compress files on‑the‑fly during requests?

No. According to the `gc‑victor/sxo` source code, all compression happens at build time through the esbuild pipeline. The static handler merely selects between pre‑existing `.br`, `.gz`, or uncompressed files based on the client’s `Accept‑Encoding` header, eliminating runtime CPU overhead.

### What happens if a browser doesn’t support Brotli or Gzip?

If the client sends an `Accept‑Encoding` header without `br` or `gzip` (or omits the header entirely), the `canBrotli` and `canGzip` flags remain false. The handler serves the original uncompressed file from `dist/client/` without setting a `Content‑Encoding` header.

### How do I verify which compression format is being served?

Use `curl` with the `-I` flag to inspect response headers. Send a request with `Accept-Encoding: br, gzip` and check for the `Content-Encoding` header in the response. Alternatively, examine the network tab in browser DevTools; the response headers will indicate `br` for Brotli or `gzip` for Gzip when pre‑compressed assets are served.

### Is precompression enabled in development mode?

No. The static handler accepts a `skipCompression` parameter (documented at line 43 of `src/js/server/shared/static‑handler.js`) that disables the entire negotiation flow. In development, SXO sets this flag to ensure uncompressed assets are served, allowing for faster builds and easier debugging without waiting for compression generation.