Docs

proa new site

Scaffold an opinionated Proa project.

Open Markdown

Use proa new site to create a Rust project with the Proa site conventions. Pass the complete destination path; its final segment becomes the package name, and --title controls the human-facing title independently:

proa new site my-app --yes
cd my-app && proa dev --open

To study a complete production-shaped application, scaffold ORIGIN:

proa new site origin-atlas --template origin --yes

For a Docker-ready deployment:

proa new site my-app --deploy docker --yes

Templates

--template selects a product preset:

TemplateShape
app (default)SQLite/SQLx with request-scoped keyed data loading, proa-ui source components, Tailwind source, and guided application content. basic is an accepted alias.
marketingContent-oriented site without a database.
docsDocumentation content and HTML/Markdown representations.
minimalSmall CSS-based application with optional blank starter content.
originORIGIN, the complete reference application: a live routing atlas backed by a custom RIPEstat DataLoader, streamed Suspense sections, proa-ui components that each carry a Markdown representation, rsjs islands, self-hosted fonts, and a golden test pinning the server-rendered document byte for byte.

Unknown template names fail with an error naming the presets.

Capability overrides

Presets resolve to orthogonal capabilities, each individually overridable:

FlagValuesEffect
--databasesqlite, noneDatabase module, migrations, request-scoped loader, and guided data components.
--uiproa, noneVendors proa-ui source components into src/components/.
--stylingtailwind, cssTailwind source input or a plain stylesheet. --tailwind and --no-tailwind are compatibility aliases.
--starterguided, blankGuided starter content or empty pages. --empty is an alias for --template minimal --starter blank.
--deploynone, docker, railway, coolifyProvider-native deployment files.

The origin preset owns its application content, so only --deploy can be overridden there; examples/origin-routing-atlas in the Proa repository is the same template, and a drift test keeps the two byte-identical.

Options

FlagBehavior
--title <TITLE>Human-facing display title. The package name always comes from the path.
--vscode / --no-vscodeGenerate or omit the recommended VS Code workspace files.
--agents-md / --no-agents-mdGenerate or omit AGENTS.md local agent instructions (on by default).
--no-gitSkip Git initialization.
--verifyRun the full proa check --all validation after committing the project.
--start / --openEnter proa dev after scaffolding, optionally opening the local URL.
--offlineForbid registry, tool, and Cargo network access.
--dry-run / --jsonResolve and print the complete plan without writing anything.
--yesAccept recommended defaults; never implies verify, start, open, or deploy.

Tailwind prerequisite

When Tailwind is enabled, proa dev and proa build invoke tailwindcss from your PATH to create public/styles.css; a checked-in prebuilt stylesheet keeps the first page styled even when the executable is missing. Install it with the Tailwind-only installer mode:

curl -fsSL https://proa.so/install.sh | sh -s -- --tailwind-only

Or with Homebrew: brew install tailwindcss. A dry run never installs tools.

Dry runs

Use dry runs before generating into an existing directory:

proa new site my-app --dry-run
proa new site my-app --dry-run --json

The text dry run prints planned file writes; the JSON dry run emits the machine-readable scaffold plan. Scaffolding itself is transactional: files are assembled and validated in a staging directory and committed only after the whole plan succeeds, so a conflict never leaves partial writes.

Generated layout

The default app preset generates:

.cargo/
config.toml
.github/
workflows/
ci.yml
.env.example
Cargo.toml
proa.config.json
proa.lock.json
build.rs
rust-toolchain.toml
README.md
AGENTS.md
src/
components/
endpoints/
layouts/
pages/
app.rs
config.rs
db.rs
error.rs
loader.rs
main.rs
routes.rs
static_assets.rs
migrations/
data/
public/
favicon.svg
styles.css
styles/
input.css
tests/

What each directory holds:

PathContents
src/main.rsProcess startup: configuration, the database pool, and serving the router.
src/routes.rsRouter assembly and middleware, kept visible so a deploy is easy to audit.
src/pages/One module per route: the page component, its Markdown representation, and the handler. See Routing.
src/endpoints/Operational endpoints such as /healthz and /readyz.
src/layouts/Document shells shared across routes, such as root.rs.
src/components/Source-owned render components, including any vendored with proa ui add.
src/db.rs, src/loader.rsThe SQLx pool and the request-scoped DataLoader behind cx.load_typed.
migrations/, data/SQL migrations and the local SQLite database location.
public/Pre-built browser assets: CSS output, images, downloads.
tests/Integration tests, including the representation and data-loading contracts.
build.rsBuild-time wiring. The origin template also runs the proa_fonts_build collector for google_font!/local_font! declarations (see Fonts).

