Server-first.
Fragment-driven.
No SPA required.
Write HTML components that run on the server. Add interactivity exactly where you need it — with fragments, signals, or server functions. Nothing more.
Server Render
Components run on the server. Request data, session, params — all available at render time. Full HTML shipped, zero JS by default.
<script>
import { params } from 'jamrock:conn';
const { name } = params;
</script>
<h1>Hello, {name}!</h1>
Fragments
Named regions of the page that can be updated live via SSE — without a full reload, without a client router, without any boilerplate.
<fragment name="feed" interval="5">
{#each posts as post}
<article>{post.title}</article>
{/each}
</fragment>
Client Signals
When you genuinely need client reactivity, reach for signals. Declare them in a client script, reference them with $ in templates.
<script context="client">
import { signal } from 'jamrock';
const count = signal(0);
</script>
<button onclick={() => count.value++}>
Clicked {$count} times
</button>
Try it live
This counter runs on the server. Click a button — the fragment re-renders via SSE, no page reload.
<script context="module">
let count = 0;
export async function increment() { count++; }
export async function decrement() { if (count > 0) count--; }
</script>
<fragment name="counter">
<form rpc:call={decrement}><button>−</button></form>
<span>{count}</span>
<form rpc:call={increment}><button>+</button></form>
</fragment>
Get started
Install jamrock and pick a runtime — node, deno, or bun:
curl -L get.jamrock.dev | bash
Then scaffold your first app:
jamrock init my-app
cd my-app && npm install
npm run dev
■ Jamrock v0.0.0 (node v24)
Processing ./pages → ./build
Listening on http://localhost:8080