brust 2.0.0-alpha.5
Guide / Project structure

Project structure

A brust app is a routes file, components, an optional actions app, and a brust.toml. This is the blank template.

The files

~/my-app
my-app/
├── routes.tsx
├── app.css
├── components/
│   ├── Layout.tsx
│   └── Counter.tsx
├── pages/
│   └── HomePage.tsx
├── actions.ts
├── public/
│   └── favicon.svg
├── brust.toml
├── wrangler.jsonc
├── package.json
├── tsconfig.json
├── README.md
└── .gitignore

Pick a file to see what it does.

Live demoFileTree · native

routes.tsx Maps paths to components with defineRoutes. The entry brust build reads.

Only routes.tsx is required by name, and you can pass another entry to brust build. The components/ and pages/ split is a convention: the compiler follows imports, not folders.

The scripts

package.json
{
  "scripts": {
    "dev": "brust dev routes.tsx",
    "build": "brust build routes.tsx",
    "start": "brust start",
    "typecheck": "bun check",
    "dev:cf": "brust dev routes.tsx --target cloudflare",
    "deploy:cf": "brust build routes.tsx --target cloudflare && wrangler deploy -c dist/cf/wrangler.jsonc"
  },
  "devDependencies": {
    "@tailwindcss/node": "4.3.3",
    "@tailwindcss/oxide": "4.3.3",
    "@types/bun": "^1.4.0",
    "@types/react": "^19.2.0",
    "tailwindcss": "4.3.3",
    "typescript": "^7.0.2",
    "wrangler": "^4.149.0"
  }
}

dev runs brust dev: it builds into .brust/dev, starts the server and rebuilds when you save, see Dev mode. The :cf scripts target Cloudflare Workers, see Deployment. tailwindcss, @tailwindcss/node and @tailwindcss/oxide are pinned dev dependencies at one version: the build uses them, the server does not.

What brust build writes

~/my-app
dist/
├── manifest.json      every route and component, with its tier
├── jinja/<id>.jinja   the compiled template of each component
├── client/*.js        native chunks and React islands, content-hashed
├── client/*.css       app.css and the Tailwind utilities you use, minified, hashed
├── jobs.js            the server code: loaders and jobs
├── actions.js         your actions app, when [actions] is on
├── public/            a copy of ./public
└── index.js           bun dist/index.js starts the server

The build writes to a temporary folder next to dist/ and swaps it in only when it succeeds, so a failed build leaves the last good one in place. Each page links the CSS its layout and page import from client/ in <head>; no JS bundle carries CSS. dist/ imports react and @brust/core at runtime: keep it inside the app, next to its node_modules.