stoneware

Documentation

Quick start

Scaffold a project, run it, and understand what the two directories mean.

Scaffolding runs on plain Node, so it works before Bun is installed. Everything after that — the dev server, the build — runs on Bun.

terminalsh
bunx create-stoneware my-site   # npx create-stoneware my-site also works
cd my-site
bun install
bun run dev

What you get

  • routes/ — server-rendered pages and API routes. Never ships JavaScript.
  • islands/ — interactive components. The only place client JS originates.
  • lib/ — behavior functions and shared utilities.
  • public/ — static assets, served as-is.
  • stoneware.config.ts — port, CSP, CSRF settings.

That split is the whole mental model. A component is interactive because of the directory it lives in, not because of a directive written inside it.

Your first page

routes/index.tsxtsx
import type { PageProps } from "stoneware";

export default function Home({ params }: PageProps) {
  return <h1>It renders on the server</h1>;
}

A template is a plain function: props in, markup out. There is no base class to extend, no hook to call, and no lifecycle to learn. It runs once per request, on the server.

Something wrong in the framework itself rather than the page? Open an issue on GitHub.