Status: ACCEPTED Date: 2026-05-23 Supersedes: ADR-0033 (renderer timing independence — confirmed) Applies to: v0.21 (contract) → v0.22 (production implementation)
v0.21 defined the ISR cache contract (IsrCache, MemoryIsrCache, isr-manifest.json).
The initial implementation included a TCP Redis adapter (RedisIsrCache) using raw RESP
protocol — a mistake.
LessJS targets edge-first deployment (Cloudflare Workers, Deno Deploy). TCP connections
are not available on Cloudflare Workers, and Deno has Deno.openKv() natively. Redis is
an unnecessary infrastructure dependency for a framework whose primary selling point is
zero-runtime static output.
- Redis adapter deleted from codebase. The RESP-based
RedisIsrCachewas removed. - IsrCache interface remains the single contract.
MemoryIsrCacheis the reference implementation for dev/tests. - Production adapters go in v0.22, targeting the platforms LessJS actually runs on:
| Platform | Adapter | Backend |
|---|---|---|
| Cloudflare Workers | CfKvIsrCache |
Workers KV (KVNamespace) |
| Deno Deploy / Deno | DenoKvIsrCache |
Deno.openKv() |
| Self-hosted / Redis | RedisIsrCache (optional, community) |
Redis via ioredis |
- The adapter pattern enables platform-native TTL without framework-level timer
management. CF KV
expirationTtland Deno KVexpireInboth match ISR'srevalidatesemantics exactly.
Route exports revalidate: 60
↓
Build writes isr-manifest.json
↓
Edge handler (CF Worker / Deno)
↓
IsrCache.get(cacheKey)
├─ miss → renderDSD(tagName, component, props)
│ → cache.set(key, { html, revalidate: 60 })
│ → return fresh HTML
├─ hit → return cached HTML
├─ stale → return cached HTML + trigger async regeneration
└─ error → return last good HTML or 500
The key insight from ADR-0033: renderDSD() is timing-independent. Whether called at
build time (SSG) or request time (ISR regeneration), the output is identical. ISR is
not "adding SSR" — it is reusing the same renderer behind an HTTP endpoint.
| Concern | CF Workers | Deno Deploy |
|---|---|---|
| TCP availability | ❌ No raw TCP | ✅ via Deno.connect |
| KV alternative | ✅ Workers KV | ✅ Deno.openKv() |
| Global distribution | ✅ KV is edge-replicated | ✅ Deno KV (FoundationDB) |
| TTL | ✅ expirationTtl |
✅ expireIn |
| Cold start | ✅ API call, no connect | ✅ API call, no connect |
Redis is appropriate for self-hosted deployments but should not be the default.
A community-maintained RedisIsrCache can exist as an optional adapter.
- Framework aligns with deployment targets actually used (CF Workers, Deno).
- No TCP dependency or connection management code in core.
- Each platform adapter is ~20 lines — the
IsrCacheinterface is the right abstraction.
- Redis users need to bring their own adapter (or use a community package).
DenoKvIsrCacherequires Deno 2.x+ (KV is stable since 2.0).- ISR production handler still needs to be built (v0.22 scope).
- ADR-0033: Renderer Kernel — timing-independent
renderDSD() - ADR-0035: SSG Admission — client-only island exclusion (v0.20)
- ADR-0036: Ocean-Island Architecture (v0.20)
- ADR-0037: DSD-First Strategic Boundary (v0.20)
- v0.21 changelog: ISR contract + build manifest
- v0.22 roadmap: Production ISR handler + KV adapters + Showcase