Minimal & Fast
Complete HTML from the server. No React runtime, no hydration waterfall — only the bytes a content page needs.
A minimal, high-performance foundation for content sites. Complete HTML from the server, islands only where you touch, cache ready before the visitor asks.
Response
200 · HTML ready
Routes
route() · TTL
$ npx jskelet init
✓ route ready
✓ island ready
→ http://localhost:3000
Why JSkelet
The server prepares the content, the cache removes the waiting, and islands add only the behaviour a page actually needs.
Complete HTML from the server. No React runtime, no hydration waterfall — only the bytes a content page needs.
A menu, a counter or a chart lives in its own island. Its module downloads only when it becomes visible.
Plain async controllers, EJS templates and a small API. Readable without ceremony, replaceable without drama.
Transparent performance
These numbers are read from the real build output and reflect the weight after gzip. Working code, not a marketing promise.
| Raw | gzip | |
|---|---|---|
| Stylesheet (Tailwind v4 output) | 77.4 kB | 13.1 kB |
| Client entry (island loader) | 564 B | 302 B |
| Icon sprite | 12.1 kB | 3.9 kB |
| Every island (on demand, separate chunks) | 72.0 kB | 27.7 kB |
| Total — if every island loads | 162.0 kB | 45.0 kB |
45.0 kB
Everything included (gzip)
Stylesheet, entry, sprite and every island on the site combined. No single page downloads all of it.
0
Web font requests
A system font stack. No FOUT and no font-driven layout shift.
1
Render-blocking request
One stylesheet. The client entry is a module, so it is deferred.
2
Islands loaded immediately
Theme and mobile menu. Every other island waits until it scrolls into view.
If you want a comparable number, measure your own project the same way: a claim of being lightweight only means something once it is measured on your page.
Simple by design
Stale-while-revalidate keeps visitors out of the render queue. One route, one TTL, predictable behaviour.
export default function register(app, { route, notFound }) {
app.get("/", route(
async () => ({
view: "pages/home",
data: { pillars },
}),
{ revalidate: 3600 },
));
app.get("/product/:slug", route(async ({ params }) => {
const product = await getProduct(params.slug);
if (!product) notFound();
return { view: "pages/product", data: { product } };
}));
}
Ops you can see
The HTML cache starts in process memory. Flip a switch and the same keys share across replicas, open a hardened panel, and talk to your edge.
Shared tier
L1 stays in process for microsecond hits. Redis holds the shared HTML/data bodies and fans invalidateHtmlCache() / clearHtmlCache() to every replica over pub/sub — ioredis is optional; missing it just means L1-only.
Primary store
In-process L1
Shared bodies
Redis HTML + data
Fan-out
Pub/sub invalidate
The right match
JSkelet is built for content and discoverability. For state-heavy applications, another tool is often the better answer.
FAQ
Most pages are not interactive. React's cost is fixed: the runtime downloads, a tree is built, hydration runs — and the result is the same HTML the server already produced. JSkelet removes that fixed cost and gives interaction only to the elements that need it.
The framework itself is plain JavaScript with JSDoc and has no compile step. On the application side you can enable checked JavaScript and keep most of the same type safety without a build; for .ts files you would add a step to the pipeline yourself.
Each instance keeps its own L1 cache, so a cold boot still needs a warm-up and TTLs can drift. Prewarming closes most of that gap; an optional Redis tier shares HTML and broadcasts invalidateHtmlCache() / clearHtmlCache() to every replica over pub/sub. Targeted invalidation itself is first-class either way.
Yes. Without a manifest the asset helper falls back to unhashed paths and the layout simply prints no stylesheet tag. Forgetting the build step gives you an unstyled but working page, not an error.
More questions and the full mapping table live on the migration page.
One command scaffolds a working skeleton with a route, a component and an island.