Public betaCargo + Rust

Getting started

Build your first Axonyx site without needing to be a Rust expert first: install two Cargo tools, scaffold a site, run the local server, then check and build the app when you are ready to share it.

Beta API

Axonyx is ready for early sites, docs, landing pages, package UI experiments, and architecture feedback. The syntax and standard library will still change before 1.0.

The first loop

Think of Axonyx like a Cargo-native web framework: your first edits are pages, routes, content, and UI. Rust is the engine underneath, not a wall you need to climb before rendering a page.

What you will build

A small site with a generated `app/page.asx`, public assets, Foundry styling, route checks, and a production build command.

What you need

Rust with Cargo installed, then the Axonyx CLI tools from crates.io. If you come from React or Next, start by treating `.asx` files like readable page components.

Current beta packages

The native beta loop now resolves from crates.io. New apps created with the site template use the runtime and UI packages directly from Cargo.

Framework crates

Loading package versions from Axonyx state...

This line is seeded from `dist/_ax/state/snapshot.json` as the first backend-provided state packet.

UI package

`axonyx-ui` 0.0.71 is consumed as a Cargo package.

Package CSS is served through `/_ax/pkg/axonyx-ui/index.css` by the Axonyx dev/build tooling.

Foundry component behavior is served from `/_ax/pkg/axonyx-ui/js/index.js`, so apps do not need to copy generic drawer, tabs, dropdown, popover, or theme-switcher JS.

Install

Install the project scaffold and Cargo helper. These are normal Cargo binaries, so there is no Node toolchain requirement for the native Axonyx loop. If you do not have Rust yet, install it from `rustup.rs` first.

Code
ax
cargo install create-axonyx
cargo install cargo-axonyx

Create a site

Create the site template and start the local dev server. This is the shortest happy path: install, create, run, open the browser.

Code
ax
create-axonyx my-site --yes --template site
cd my-site
cargo ax run dev

Open `http://127.0.0.1:3000`. If the generated site renders, the first loop is complete. Keep the dev server running while you edit `app/page.asx` or `app/layout.asx`.

Generate routes and components

The generator creates canonical function-shaped ASX without replacing existing files. Use the short `g` alias while building the app shell.

Code
terminal
cargo ax g page settings/profile
cargo ax g component ThemeSwitcher
cargo ax g island CommandPalette

An island includes a colocated client module and is only loaded by routes that render that component.

Choose a starter

Axonyx ships three focused starters for the first static-site loop. They all use Cargo packages, Foundry UI, `use "@axonyx/ui"`, Aegis checks, and the same `cargo ax run dev` workflow.

site

Use this for a public product site, company page, or framework landing page. It includes home, about, and contact routes with a polished Foundry shell.

Code
ax
create-axonyx my-site --yes --template site

docs

Use this for documentation. It starts with a left docs nav, getting-started content, component links, and a theme switcher loop that matches the native Axonyx site direction.

Code
ax
create-axonyx my-docs --yes --template docs

blog

Use this for content-first publishing. Posts are prerendered from local files, so the first blog loop has no database or CMS server requirement.

Code
ax
create-axonyx my-blog --yes --template blog

Edit `.asx` pages

Routes live in `app/**/page.asx`. The syntax is JSX-like enough for frontend developers, but lowers into Axonyx runtime output.

Code
ax
use "@axonyx/ui"
import { Card } from "@axonyx/ui/foundry/Card.asx"

page Home() {
  const heroClass = "starter-card"

  return ASX {
    <Container max="xl">
      <Card className={heroClass} title="Hello Axonyx">
        <Copy tone="lead">Readable pages, Rust runtime.</Copy>
      </Card>
    </Container>
  }
}

`use "@axonyx/ui"` activates the package stylesheet and component behavior runtime. Component imports stay explicit, so pages remain easy for humans and AI tools to inspect.

Check before deploy

Run doctor before sharing or deploying. It checks config, runtime, package versions, UI package resolution, `use "@axonyx/ui"` asset wiring, `.asx` and `.ax` diagnostics, and typed API contracts.

Code
ax
cargo ax check
cargo ax doctor --deny-warnings
cargo ax build --clean

The static build writes deployable HTML into `dist/`.

Code
ax
cargo ax api --schema
cargo ax api --openapi --out public/openapi.json

The API contract commands are useful once your app has routes, loaders, or actions with declared return types.Read the API contracts guide.

Deploy to Render

For Render, use `cargo ax build` as the build command and `cargo ax run start --host 0.0.0.0 --port $PORT` as the start command.

Code
terminal
cargo install cargo-axonyx --version 0.2.16 --force && cargo ax build --clean
cargo ax run start --host 0.0.0.0 --port $PORT

Open the Render deploy guide.

Fast QA with Aegis

Aegis is the Rust-first QA runner behind `cargo ax test`. New `create-axonyx` templates include `aegis.toml`, so fast pre-deploy checks can verify route status, expected text, expected links, and same-origin broken-link detection.

Code
ax
cargo install axonyx-aegis --force
cargo ax test
cargo ax test --format json --fail-fast false
Code
ax
base_url = "https://axonyx.dev"

