Quick Start
From zero to a running server in under 5 minutes.
Prerequisites
You need Bun installed. That's the only dependency.
curl -fsSL https://bun.sh/install | bash
1. Create your project
Make a folder and initialize it:
mkdir my-site && cd my-site
bun init -y
bun add index97
2. Create the server entry point
Create server.js:
import { createServer } from 'index97'
createServer({
pagesDir: './pages',
port: 3000,
dev: true
})
3. Create your first layout
Create pages/_layout.html:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>{{slot:title || My Site}}</title>
</head>
<body>
<nav><a href="/index97/">Home</a></nav>
<main>{{content}}</main>
</body>
</html>
4. Create your home page
Create pages/index.phtml:
<template data-slot="title">Welcome — My Site</template>
<h1>Hello, world!</h1>
<p>Building websites like it's 1997.</p>
5. Run it
bun server.js
Open http://localhost:3000. Your page renders inside the layout automatically.
dev: true, any file change instantly updates the browser. CSS changes re-stamp without a full reload.
6. Add a handler
Pair a .js file with your .phtml to provide data. Create pages/hello.js:
export async function GET(req) {
const name = new URL(req.url).searchParams.get('name') ?? 'world'
return { name }
}
And pages/hello.phtml:
<template data-slot="title">Hello — My Site</template>
<h1>Hello, {{name}}!</h1>
Visit /hello?name=Joey — the handler fetches data, the template renders it.
7. Add a dynamic route
Create pages/posts/[slug].js:
const posts = {
'hello-world': { title: 'Hello World', body: 'My first post.' }
}
export async function GET(req) {
const post = posts[req.params.slug]
if (!post) return new Response('', { status: 404 })
return { post }
}
And pages/posts/[slug].phtml:
<h1>{{post.title}}</h1>
<p>{{post.body}}</p>
Visit /posts/hello-world. The slug parameter is available via req.params.slug.
8. Build a static site
For dynamic routes, export staticPaths() to tell the builder which URLs to generate:
// posts/[slug].js
const posts = {
'hello-world': { title: 'Hello World', body: 'My first post.' }
}
export async function GET(req) {
const post = posts[req.params.slug]
if (!post) return new Response('', { status: 404 })
return { post }
}
export async function staticPaths() {
return Object.keys(posts).map(slug => ({ slug }))
}
Then run the build:
index97 build ./pages
Static assets from public/ are copied automatically. Output goes to dist/ by default:
index97 build ./pages --out ./output
Next steps
- Architecture — understand the full routing system
- Templates — all the template syntax
- Layouts — named slots, defaults, layout data
- Features — forms, partials, error pages, hot reload, CLI