Performance
Incremental scanning, hash-based caching, and route-level optimization for fast theme generation.
Overview
Nightfall is designed to be fast even on large applications. The first scan captures everything; subsequent scans only process what changed. On a typical 20-route app, incremental rescans take under 2 seconds.
Incremental Scanning
After the first full scan, Nightfall only re-scans routes where the visual output changed. It detects changes by comparing a hash of the visible DOM state:
# First scan: full (all routes)
npx nightfall-css scan --url http://localhost:3000 --routes / /about /pricing
# [scan] Scanning 3 routes (first run)...
# [scan] / → 14 colors found (320ms)
# [scan] /about → 8 colors found (180ms)
# [scan] /pricing → 11 colors found (220ms)
# [scan] Total: 720ms
# Second scan: incremental (only changed routes)
npx nightfall-css scan --url http://localhost:3000 --routes / /about /pricing
# [scan] / → unchanged (hash match, skipped)
# [scan] /about → unchanged (hash match, skipped)
# [scan] /pricing → 2 colors changed (190ms)
# [scan] Total: 190msHash-Based Caching
Nightfall caches scan results in .nightfall/cache/. Each route gets a hash based on the visible DOM state. The hash includes:
- Computed styles — All color-related CSS properties on every visible element
- CSS variables — Values of all custom properties on :root
- DOM structure — Element nesting that affects color relationships
{
"/": {
"hash": "a3f8e2c1",
"scannedAt": "2026-04-08T12:00:00Z",
"colorCount": 14
},
"/about": {
"hash": "b7d4f190",
"scannedAt": "2026-04-08T12:00:00Z",
"colorCount": 8
},
"/pricing": {
"hash": "c2e5a3b8",
"scannedAt": "2026-04-08T12:00:05Z",
"colorCount": 11
}
}Route-Level Caching
Each route's scan data is cached independently. This means:
- Parallel scanning — Multiple routes can be scanned concurrently using Playwright browser contexts
- Partial invalidation — Changing one route only rescans that route, not the whole app
- Cache sharing — Colors found on multiple routes are deduplicated in the final output
Cache Management
# View cache stats
npx nightfall-css cache --stats
# Routes cached: 12
# Total colors: 34
# Cache size: 48KB
# Last full scan: 2026-04-08T12:00:00Z
# Clear the cache (forces full rescan)
npx nightfall-css cache --clear
# Clear cache for a specific route
npx nightfall-css cache --clear --route /pricingParallel Route Scanning
By default, Nightfall scans up to 3 routes concurrently. Increase this for faster scans on large sites (at the cost of more memory):
# Scan 5 routes in parallel
npx nightfall-css scan --url http://localhost:3000 \
--routes / /about /pricing /docs /blog \
--concurrency 5Generation Performance
Theme generation (the transform step) is fast because it operates on the color graph in memory, not on the DOM. Typical generation times:
- Small app (10-20 colors) — Under 10ms
- Medium app (20-50 colors) — Under 25ms
- Large app (50-100 colors) — Under 50ms
- Very large (100+ colors) — Under 100ms
The bottleneck is always the scanning step (browser launch + page rendering), not the transformation.
Watch Mode Optimization
In watch mode, Nightfall keeps the Playwright browser open between rescans, eliminating the browser launch overhead (typically 500-1000ms):
# Watch mode keeps browser warm
npx nightfall-css watch --url http://localhost:3000
# First scan: ~1200ms (includes browser launch)
# Subsequent rescans: ~200ms (browser already running)
# Incremental rescans: ~100ms (only changed routes)