Prerequisites
- Local tools: Use Node.js 22 or newer and pnpm.
- Cloudflare account: An account is needed only for deployment. Local development works without a login. You don't need a paid Workers plan to build and deploy with Goribu.
Create an app
pnpm create goribu@latest my-app
cd my-app
pnpm install
pnpm dev
pnpm create goribu@latest my-app --js
cd my-app
pnpm install
pnpm dev
Open the local URL printed in your terminal. The starter is ready for you.
- App name: Use up to 50 lowercase letters, digits or hyphens. Start with a letter and end with a letter or digit. Pass a name, not a path.
- Existing directories: The starter generator does not overwrite an existing directory.
- Dependency installation: The starter generator does not install dependencies for you.
For JavaScript, add --js:
pnpm create goribu@latest my-app --js
Both variants use the same framework APIs.
Find your way around
| File | Purpose |
|---|---|
src/routes/index.tsxsrc/routes/index.jsx | The home page. |
public/ | Static assets served at the site root. |
src/setup/_document.tsxsrc/setup/_document.jsx | Optional custom HTML document around your pages. |
src/setup/client-entry.js | Required browser bootstrap and global CSS imports. |
src/styles/global.css | Global styles and the Tailwind import. |
goribu.config.js | App runtime, deployment, and resource settings. |
vite.config.js | Vite, Goribu, and Tailwind plugins. |
AGENTS.md | Project instructions for coding agents. |
Your pages and handlers go in the src/routes together, while reusable components can go in other folders like src/components/. Leave .goribu/, .wrangler/, goribu.wrangler.jsonc, and node_modules/ to the tools that generate them.
Start coding with your agent
Your agents will read the included AGENTS.md before changing the app. If not, just ask them to. Then describe a feature and its expected behavior. The AI coding guide explains how to provide useful context and At a glance there's a compact API introduction to point your agents to.
Commands
Run commands from your app directory.
| Command | Purpose |
|---|---|
pnpm dev | Develop locally with hot updates. |
pnpm typecheck | Check TypeScript without emitting files. TypeScript starter only. |
pnpm build | Build the Worker, browser assets, and static pages. |
pnpm check | Inspect the production target, resources, and migrations without changing them. |
pnpm exec goribu cloudflare-login | Log in to Cloudflare through Wrangler. |
pnpm run deploy | Build and deploy to Cloudflare. |
- Custom port: Run
pnpm dev --port 5199to use a specific port number (in this case 5199) instead of the default. The command fails if the port is already in use. - Network access: Add
--hostto yourpnpm devto listen on every network interface. Then other devices on your network can reach the development server. - Persistent defaults: Set development defaults in
vite.config.js.
pnpm dev --port 5199
pnpm dev --host
If using npm, add -- before script options so npm forwards them to the development server: npm run dev -- --host or npm run dev -- --port 5199.
Development and production builds compile TypeScript without type checking. Run pnpm typecheck separately in TypeScript projects.
Use the full pnpm run deploy command (don't forget the run part) to ship your app to Cloudflare. See Deploys when you are ready to publish.
Write a route
Create src/routes/hello.tsxsrc/routes/hello.jsx with the following example, then visit /hello?name=Kate. Use type-only imports to describe your page props and request handlers:The handler passes props to the page with res.render():
import type { Handler } from "goribu/server";
import type { Meta } from "goribu";
type Props = { name: string };
// Read the query string and pass serializable props to the page.
export const GET: Handler<Props> = (req, res) => {
const name = req.query.get("name")?.trim() || "friend";
return res.render({ name });
};
export const meta: Meta<Props> = ({ props }) => ({
title: `Hello, ${props.name}`,
});
// Render the same props on the server and in the browser.
export default function HelloPage({ name }: Props) {
return <h1>Hello, {name}.</h1>;
}
// Read the query string and pass serializable props to the page.
export const GET = (req, res) => {
const name = req.query.get("name")?.trim() || "friend";
return res.render({ name });
};
export const meta = ({ props }) => ({
title: `Hello, ${props.name}`,
});
// Render the same props on the server and in the browser.
export default function HelloPage({ name }) {
return <h1>Hello, {name}.</h1>;
}
- Handler generics:
Handler<Props, Env, Params>also accepts types for Worker bindings and dynamic parameters. - Runtime validation: Types describe expectations, so validate request input at runtime. The API reference lists public types.