The compiler knows
what's reactive.
Every reactive framework asks you to remember which reads are tracked and what you may not destructure. Fluixi's compiler resolves that itself — by where a value came from, not by how it's named — and carries it through JSX, templates, the DOM it generates, SSR, hydration and routing as one model. You write ordinary TypeScript.
npm create fluixi@latestfunction Counter() {
const count = $signal(0); // no import — the compiler resolves it
return (
<button onClick={() => count.set(c => c + 1)}>
{count()}
</button>
);
}Both syntaxes compile to the same calls. Switch to Compiled to see them.
Ordinary TypeScript, still reactive.
The compiler resolves a reactive value by the binding it came from, never by how the name reads — so an alias is recognised and a local function of the same name is not. Knowing that, it can rewrite what a runtime alone would lose.
- Destructure props and the bindings stay live reads
- What it can't prove safe is left as written, and reported
- JSX and
html``compile to one reactive model
function Card({ title, ...rest }) {
return <h2 {...rest}>{title}</h2>; // title still updates
}
import { signal as state } from '@fluixi/reactive/signal';
const count = state(0); // a signal — resolved through the import
function signal() { return 42; }
const value = signal(); // not a signal — a local functionEverything a modern app needs
One framework, from the signal graph to the edge.
Fine-grained reactivity
A TC39-Signals graph updates exactly the DOM that changed — no virtual DOM, no diffing, no re-renders.
Compiled, not interpreted
JSX compiles straight to imperative DOM calls. You ship the work, not a runtime that re-discovers it.
SSR + streaming
Request-scoped server rendering with web-stream output and seamless hydration — isolated per request.
Static generation
Set `prerender` and `fluixi build` crawls your routes to static HTML — this very page is SSG.
File-based routing
Routes from the filesystem, nested layouts, lazy loading, data loaders — with a framework-agnostic core.
Server functions & actions
`"use server"` turns a function into a typed RPC; forms get progressive-enhancement actions.
API routes & middleware
Drop a handler in `src/api/**` for `/api/*`; a middleware chain runs before every render.
DI, i18n, interceptors
Angular-style dependency injection, built-in typed i18n, and an HTTP interceptor pipeline.
Islands & edge
Partial hydration for mostly-static pages, and an edge-safe server that runs on Workers, Deno and Bun.
Start in seconds — JSX or html``.
One command scaffolds an SPA or an SSR app, in JSX or JSX-free html`` templates. Both compile to the same fine-grained DOM calls, so you can even mix them in one file.
--jsxor--html·--spaor--ssr- html`` needs no
jsxin tsconfig — plain.tsfiles - Editor support via
@fluixi/ts-plugin, wired in for you
npm create fluixi@latest my-app -- --html --ssrimport { html } from "@fluixi/core";
// No JSX, no tsconfig changes — plain .ts, same compiled output.
function Counter() {
const count = signal(0);
return html`
<button @click=${() => setCount(c => c + 1)}>
count: ${count()}
</button>
`;
}The server is just a function away.
Mark a function "use server" and the compiler strips its body from the browser, leaving a typed RPC stub. Secrets, database calls and your API keys never ship to the client.
- Request-scoped context, cookies and headers
- Form actions with progressive enhancement
- File-based API routes at
/api/*
// runs only on the server — the body is stripped from the client bundle
async function getUser(id: string) {
"use server";
return db.users.find(id); // secrets stay server-side
}
// call it from anywhere like a normal async function:
const user = await getUser("42");See your reactivity.
The Fluixi Playground compiles JSX in your browser and renders the live dependency graph — watch state, memos, stores and effects light up as they propagate.
Try the Playground →