Web Framework for Dynamic High-Performance Sites and Apps.

Server-first framework built with TypeScript and Bun. File-based routes, streaming templates, dynamic islands, server actions, and minimal JavaScript.

Read The Docs Install Hyperspan

All TypeScript.

No special syntax to learn. No custom file extensions or formats. No special rules or weird semantics. No magic. No compiler (thanks Bun!). All TypeScript, all the way down.

import { createRoute } from '@hyperspan/framework';
import { html } from '@hyperspan/html';

export default createRoute().get(async (c) => {
  const posts = await fetchPosts();

  return html`
    <div>
      <h1>Posts</h1>
      <ul>
        ${posts.map((post) => html`<li>${post.title}</li>`)}
      </ul>
    </div>
  `;
});
import { createRoute } from '@hyperspan/framework';
import { html } from '@hyperspan/html';

export default createRoute().get(() => {
  return html`
    <div>
      <h1>Async Content Blocks:</h1>
      ${AsyncBlock(1000, "Content Block 1")}
      ${AsyncBlock(2000, "Content Block 2")}
    </div>
  `;
});

async function AsyncBlock(waitMs: number, msg: string) {
  await sleep(waitMs);
  return html`<div>${msg}</div>`;
}

Streaming Templates.

Streaming responses by default for any template that contains async content. Send all your static content immediately for better TTFB, then stream in each piece of dynamic content as it's ready. Automatic opt-outs for bots, crawlers, and AI.

Dynamic Islands.

Rich client-side interactivity with server-first performance. Only ship the JavaScript you need, when you need it. Zero client-side JavaScript by default.

import { html } from '@hyperspan/html';
import { createRoute } from '@hyperspan/framework';
import { renderPreactIsland } from '@hyperspan/plugin-preact';
import ExampleCounter from '@/src/components/example-counter.tsx';

export default createRoute().get(() => {
  return html`
    <div>
      <!-- Call the renderIsland() function and pass any props you need! -->
      ${renderPreactIsland(ExampleCounter, { count: 5 })}
    </div>
  `;
});
import { createAction } from '@hyperspan/framework/actions';
import { html } from '@hyperspan/html';
import { z } from 'zod/v4';

export default createAction({
  name: 'example-action',
  schema: z.object({
    name: z.string().min(1, 'Name is required'),
  }),
})
  .form((c, { data }) => {
    return html`<form method="post">
      <input type="text" name="name" value="${data?.name}" />
      <button type="submit">Submit</button>
    </form>`;
  })
  .post(async (c, { data }) => {
    return html`<p>Hello, ${data.name}!</p>`;
  });

Server Actions.

Actions render forms that submit their data back to the server and update the view in-place automatically. Keep all your validation and data processing logic on the server, with minimal JavaScript shipped the client.