[[fast]]
name = "home"
goto = "/"
expect_text = "Axonyx"
expect_links = ["/docs/getting-started", "/components"]
check_links = true
expect_not = ["Internal Server Error"]

Inspect actions

`cargo ax actions` prints route-local action contracts from `app/**/actions.ax`, including input type, optional marker, and default value.

Code
ax
cargo ax actions
cargo ax actions --format json
cargo ax actions --schema

Keep packages current

If `cargo ax doctor` warns that `axonyx-runtime` or `axonyx-ui` is behind the version expected by your CLI, run the upgrade helper and then refresh Cargo`s lockfile.

`cargo ax upgrade` also repairs the canonical `axonyx-ui` stylesheet and behavior runtime entries in `app/layout.asx` when the UI module is already installed.

Code
ax
cargo ax doctor
cargo ax upgrade
cargo update
cargo ax doctor --deny-warnings

State bridge

Small local state can be declared directly in `.asx` and bound to elements. The compiler lowers this into stable bridge metadata, then the runtime injects the tiny client bridge only when the page needs it.

Axonyx now loads a small Rust/WASM executor for typed String, Number, and Bool local operations. The browser host still owns events and targeted DOM writes, and falls back safely when WebAssembly is unavailable.

Live binding

Current theme:silver

Current count:1

Backend patch

This form posts to `app/docs/getting-started/actions.ax`. The backend returns an Axonyx patch response, then the state bridge updates both page state and imported component state without a page reload.

Sending patch...

Patch applied.

Patch failed.

Component-owned state

Imported component patch

This card owns its own `mode` state. The route action patches it through `StatePatchProbe.mode`, so the page does not need to know the internal signal key.

Component mode:silver

Authoring shape

Code
ax
// app/components/StatePatchProbe.asx
component StatePatchProbe() {
  state mode: String = "silver"

  render ASX {
    <strong bind:text={mode}>{mode}</strong>
  }
}

// app/docs/getting-started/page.asx
import { StatePatchProbe } from "@/components/StatePatchProbe.asx"

state docsTheme = "silver"

<ActionForm name="SetDocsTheme">
  <select name="theme">
    <option value="silver">silver</option>
    <option value="bronze">bronze</option>
    <option value="gold">gold</option>
  </select>
  <button type="submit">Apply backend patch</button>
</ActionForm>
<StatePatchProbe />

// app/docs/getting-started/actions.ax
action SetDocsTheme(theme: string) {
  require input.theme in themes else error "Theme must be silver, bronze, or gold."
  patch docsTheme = input.theme
  patch StatePatchProbe.mode = input.theme
  return ok()
}

Environment contract

Keep real values in `.env`, but declare the contract in `app/backend.ax`. Axonyx checks `env.KEY` reads before the build, so a backend file cannot silently depend on an undeclared variable.

.env

Code
ax
AX_SECRET_DB_URL=postgres://localhost/axonyx
AX_PUBLIC_SITE_URL=https://axonyx.dev

app/backend.ax

Code
ax
backend
  env AX_SECRET_DB_URL: Secret<String>
  env AX_PUBLIC_SITE_URL: Public<String>
  data themes: List<String> = ["silver", "bronze", "gold"]

Backend usage

Code
ax
export type Post {
  title: String
  slug: String
  summary?: String
}

query loadPosts(status: String = "published") -> Post[] {
  data siteUrl = env.AX_PUBLIC_SITE_URL
  data posts = db.posts.where({ status: input.status }).order({ created_at: "desc" }).limit(6).all()
  return posts
}

query loadFeaturedPosts() -> Post[] {
  data posts = db.query("select * from posts where featured = ?", true)
  return posts
}

Typed data V1

Axonyx can define record types in `.ax`, bind loader results to typed lists, and catch missing fields before render.

Code
ax
page Posts() {
  data status: String = "published"
  data posts = loadPosts(status)

  return ASX {
    <Each items={posts} as="post">
      <Card title={post.title}>
        <Copy>{post?.summary}</Copy>
      </Card>
    </Each>
  }
}

Scope namespace imports

Scope files can stay explicit for one function, or import a whole domain namespace when a route grows. Namespace members remain qualified, so the graph is readable and avoids hidden globals.

Code
ax
import { isTheme } from "./domain.ax"

scope Page <isTheme> {
  render Page()
}

import * as Domain from "./domain.ax"

scope Blog <Domain> {
  state filter: String = "published"
  render Domain.BlogPage()
}

Content collections

Configure docs, blog, or CMS-style content in `Axonyx.toml`, then read it from route-local query functions through `Content.Collection`.

Code
ax
[content.collections.docs]
path = "content/docs"
extensions = ["md", "mdx"]

query DocsList()
  data docs = Content.Collection("docs")
    order slug asc
  return docs

page DocsHome() {
  data docs = DocsList()

  return ASX {
    <Each items={docs} as="doc">
      <Card title={doc.title}>
        <Copy>{doc.excerpt}</Copy>
      </Card>
    </Each>
  }
}

Schema pull

`cargo ax schema pull` is the first fast-Swagger style command: it can turn JSON or a typed envelope into `.ax` type declarations.

Code
ax
cargo ax schema pull ./sample-posts.json --name Post