proa.config.json controls the proa dev and proa build lifecycle commands and records component registry aliases. proa.lock.json records the scaffold capabilities and every component installed by proa ui add. The generated Cargo dependencies on Proa crates are git dependencies on the Proa repository; .cargo/config.toml only turns on git-fetch-with-cli so your Git credential helper can fetch it.

Live reload

proa dev reloads open browser tabs after a rebuild, so editing a page and looking at it does not need a manual refresh.

A Rust change recompiles the site and replaces the server process, so the tab does a full reload, in the same way Vite falls back to full-reload for anything it cannot patch in place. The reload is only sent once the replacement server is accepting connections again, which is what keeps a tab from landing on a connection-refused page. A stylesheet-only change never restarts the server: the assets are rebuilt and every stylesheet is re-fetched in place, so scroll position, form values, and open dialogs survive. A failed build leaves the last working server running and raises a dismissible overlay in the tab with the failure summary. Cargo streams the compiler diagnostics themselves to the proa dev terminal, and the overlay says so.

Nothing needs to be added to your source. proa dev runs the event stream in its own process, so it outlives every server restart, and proa_framework_axum::serve injects the matching client into HTML responses. Applications that do not serve through proa_framework_axum::serve can add proa_framework_axum::DevReloadLayer themselves.

Injection is switched on by two variables that proa dev sets on the server process it spawns: PROA_DEV_RELOAD_PORT and PROA_DEV_RELOAD_TOKEN. The token is 16 random bytes drawn once per proa dev process, and the event stream answers 403 to any request that does not present it. That is what stops another site open in the same browser from reading your build failures, which carry absolute paths and source snippets, and what stops a tab left over from an earlier session from being reloaded by a server that never served it. Because both variables are required and the token is never reused, a PROA_DEV_RELOAD_PORT left exported in a shell profile cannot switch dev tooling on in a release binary; it logs a warning and stays off.

A tab whose token has gone stale, which is what a restarted proa dev looks like, reloads itself once to pick up the current one. Live reload holds one Server-Sent Events connection per tab, and browsers allow six per origin, so responses to embedded frames are left uninjected rather than spending a connection each.

The controls are proa dev flags:

FlagDefaultEffect
--no-reloadreload onTurns live reload off.
--reload-port <PORT>operating-system assignedPort for the event stream. Set it only if you want a predictable one. proa dev passes it to the server as PROA_DEV_RELOAD_PORT.
--no-css-hot-swaphot swap onRestarts the server for stylesheet changes instead of swapping them in place. Use it when stylesheets are compiled into the binary rather than served from disk.
--debounce-ms <MILLISECONDS>300Quiet window a change must survive before a rebuild starts. Raise it if a formatter or code generator triggers extra cycles.

The debounce window cannot go below the 100ms file-watch poll interval. proa dev reads no PROA_DEV_* variables from your shell.

The event stream takes an operating-system assigned port by default. A fixed offset from the dev port would claim the port your next site wants, and that site would then fail to bind with an error naming neither live reload nor the process holding it. A tab whose stream endpoint has moved reloads itself and picks up the current one, so the port does not need to be stable. Pass --reload-port if you want it to be.

Live reload is a watch-mode feature, so proa dev --no-restart does not start it. Turning live reload off does not turn off the stylesheet fast path: a stylesheet-only change still rebuilds assets without restarting the server, it just does not tell the browser. Use --no-css-hot-swap for that, and note that --no-assets disables it too, since there is nothing left to rebuild.

The fast path only sees stylesheets under a watched path. dev.watch defaults to src, styles, Cargo.toml, build.rs, and proa.config.json, so a site whose only stylesheet is public/styles.css (what --no-tailwind generates) needs public added to dev.watch before edits to it are noticed at all.

When --deploy coolify is enabled, the generated project also includes Dockerfile, .dockerignore, coolify.env.example, and COOLIFY.md. See Coolify for the deployment flow and pull request preview URL setup.

Search

Type at least 2 characters