Quick Start
Build your first Avalon page with an interactive island in under 5 minutes.
Scaffold a new project
The fastest way to get started is with the Avalon CLI:
npx avalon my-app
For Bun users:
bunx avalon my-app
This will walk you through selecting your frameworks, styling approach, and deployment target.
Install dependencies
cd my-app
npm install
Or with Bun:
cd my-app
bun install
Start the dev server
npm run dev
Open http://localhost:3000 in your browser. You should see the Avalon welcome page.
Create a page
Pages live in src/pages/. Create src/pages/hello.tsx:
export default function HelloPage() {
return (
<div>
<h1>Hello, Avalon</h1>
<p>This page ships zero JavaScript.</p>
</div>
);
}
Visit http://localhost:3000/hello — you'll see your page rendered as pure HTML with no client-side JavaScript.
Add an island
Islands are interactive components that hydrate on the client. Create src/islands/Counter.tsx:
/** @jsxImportSource preact */
import { useState } from 'preact/hooks';
export default function Counter() {
const [count, setCount] = useState(0);
return (
<button onClick={() => setCount(c => c + 1)}>
Count: {count}
</button>
);
}
Then use it in your page with the island prop to control when it hydrates:
import Counter from '../islands/Counter.tsx';
export default function HelloPage() {
return (
<div>
<h1>Hello, Avalon</h1>
{/* Hydrates only when the user first interacts with it */}
<Counter island={{ condition: 'on:interaction' }} />
</div>
);
}
Build for production
npm run build
Avalon builds a Nitro server bundle in .output/. Deploy it to Node, Bun, Cloudflare Workers, Vercel, or any Nitro-compatible target.
Try it live
Here's a live example of an island component — it starts in a static state and becomes interactive on your first interaction: