Axonyx is a Rust-first web framework and language layer for building low-JavaScript sites, docs, and future CMS-style applications with .ax files, Cargo-native tooling, and Foundry UI.
Status: public beta loop.
Axonyx can already scaffold apps, render .ax pages, build static output, serve route-aware local previews, import Foundry UI from axonyx-ui, and publish deployable sites. It is not yet a full replacement for React, Next.js, or mature CMS platforms. The next runtime work is tracked in the GitHub issues and Wiki.
Current builds emit framework inspection artifacts under dist/_ax, including
the Melt graph, content manifests, and state manifests when .ax files declare
state signals.
- JSX-like
.asxauthoring inapp/**/page.asxandapp/**/layout.asx - nested app routes
- dynamic route params and query context
- route boundaries through
app/not-found.asxandapp/error.asx - route-local
loader.axandactions.axdraft support - first action patch response contract through
application/ax-patch+json - backend-oriented
.axfiles for loaders, actions, routes, and jobs - static builds through
cargo ax build - route-aware dev/start server through
cargo ax run devandcargo ax run start - strict project diagnostics through
cargo ax doctor --deny-warnings - early typed data checks for
type Post,List<Post>, and<Each>field access - first state bridge contracts through stable
SignalId,data-ax-signal, and typed patch events - first Melt state manifest for
.axstatedeclarations - reusable Foundry UI imports through
@axonyx/ui/... - generated apps consuming published crates from crates.io
This repository contains the public CLI packages:
create-axonyx- project scaffolding CLI, similar in spirit tocreate-next-appcargo-axonyx- Cargo helper CLI exposed ascargo ax ...
Generated apps consume the runtime and UI packages through crates.io by default:
[dependencies]
axonyx-runtime = "0.1.14"
axonyx-ui = "0.0.48"Install the public CLI tools:
cargo install create-axonyx
cargo install cargo-axonyxCreate and run a site:
create-axonyx my-site --yes --template site
cd my-site
cargo ax run devThe default dev/start server uses the Tokio transport. The older standard library transport remains available as a fallback while the production path matures:
cargo ax run dev --transport stdFor hosted starts, use the normal start command:
cargo ax run start --host 0.0.0.0 --port 3000The legacy --production-server flag still selects Tokio for older deploy
scripts, but it is no longer required. The Tokio path installs a Ctrl+C
shutdown listener and a short connection drain window so hosted starts and
local previews can stop cleanly.
For Render-style deployment checks:
cargo ax doctor --deploy renderThe Render check recommends the same Tokio-backed start command so local smoke
and hosted deploys exercise the same server path. It also reports the
recommended health-check path: /__axonyx/health.
Production preview exposes a stable health probe for hosted platforms and load balancers:
GET /__axonyx/health
Request reads default to a short production-safe timeout and can be tuned per app:
[server]
request_timeout_seconds = 2
shutdown_grace_seconds = 5
max_connections = 1024This is intentionally a runtime choice, not an authoring burden: .ax pages,
loaders, actions, and state patches keep the same shape while Axonyx chooses the
transport layer underneath.
The Tokio server path also exposes the first SSE probe:
cargo ax run dev
# open /__axonyx/eventsThis is the first axonyx-server-net step toward live patch streams, CMS event
feeds, and worker/build notifications.
Check and build:
cargo ax doctor --deny-warnings
cargo ax build --cleanAvailable templates today:
site- the default static product/company siteblog- a Markdown content collection with prerendered article routesdocs- a static documentation shell with Getting Started, Components, Reference, and Examplesminimal- the full-stack playground with loaders, actions, API routes, jobs, and database examples
The three static templates intentionally have different information architectures, route trees, and output contracts. All of them build without a database or application backend and include Aegis route/link checks.
From this repository, contributors can also run the scaffold locally:
cargo run -p create-axonyx -- my-site --yes --template siteRecommended authoring path today:
- JSX-like
.asxfiles inapp/**/page.asxandapp/**/layout.asx - nested app routes with route-local
loader.axandactions.axwhen needed - imports from local app components via
@/components/... - imports from Axonyx UI packages via
@axonyx/ui/...
Example route tree:
app/
layout.asx
page.asx
docs/
page.asx
components/
page.asx
blog/
[slug]/
page.asx
loader.ax
Legacy indentation-first .ax syntax still exists for compatibility and reference work, but new examples and new framework authoring should prefer the JSX-like .asx direction.
Typed data is available in the JSX-like path:
page Blog() {
type Post {
title: String
slug: String
summary?: String
}
data posts: List<Post> = loadPosts()
return ASX {
<Each items={posts} as="post">
<Card title={post.title} />
</Each>
}
}
Route-local query functions can live next to the page:
query loadPosts() -> Post[] {
data posts = db.posts.all()
return posts
}
cargo ax check reports axonyx-type diagnostics when a typed page accesses a missing field such as post.summary.
Use post?.summary when a missing field is intentional and should render as an empty string.
Use summary?: String in the type when the field is part of the schema but optional.
Early UI state authoring is also available in JSX-like .asx:
page Settings() {
state theme = "silver"
state count: Number = 0
return ASX {
<select bind:value={theme}>
<option value="silver">Silver</option>
<option value="bronze">Bronze</option>
<option value="gold">Gold</option>
</select>
<span bind:text={theme}>{theme}</span>
<input bind:value={count} />
}
}
Axonyx lowers this into stable data-ax-signal / data-ax-bind metadata and injects the small state bridge only when a page uses signal bindings. The browser bridge exposes window.__axonyx.state with get, set, subscribe, applyPatch, and snapshot.
The first Melt state manifest lives in axonyx-core::state::build_state_manifest.
It extracts top-level .ax state declarations into stable signal records with
id, key, name, scope, ty, and initial. Framework reports now assign
route-aware scopes such as app:language:1, layout:docs:sidebarOpen:1, and
page:settings:filter:1, while the runtime still keeps legacy root:* signal
keys compatible during the transition.
State declarations can be authored with explicit ownership:
app state language: String = "sr"
layout state sidebarOpen: Bool = false
page state filter: String = ""
Use app state for app-wide concerns like language or theme, layout state for
shared route shell state, and page state for local route state.
Action patch responses resolve short authoring names like patch theme = ...
through the route manifest before sending browser patches, so the client receives
the stable scoped signal key.
Use ActionForm to target route actions without manually wiring Axonyx transport
fields:
<ActionForm name="SetTheme">
<select name="theme">
<option value="silver">Silver</option>
<option value="gold">Gold</option>
</select>
<ActionStatus state="pending">Saving theme...</ActionStatus>
<ActionStatus state="complete">Theme saved.</ActionStatus>
<ActionStatus state="error">Theme could not be saved.</ActionStatus>
<Button type="submit">Apply</Button>
</ActionForm>
It renders a regular form pointed at /__axonyx/action and includes the
internal patch marker automatically. ActionStatus renders a status message that
is shown from the form lifecycle state managed by the small action runtime.
Route actions coerce declared input: fields before execution: string stays
text, bool accepts browser checkbox-style values such as on, and integer
fields such as i64 / u64 must parse successfully or the action fails with a
clear runtime error. Optional action inputs use ?, for example
summary?: string; missing optional fields become Null, while missing required
non-boolean fields fail before the action body runs. Inputs can also define
literal defaults, such as language?: string = "sr" or count: i64 = 0.
From an app root:
cargo ax doctor
cargo ax check
cargo ax migrate asx --dry-run
cargo ax g component ThemeSwitcher
cargo ax g island CommandPalette
cargo ax g page settings/profile
cargo ax contracts
cargo ax schema pull ./sample-posts.json --name Post
cargo ax actions
cargo ax content
cargo ax state
cargo ax build
cargo ax run dev
cargo ax testAxonyx 0.2 uses .asx for pages, layouts, boundaries, and UI components while
keeping .ax for loaders, actions, API routes, domain code, and jobs. Existing
projects can preview and apply the mechanical migration with:
cargo ax migrate asx --dry-run
cargo ax migrate asxcargo ax schema pull accepts sample JSON as a draft, but it can also read a typed
envelope from an endpoint or file. When the source includes schema, Axonyx uses
that contract instead of guessing from null values:
{
"type": "List<Post>",
"schema": {
"Post": {
"title": "String",
"summary": "Optional<String>"
}
},
"data": []
}Use strict doctor mode in CI:
cargo ax doctor --deny-warningscargo ax test is reserved for Aegis, the future Rust-first QA runner for
component, route, and browser checks. In the current beta it is a preview
placeholder only; use cargo ax check, cargo ax doctor --deny-warnings, and
cargo ax build --clean for real validation today.
Use JSON output for editor tooling:
cargo ax doctor --format json
cargo ax routes --format json
cargo ax actions --format json
cargo ax state --format json
cargo ax contracts --format jsoncargo ax contracts is the stable, versioned application contract surface for
tools. Contract V1 combines named .ax types, structured component props,
page data bindings, loader/action signatures, API routes, and scopes without
exposing the full internal Melt graph. Write it explicitly with:
cargo ax contracts --format json --out public/axonyx-contracts.jsonEvery production build also emits the same schema at
dist/_ax/contracts/manifest.json. Missing type annotations remain visible as
unknown/empty metadata unless a direct route-local loader call provides a
declared return contract. For example, data posts = loadPosts() inherits
List<Post> from app/posts/loader.ax when loadPosts returns Post[].
Explicit page types are checked against that loader contract, and mismatches
fail cargo ax check instead of silently changing the public manifest.
When no route-local loader matches, a uniquely named shared query under
app/** can provide the same type contract. Route-local loaders take priority;
ambiguous shared query names fail diagnostics rather than depending on file
system traversal order.
UI package tooling uses the same structured prop shape. With axonyx-ui
installed, cargo ax registry --format json parses each registry component and
adds its props contract (name, ty, required, and default) without
changing the existing cargo ax add copy/install path.
cargo ax build scans backend-oriented .ax sources:
app/**/loader.axapp/**/actions.axroutes/**/*.axjobs/**/*.ax
and regenerates:
src/generated/backend.rs
It also renders static page routes from app/**/page.asx into:
dist/
index.html
docs/index.html
components/index.html
...
Use a clean static output build when preparing deploy artifacts:
cargo ax build --cleanTo choose another output directory:
cargo ax build --out-dir public-build --cleanDynamic page routes are skipped unless they are listed in Axonyx.toml:
[prerender]
routes = [
{ route = "/blog/:slug", params = [{ slug = "hello-axonyx" }, { slug = "foundry-ui" }] },
]That renders:
dist/blog/hello-axonyx/index.html
dist/blog/foundry-ui/index.html
Run the route-aware server:
cargo ax run devFor a production-style process without dev live reload:
cargo ax run start --host 0.0.0.0 --port 3000Inspect the route tree:
cargo ax routesThis lists app/**/page.asx page routes, routes/**/*.ax backend routes, dynamic params, nested layout count, and route-local loader.ax / actions.ax files.
Inspect route-local action contracts:
cargo ax actions
cargo ax actions --format json
cargo ax actions --route /posts
cargo ax actions --name CreatePost
cargo ax actions --name CreatePost --schemaThis reports each app/**/actions.ax action, its route, and declared input:
fields with type, optional marker, and default value. It is the first small DX
step toward Axonyx endpoint/schema discovery without making developers guess
form contracts.
Inspect content collections:
cargo ax content
cargo ax content --format jsonConfigure early Melt-time content indexing in Axonyx.toml:
[content.collections.docs]
path = "content/docs"
extensions = ["md", "mdx"]This indexes matching files into a content manifest today. Later runtime work can use the same manifest for docs, blog, and CMS routing.
During cargo ax build, configured collections are written to:
dist/_ax/content/manifest.json
Route loaders can read configured content collections in preview/build:
query loadDocs() -> Doc[] {
data docs = Content.Collection("docs")
order slug asc
return docs
}
Markdown entries expose path, slug, extension, bytes, body, and simple
frontmatter fields such as title or description.
Add a docs module into an existing app:
cargo ax add docsAdd the Foundry UI package when needed:
cargo ax add uicargo ax add cms and cargo ax add blockbit are reserved for the future
Blockbit CMS module. CMS stays outside framework core; Axonyx core provides the
runtime primitives that Blockbit will build on.
Today, cargo ax add ui and the site / docs templates use the published axonyx-ui Cargo package by default.
Generated apps can target:
- the published crates.io package,
axonyx-runtime = "0.1.14" - a local Cargo
pathdependency into a checked-out runtime workspace - the standalone Git repo at
https://github.com/vladanPro/axonyx-runtime
Use --runtime-source path only when contributing to Axonyx itself from the framework workspace.
Use --runtime-source git when testing an unreleased runtime branch:
cargo run -p create-axonyx -- my-app --yes --runtime-source gitWhen working on this monorepo itself:
git submodule update --init --recursive
cargo testRun the core loop smoke test from the framework repo root:
powershell -ExecutionPolicy Bypass -File scripts/smoke-core-loop.ps1 -Template siteThe smoke test creates a temporary app, uses the local framework and local axonyx-ui when available, then runs:
cargo ax check
cargo ax doctor --deny-warnings
cargo ax build --cleanIt passes only if the app has no strict doctor warnings/errors and dist/index.html is generated.
Axonyx should stay Rust-first and compiler-assisted, not a React clone.
The preferred runtime direction is:
compile .ax
-> static HTML with stable node ids
-> dependency graph
-> small runtime patcherState and binding are separate concepts:
global/state = storage model
hard/soft = binding modelPreferred mental model:
Soft = snapshot
Hard = live handleThe server/runtime can be async internally, but Axonyx authoring should stay structured and declarative. Developers should place work into loader, action, signal, <Await>, and job instead of hand-orchestrating promise timing.
See Structured Async In Axonyx.
The next framework spine is tracked as Axonyx Runtime Core / The Melt.
Primary GitHub issues:
- #8 Epic: Axonyx Runtime Core / The Melt
- #9 axonyx-server-net: migrate server to Hyper/Tokio
- #10 axonyx-std-fs: capability FS and content collections
- #11 axonyx-std-state: SignalId bridge and typed patches
- #12 axonyx-std-auth: sessions, crypto, and policies
- #13 axonyx-std-process: jobs, workers, and child processes
- #14 Framework finishing layer after runtime core
Architecture references:
The structured docs index lives in:
docs/README.md
Recommended reading order:
docs/overview.mddocs/ax-v2-authoring.mddocs/architecture/structured-async.mddocs/templates.mddocs/backend-authoring.mddocs/release-runbook.md
Drafts and lower-level architecture notes should live in docs/, not in the top-level README.
- Main site: https://axonyx.dev
- React adapter site: https://react.axonyx.dev
- Runtime repo: https://github.com/vladanPro/axonyx-runtime
- UI package: https://github.com/vladanPro/axonyx-ui
- React adapter: https://github.com/vladanPro/axonyx-react
- crates.io user: https://crates.io/users/vladanPro
crates/
cargo-axonyx/
create-axonyx/
vendor/
axonyx-runtime/
docs/