You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: README.md
+29-26Lines changed: 29 additions & 26 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -1,6 +1,6 @@
1
1
# static-web
2
2
3
-
A production-grade, high-performance static web file server written in Go. Zero external runtime dependencies beyond `BurntSushi/toml` and `hashicorp/golang-lru/v2`.
3
+
A production-grade, high-performance static web file server written in Go. Built on [fasthttp](https://github.com/valyala/fasthttp) for maximum throughput — **~141k req/sec**, 55% faster than Bun's native static server.
4
4
5
5
## Table of Contents
6
6
@@ -57,7 +57,7 @@ static-web --help
57
57
|**gzip compression**| On-the-fly via pooled `gzip.Writer`; pre-compressed `.gz`/`.br` sidecar support |
58
58
|**HTTP/2**| Automatic ALPN negotiation when TLS is configured |
59
59
|**Conditional requests**| ETag, `304 Not Modified`, `If-Modified-Since`, `If-None-Match`|
60
-
|**Range requests**| Byte ranges via `http.ServeContent` for video and large files |
60
+
|**Range requests**| Byte ranges via custom `parseRange`/`serveRange` implementation for video and large files |
With `preload = true` and `gc_percent = 400`, static-web delivers ~76k req/sec — within 20% of Bun's native static serving, while offering full security headers, TLS, and compression out of the box.
148
+
With `preload = true` and the fasthttp engine, static-web delivers **~141k req/sec** — **55% faster than Bun's native static serving**, while offering full security headers, TLS, and compression out of the box.
149
149
150
150
### Micro-benchmarks
151
151
@@ -158,13 +158,16 @@ Measured on Apple M2 Pro (`go test -bench=. -benchtime=5s`):
158
158
159
159
### Key design decisions
160
160
161
+
-**fasthttp engine**: Built on [fasthttp](https://github.com/valyala/fasthttp) — zero-alloc request handling with pre-allocated per-connection buffers. No per-request allocations on the hot path.
162
+
-**`tcp4` listener**: IPv4-only listener eliminates dual-stack overhead on macOS/Linux — a 2× throughput difference vs `"tcp"`.
161
163
-**Preload at startup**: `preload = true` reads all eligible files into RAM before the first request — eliminating cold-miss latency.
162
-
-**Direct `w.Write()` fast path**: cache hits bypass `http.ServeContent` entirely; pre-formatted `Content-Type` and `Content-Length` headers are assigned directly.
164
+
-**Direct `ctx.SetBody()` fast path**: cache hits bypass range/conditional logic entirely; pre-formatted `Content-Type` and `Content-Length` headers are assigned directly.
165
+
-**Custom Range implementation**: `parseRange()`/`serveRange()` handle byte-range requests without `http.ServeContent`.
166
+
-**Post-processing compression**: compress middleware runs after the handler, compressing the response body in a single pass.
-**GC tuning**: `gc_percent = 400` reduces garbage collection frequency — the hot path is allocation-free, but `net/http` internals allocate per-request.
168
+
-**GC tuning**: `gc_percent = 400` reduces garbage collection frequency — the hot path is allocation-free.
165
169
-**Cache-before-stat**: `os.Stat` is never called on a cache hit — the hot path is pure memory.
166
170
-**Zero-alloc `AcceptsEncoding`**: walks the `Accept-Encoding` header byte-by-byte without `strings.Split`.
167
-
-**Pooled `sync.Pool`**: both `gzip.Writer` and `statusResponseWriter` are pooled.
168
171
-**Pre-computed `ETagFull`**: the `W/"..."` string is built when the file is cached.
169
172
170
173
---
@@ -208,10 +211,10 @@ Only `GET`, `HEAD`, and `OPTIONS` are accepted. All other methods (including `TR
208
211
209
212
| Mitigation | Value |
210
213
|------------|-------|
211
-
|`ReadHeaderTimeout`| 5 s (Slowloris) |
212
214
|`ReadTimeout`| 10 s |
213
215
|`WriteTimeout`| 10 s |
214
-
|`MaxHeaderBytes`| 8 KiB |
216
+
|`IdleTimeout`| 75 s (keep-alive) |
217
+
|`MaxRequestBodySize`| 0 (no body accepted — static server) |
Enable `preload` to read every eligible file into the in-memory cache at startup. Combined with GC tuning, this yields the highest possible throughput — up to **~76,000 req/sec** on Apple M-series (within 20% of Bun's native static serve, while including full security headers, TLS, and compression).
605
+
Enable `preload` to read every eligible file into the in-memory cache at startup. Combined with the fasthttp engine, this yields the highest possible throughput — up to **~141,000 req/sec** on Apple M-series (**55% faster than Bun's native static serve**, while including full security headers, TLS, and compression).
`gc_percent` sets the Go runtime `GOGC` target. A higher value means the GC runs less often, trading memory for throughput. The handler's hot path is allocation-free, but `net/http` internals allocate per-request. Recommended values:
643
+
`gc_percent` sets the Go runtime `GOGC` target. A higher value means the GC runs less often, trading memory for throughput. The handler's hot path is allocation-free, and fasthttp reuses per-connection buffers (unlike net/http which allocates per-request). Recommended values:
0 commit comments