A full-stack Rust application framework — reactive Rust/WASM UI, type-safe server functions, a local-first data layer, auth, storage, background jobs, and one-command deploy. One language, end to end.
pocopine is a full-stack application framework written in Rust. The
front end is a directive-driven Rust/WASM UI layer: a Vue-3-style
reactive core (real Proxy traps, auto dep-tracking) wired into
compiled .poco template plans, with tag-based components and a
built-in SPA router. The back end is reached through a type-safe
server-function bridge — write an async fn, call it from the client
as a typed stub. Around that core sits a set of opt-in crates for the
rest of an application: a query-centric data layer, auth, object
storage, live updates, background jobs, observability, and deploy
adapters.
Templates live in plain HTML files (.poco), styles in plain CSS
files, logic in plain Rust files. No mixed-language SFCs, no virtual
DOM, and no JavaScript toolchain unless you opt into Pocopine-managed
typed .client.ts modules. One canonical way per decision — the
framework is opinionated so application code stays small.
Status: pre-1.0 / experimental. The API is still moving; every breaking change lands in an RFC under
rfcs/.
// examples/counter/src/lib.rs
use pocopine::prelude::*;
use serde::{Deserialize, Serialize};
#[derive(Default, Serialize, Deserialize)]
#[component]
pub struct Counter { pub count: i32, pub label: String }
#[handlers]
impl Counter {
pub fn increment(&mut self) { self.count += 1; }
pub fn decrement(&mut self) { self.count -= 1; }
}
#[wasm_bindgen(start)]
pub fn main() { App::new().register::<Counter>().run(); }<!-- examples/counter/src/Counter.poco -->
<div>
<p><strong pp-text="count"></strong> <span pp-text="label"></span></p>
<button pp-on:click="decrement">-</button>
<button pp-on:click="increment">+</button>
</div><!-- examples/counter/index.html -->
<body>
<counter label="clicks"></counter>
<script type="module">
import init from "/pkg/counter.js";
init();
</script>
</body>That's the whole counter. No virtual DOM, no build step beyond
pocopine dev, no Rc<RefCell<_>> in the author's code.
The pocopine CLI handles building, serving, and hot-reload — one
install covers all three.
cargo install pocopine-cliFrom a source checkout, use the repo helper:
./install.sh
pocopine doctor --path .A pocopine app is a regular Rust library crate. Add pocopine
(runtime) and, optionally, pine (UI primitives).
cargo new --lib hello-pine
cd hello-pine
cargo add pocopine pineA component is a Rust struct plus a sibling .poco template.
// src/lib.rs
use pocopine::prelude::*;
#[derive(Default, Serialize, Deserialize)]
#[component(template = "Counter.poco")]
pub struct Counter { pub n: u32 }
#[handlers]
impl Counter {
pub fn bump(&mut self) { self.n += 1; }
}
#[wasm_bindgen(start)]
pub fn main() {
App::new().register::<Counter>().run();
}<!-- src/Counter.poco -->
<button @click="bump">
clicked <strong pp-text="n"></strong> times
</button>pocopine dev builds the wasm bundle, serves it on a local port, and
rebuilds on save.
pocopine dev
# → listening on http://127.0.0.1:5243Ship with pocopine build --release, then pocopine deploy.
pocopine is a Cargo workspace. Apps depend on the pocopine façade
crate (runtime + prelude) and add only the modules they need. Each
module is documented under docs/.
| Crate | What it does |
|---|---|
pocopine |
The façade crate apps depend on: runtime re-exports + prelude. |
pocopine-core |
Reactive runtime — signals, effects, component scopes, directives, router. A Rust/WASM port of Alpine.js. |
pocopine-macros |
#[component], #[handlers], #[store], #[server]. |
pocopine-template-parser |
Host-only .poco parser (html5ever); shared by the macros and Stylekit. Never linked into wasm. |
pocopine-expr |
Pure-Rust template-expression grammar (RFC 012), shared by the runtime evaluator and compile-time validation. |
pocopine-stylekit |
Pine Stylekit — a Pocopine-native, Tailwind-shaped utility-CSS compiler. Build-time only, no browser runtime. |
| Crate | What it does |
|---|---|
pine |
Unstyled, accessible UI primitives (Button, Dialog, Popover, …) ready to style. |
pine-icons |
Tabler Icons as a tree-shaken Pine component. |
pine-charts |
SVG-first chart primitives. |
pine-motion |
Motion.dev-style animation — springs, gestures, drag, scroll, shared-layout (FLIP). |
pine-richtext |
Rust-native rich-text document model + editor state, with an optional browser view. |
| Crate | What it does |
|---|---|
pocopine-server |
Host-side helpers for #[server] functions: axum integration + static-file serving. |
pocopine-client-codegen |
Discovery + typed-facade generation for managed .client.ts modules. |
pocopine-ts-rs |
Rust → TypeScript DTO generation (a Pocopine-owned fork of ts-rs). |
| Crate | What it does |
|---|---|
pocopine-sync-query |
Query-centric, local-first data layer: filtered subscriptions, predicate-routed mutations, reactive selectors, typed writes. |
pocopine-sync |
Sync protocol + server plugin the query layer rides on. |
pocopine-sync-sqlite / -indexdb
|
Local-store backends (server/native and browser). |
pocopine-storage |
Object-storage protocol + server-mediated uploads, with -s3, -gcs, and -azure backends. |
| Crate | What it does |
|---|---|
pocopine-auth |
Auth contracts + server-function guards. |
pocopine-auth-credentials |
First-party email + password (argon2id, signup/login/logout as a ServerPlugin). |
pocopine-auth-jwt |
JWT verification for Firebase, Clerk, Auth0, Supabase, custom OIDC, and pocopine-issued tokens. |
pocopine-auth-client |
Wasm-side bearer-token bridge + fetch middleware. |
| Crate | What it does |
|---|---|
pocopine-live |
Browser live-invalidation streams (SSE) for collection/query refresh. |
pocopine-events |
Event envelopes, cursors, and backends for live features. |
pocopine-jobs |
Background jobs — Redis Streams + scheduler, periodic firings, reclaim, in-memory backend. |
| Crate | What it does |
|---|---|
pocopine-observe |
Shared observability event contract for logging, tracing, and analytics. |
pocopine-logging |
Logging adapters for server and browser. |
pocopine-analytics |
Analytics + telemetry adapters. |
| Crate | What it does |
|---|---|
pocopine-cli |
pocopine build | run | dev | deploy. |
pocopine-deploy |
Deploy contract + adapters (RFC 080), with -railway and -render. Host-API-direct; no host CLIs. |
pocopine-launcher |
Procfile-style entrypoint for the production OCI image. |
| Crate | What it does |
|---|---|
pocopine-crypto |
Centralized hashing + checksum primitives (sha2, hmac, crc32c). |
pocopine-codec |
Shared encoding (base64, percent-encoding, serde adapters). |
Full guides and tutorials live under docs/. Start here:
Concepts & guides
- Components — structure, state, and composition. Read first.
-
Reactivity — effects, dep tracking, signals, and the
Proxybridge. -
.pocotemplates — the template format, compilation, scoped styles, and expressions. -
Pine Stylekit — the utility-CSS compiler and
@themetokens. - Animation — presets, FLIP, and the WAAPI escape hatch.
- Routing — route guards, async loaders, and fetch middleware.
- App plugins / Server plugins — install-time setup and lifecycle ordering.
- Sync (client) / Sync (server) — the query data layer, end to end.
- Object-storage uploads — the server-mediated upload path.
- Logging, tracing & observers — structured events, sinks, and privacy labels.
- Charts · Icons · Client modules · Browser storage
Tutorials (build something end to end)
-
Sync: a workspace issue tracker —
#[query_resource], aSourceimpl, reactive views, typed writes. - Live invalidation — SSE streams + collection/query refresh callbacks.
-
Email + password auth — implement
UserStore/TokenStore(Postgres +sqlx), plug inCredentials. - Phone OTP auth — Twilio + Postgres on top of the credentials primitives.
- Firebase Auth — client modules + server-side token verification.
- Background jobs — the job runtime, scheduling, and a live-deployment validation recipe.
Drop into any one with pocopine dev --path examples/<name>:
| Example | What it shows |
|---|---|
counter |
Single component, basic directives |
todo |
Multi-component, slots, stores |
blog |
App + #[server] + axum server bin |
spa |
Router + <pp-outlet> + pp-route
|
hn |
Full SPA — routing, server fns, transitions, pp-for
|
sync |
Query data layer + pocopine-live wake-ups |
live |
SSE live invalidation + collection/query refresh |
charts |
pine-charts primitives |
richtext |
pine-richtext editor |
file-browser |
Storage browser shell for S3/MinIO |
website |
Pine UI — every primitive, side-by-side |
site |
The marketing page, dogfooded |
tailwind |
Tailwind v4 + .poco scanning (fallback styling) |
Three layers you can reach for independently, with the application modules layered on top:
- Runtime — reactive engine, component scopes, directives, and the adopted-DOM bridge for dynamic HTML. No virtual DOM; mutations happen in place against real DOM nodes.
-
Templates —
.pocofiles are pure HTML withpp-*directives. The#[component]macro wires them to Rust structs, emits static template metadata, and specializes eligible binding/listener installs at compile time. -
Server functions —
#[server] async fnon the backend; the client gets a typed stub that POSTs to/_pocopine/<fn_name>and deserializes the response. Works with any serde-compatible type.
On top of those sit the opt-in application modules — data/sync, auth,
storage, live, jobs, observability — most of which install as app
plugins (browser) or server plugins (host) through a single
lifecycle boundary. See docs/guides/plugins/app-plugins.md.
Authoritative design decisions live in rfcs/; narrative
design notes live in docs/.
pp-text, pp-html, pp-bind:<attr>, pp-on:<event>, pp-show,
pp-model, pp-init, pp-for, pp-if, pp-cloak, pp-transition:*,
pp-teleport, pp-ref, pp-route. Component templates and lifted
pp-if / pp-for / pp-teleport bodies install through
macro-generated closures rather than a generic runtime applier.
The js-framework-benchmark keyed-table action plan, run locally under
headless Firefox against pinned Rust/WASM and JS competitors. Numbers
are wall-clock geometric means (lower is better); vanilla is the
control because browser timing drifts between runs.
| framework | geomean (ms) | vs vanilla |
|---|---|---|
| vanilla JS | 185.41 | 1.00× |
| Vue 3 | 202.17 | 1.09× |
| pocopine | 215.92 | 1.16× |
| Yew | 225.07 | 1.21× |
| Leptos | 281.45 | 1.52× |
No virtual-DOM diff runs in the hot path; generated template code and
fine-grained Proxy reactivity mutate real DOM nodes in place.
Reproduce locally with the harness under jsbench/:
./jsbench/benchmark.sh pocopine --browser firefox --no-build
./jsbench/benchmark.sh --all --browser firefoxPine Stylekit is the default way to style pocopine apps — a native
utility-CSS compiler with Tailwind-shaped classes, compiled in-process
at build time (no external watcher, no Node). It runs by default: write
utility classes in .poco templates, declare colours in an @theme
block, link /pkg/stylekit.css, and pocopine build/dev does the
rest. It parses .poco with the real compiler (not text scanning) and
fails loud on typos with source spans. See
docs/guides/styling/stylekit.md.
<link rel="stylesheet" href="/pkg/stylekit.css" />Prefer Tailwind? It stays a first-class fallback — add a
[package.metadata.pocopine.tailwind] block (with no [stylekit]
block) and Stylekit defers to it; the CLI downloads the standalone
binary and runs it alongside the build. DaisyUI works as a plugin. See
docs/guides/styling/stylekit.md for both paths.
# cross-target checks (apps build for wasm32)
cargo check --workspace --target wasm32-unknown-unknown
cargo clippy --workspace --all-targets -- -D warnings
# core unit tests
cargo test -p pocopine-core --libPRs welcome — non-trivial features should open an RFC first (or be
paired with one in the same PR). See rfcs/README.md
for the convention.
- Alpine.js — the directive model and author ergonomics.
-
Vue 3 — the
Proxy-based reactive core. -
Headless UI — the
<Transition>API thatpp-transition:*mirrors. - Solid / Leptos — fine-grained reactivity references.
Dual-licensed under either of
-
Apache License, Version 2.0 (
LICENSE-APACHE) -
MIT License (
LICENSE-MIT)
at your option.
