Static File Serving Standards

SkillFiles & storage

Lets your agent serve static files and web assets with correct headers, compression, and caching.

Available today. Use it from your connected AI after setup.

Connect ahel once, and every AI you use reads what you have installed.

Then ask your AI: use the Static File Serving Standards skill

About this capability

Serve static files and web assets with optimal headers, MIME types, compression, and caching for the Static Web Server (SWS) project

What this skill tells your AI

The instructions your AI receives, as published by static-web-server/static-web-server in .agents/skills/static-file-serving/SKILL.md and read by ahel’s review.

Load this skill when configuring MIME types, selecting compression formats, setting cache headers, organizing static file directories, or optimizing file delivery with SWS.

When to load: documenting or reviewing compression setup, cache-control strategy, MIME-type overrides, SPA vs. multi-page file layout, directory listing, or pre-compression build steps.

General Principles

  • Serve the right Content-Type: SWS uses mime_guess to determine MIME types from file extensions. If the wrong type is served, rename the file or add a custom header rule
  • Compress where it helps: Text-based formats compress well (HTML, CSS, JS, JSON, SVG, XML). Pre-compress at build time for zero-CPU serving
  • Cache aggressively for versioned assets: Use fingerprinting in filenames (app.a1b2c3d.js) with Cache-Control: max-age=31536000 (1 year)
  • Don't cache HTML entry points: HTML files that reference versioned assets should have short or no cache TTL
  • Use a CDN for production: Put SWS behind a CDN (Cloudflare, Fastly, CloudFront) for edge caching and DDoS protection

MIME Types

SWS determines Content-Type from file extension. Ensure files have correct extensions:

ExtensionMIME TypeCategory
.html, .htmtext/htmlDocument
.csstext/cssStylesheet
.js, .mjstext/javascript (or application/javascript)Script
.jsonapplication/jsonData
.xmlapplication/xmlData
.svgimage/svg+xmlVector image
.pngimage/pngRaster image
.jpg, .jpegimage/jpegRaster image
.webpimage/webpRaster image
.avifimage/avifRaster image
.gifimage/gifRaster image
.icoimage/x-iconIcon
.woff2font/woff2Web font
.wofffont/woffWeb font
.pdfapplication/pdfDocument
.wasmapplication/wasmWebAssembly
.txttext/plainText
.mdtext/markdownMarkdown
.zipapplication/zipArchive
.tarapplication/x-tarArchive
.gzapplication/gzipCompressed
.brapplication/brotliCompressed
.zstapplication/zstdCompressed

Custom MIME Types

Use the TOML config file to override or add MIME types for specific paths:

[advanced.headers]
source = "**/*.yaml"
headers = { Content-Type = "application/yaml" }

Compression

Static (Pre-compressed) Compression

Pre-compress files at build time. SWS serves .br, .gz, or .zst variants automatically based on the client's Accept-Encoding header:

VariantExtensionEncoding HeaderBuild Command
Brotli.brbrbrotli -q 11 -f file
Gzip.gzgzipgzip -9 -k file
Zstandard.zstzstdzstd -19 -k file

Compression ratios (typical for text files):

FormatLevelRatioSpeed
Brotli11~75%Slowest
Zstandard19~72%Medium
Gzip9~68%Fastest

Dynamic (On-the-fly) Compression

SWS compresses responses in real-time when the client sends Accept-Encoding and no pre-compressed variant exists:

  • Only text-based MIME types are compressed (HTML, CSS, JS, JSON, XML, SVG, etc.)
  • Responses below 860 bytes skip compression (overhead exceeds savings)
  • Compression level is configurable: fastest, default, best

SWS CLI Examples

# Serve with Brotli pre-compressed variants only (no on-the-fly compression)
static-web-server --root ./dist --compression-static --compression=false

# Serve with both pre-compressed variants and on-the-fly gzip fallback
static-web-server --root ./dist --compression-static --compression

# Serve with only on-the-fly compression at fastest level
static-web-server --root ./dist --compression --compression-level fastest

Caching Strategy

Cache-Control Headers

SWS sets Cache-Control based on file extension. Enable with --cache-control-headers (default: enabled):

CategoryExtensionsmax-age
Static assets.css, .js, .png, .woff2, .avif, .webp, .pdf, .ico, .gz, .bz2, .zip, .tar1 year (31536000)
Data/feeds.json, .xml, .rss, .atom1 hour (3600)
Everything elseunknown extensions1 hour (3600)

Custom Cache Headers

Override Cache-Control for specific paths via TOML:

[advanced.headers]
source = "**/*.html"
headers = { Cache-Control = "no-cache" }

Versioned Assets Pattern

For production deployments, use content-hash filenames and cache aggressively:

dist/
  index.html              ← short cache (or no-cache)
  assets/
    app.a1b2c3d.js        ← 1-year cache (fingerprinted)
    style.e4f5g6h.css     ← 1-year cache (fingerprinted)
    logo.h7i8j9k.png      ← 1-year cache (fingerprinted)

This way, when app.a1b2c3d.js changes, the new filename app.x9y0z1.js triggers a fresh download. The HTML entry point changes to reference the new filename.

Security Headers for Static Sites

Enable --security-headers (auto-enabled with --tls) for production static sites:

static-web-server \
    --root ./dist \
    --tls --tls-cert cert.pem --tls-key key.pem \
    --security-headers \
    --cache-control-headers

Headers sent: Strict-Transport-Security, X-Frame-Options: DENY, X-Content-Type-Options: nosniff, Content-Security-Policy: frame-ancestors 'self', Referrer-Policy: strict-origin-when-cross-origin.

File Organization

Single-Page Application (SPA)

dist/
  index.html              ← entry point (served for all routes)
  assets/
    app.js
    style.css
  favicon.ico
  robots.txt

SWS configuration:

static-web-server --root ./dist --page-fallback ./index.html

The --page-fallback option serves index.html for any 404, enabling client-side routing.

Multi-Page Static Site

dist/
  index.html
  about.html
  blog/
    index.html
    post-1.html
  assets/
    main.css
    main.js
  images/
    hero.png

SWS configuration:

static-web-server --root ./dist --index-files "index.html,index.htm"

Directory Listing (Development)

For development or internal tools, enable directory listing:

static-web-server --root ./public --directory-listing

Options: --directory-listing-order (0–6), --directory-listing-format html|json, --directory-listing-download targz.

Checklist

  • Do all files have correct extensions for MIME type detection?
  • Are pre-compressed variants (.br/.gz/.zst) generated at build time?
  • Are versioned assets using fingerprint filenames for cache busting?
  • Is Cache-Control appropriate for the content type?
  • Is the HTML entry point not cached (or has short TTL)?
  • Are security headers enabled for production?
  • Is TLS enabled for production deployments?

Signals

GitHub stars
2k
Forks
130
Last commit
Sep 2026
Advanced
Catalog kind
skill
Gateway key
static-file-serving
Source
github.com/static-web-server/static-web-server