Less Complexity.
More Power.

Web Framework for High-Performance Sites and Apps.

Opinionated server-oriented framework built with TypeScript, Hono and Bun.

Tailwind, file-based routes, streaming templates, dynamic islands, and more.

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(async (context) => {
  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(() => {
  return html`
    <div>
      <h1>Async Content Blocks:</h1>
      ${AsyncBlock(1000, "Loading...")}
      ${AsyncBlock(2000, "Loading 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 and crawlers.

Dynamic Islands.

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

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

// Bun supports top-level await, so this compiles at build/server start time
const ExampleCounter = await createPreactIsland(import.meta.resolve('@/src/components/example-counter.tsx'));

export default createRoute(() => {
  return html`
    <div>
      <!-- Call the component as a function and pass any props you need! -->
      ${ExampleCounter({ count: 5 })}
    </div>
  `;
});