Flagship
The web framework with two modes.
Static routes ship zero JavaScript.
App routes ship the full interactive experience.
Same project. Same router. You choose.
Two modes, one router
export const config = { mode: "static" };
export default function About() {
return (
<main>
<h1>About Us</h1>
<p>We build tools for developers.</p>
</main>
);
}export const config = { mode: "app" };
export async function loader({ context }: LoaderArgs) {
return {
projects: await context.db.getProjects(),
};
}
export default function Dashboard() {
const { projects } = useLoaderData<typeof loader>();
return (
<main>
<h1>Dashboard</h1>
<ul>
{projects.map(p => (
<li key={p.id}>{p.name}</li>
))}
</ul>
</main>
);
}What you get
The complete picture
One file. Loader fetches data. Action handles the form. Component renders it. Error boundary catches failures. TypeScript connects everything.
import type { LoaderArgs, ActionArgs } from "@neutron-build/core";
export const config = { mode: "app" };
export async function loader({ params, context }: LoaderArgs) {
const project = await context.db.getProject(params.id);
if (!project) throw new Response("Not found", { status: 404 });
return { project };
}
export async function action({ request, params, context }: ActionArgs) {
const form = await request.formData();
await context.db.updateProject(params.id, {
name: form.get("name") as string,
});
return { saved: true };
}
export default function ProjectPage() {
const { project } = useLoaderData<typeof loader>();
const action = useActionData<typeof action>();
return (
<div>
<h1>{project.name}</h1>
{action?.saved && <p>Saved.</p>}
<Form method="post">
<input name="name" defaultValue={project.name} />
<button type="submit">Save</button>
</Form>
</div>
);
}
export function ErrorBoundary() {
const error = useRouteError();
if (isRouteErrorResponse(error)) {
return <p>{error.status}: Not found.</p>;
}
return <p>Something went wrong.</p>;
}Layouts that persist
Navigate from /app/dashboard to /app/settings. The root layout stays. The app layout stays. Only the page swaps. No re-render. No flash. No lost state.
src/routes/
_layout.tsx ← stays mounted
app/
_layout.tsx ← stays mounted
dashboard.tsx ← unmounts
settings.tsx ← mounts
projects/
_layout.tsx ← stays mounted between projects
[id].tsxInteractive islands in a sea of HTML
Static routes ship zero JavaScript. When you need interactivity, wrap a component in <Island>. Only that component hydrates. Everything else stays as HTML.
import { Island } from "@neutron-build/core";
import Counter from "../components/Counter";
export default function Home() {
return (
<main>
<h1>Welcome</h1>
<p>This is HTML. No JavaScript.</p>
<Island component={Counter} client="visible" start={0} />
<footer>Also HTML. Also no JavaScript.</footer>
</main>
);
}client="load"Hydrate immediately.client="visible"Hydrate when scrolled into view.client="idle"Hydrate when the browser is idle.client="media"Hydrate when a media query matches.How Neutron compares
| Neutron | Next.js | Remix | Astro | SvelteKit | Nuxt | SolidStart | |
|---|---|---|---|---|---|---|---|
| Static routes | Zero JS | Requires React | Requires React | Zero JS | Svelte runtime | Requires Vue | Solid runtime |
| App routes | Preact or React | Requires React | Requires React | Limited | Svelte | Vue | Solid |
| Client runtime | 3 KB (Preact) | ~42 KB | ~42 KB | 0 KB | ~2 KB | ~30 KB | ~8 KB |
| Data loading | Parallel loaders | Parallel (App Router) | Parallel loaders | Astro.glob | load() | useFetch | createResource |
| Data layer | DB + Cache + Queue | DIY | DIY | DIY | DIY | DIY | DIY |
| Mutations | Actions + Form | Server Actions | Actions + Form | Limited | Form actions | Server routes | Actions |
| Nested layouts | Yes | Yes (App Router) | Yes | Yes | Yes | Yes | Yes |
| Islands | Yes | No | No | Yes | No | No | No |
| Rendering modes | 2 (explicit) | 5+ (implicit) | SSR + pre-render | SSG + SSR + hybrid | SSR + SSG + hybrid | SSR + SSG + hybrid | SSR + SSG |
| Deploy targets | Any (adapters) | Vercel-biased | Any | Any (adapters) | Any (adapters) | Any (presets) | Any (adapters) |
Neutron takes inspiration from the best ideas across these frameworks. Every framework makes trade-offs — Neutron makes different ones.
Server Performance
Benchmarks across 8 scenarios. Production builds. Same hardware. autocannon with 80 concurrent connections.
Framework Comparison
Average performance across 8 benchmark scenarios. Production builds, same hardware.
| Framework | Avg RPS | Avg Latency | vs Neutron |
|---|---|---|---|
| Neutron (Preact) | 3,498 | ~8ms | Baseline |
| Neutron (React Compat) | 2,872 | ~10ms | -18% |
| Next.js 15 | 830 | ~14ms | -76% |
| Astro 5 | 634 | ~16ms | -82% |
| Remix 2 | 471 | ~20ms | -87% |
| Remix 3 (RR7) | 277 | ~28ms | -92% |
autocannon, 80 concurrent connections, 5s duration, production builds. Full methodology.
Why Neutron is Faster
The performance gap comes from architecture, not tricks:
Static routes skip the render pipeline. No React, no virtual DOM, no component tree. A static route is string concatenation. This is why static pages hit 8,262 RPS while Next.js hits 2,756.
App routes use Preact instead of React. Preact's server render is lighter — 3 KB vs ~42 KB. That means faster SSR and smaller bundles. Your database will still be the bottleneck, but you'll have more headroom.
What This Means in Practice
A ~4x throughput advantage means you can serve the same traffic with fewer servers. For most applications, the database is the real bottleneck — but when you do need to scale horizontally, that headroom matters.
All benchmarks are production builds tested with autocannon (80 concurrent connections, 5s duration). Full methodology and raw data available in the benchmark blog post. We encourage you to run the benchmarks on your own hardware.
Client Bundle Sizes
| Metric | Neutron | Next.js | Remix | Astro | SvelteKit | Nuxt | SolidStart |
|---|---|---|---|---|---|---|---|
| Static page JS | 0 KB | ~85 KB | ~40 KB | 0 KB | ~22 KB | ~55 KB | ~18 KB |
| App page JS | ~3 KB | ~90 KB | ~45 KB | N/A | ~24 KB | ~60 KB | ~22 KB |
| Client runtime | ~3 KB (Preact) | ~42 KB (React) | ~42 KB (React) | 0 KB | ~2 KB | ~30 KB (Vue) | ~8 KB (Solid) |
| Islands | Yes | No | No | Yes | No | No | No |
| Server runtime | Bun or Node.js | Node.js | Node.js | Node.js | Node.js | Node.js / Nitro | Node.js |
Bundle sizes are approximate and based on default configurations. Neutron ships Preact (~3 KB gzipped) by default. React-compat mode available for full React ecosystem compatibility.
The full stack
Neutron is growing into an ecosystem. Four products, one set of patterns.
The flagship framework. File-based routing, loaders, actions, islands, and two rendering modes.
Systems-level performance. 1,161 tests, trie router, middleware, JWT, WebSocket, SSE.
ML tensor library. 110+ test suites, SIMD kernels, quantized inference, autograd.
14-in-1 database. 3,724 tests, PostgreSQL compatible, MVCC, columnar OLAP.