Skip to main content

Compare

How BaseNative compares

BaseNative is a small runtime for the web platform itself: valid HTML templates that stay data instead of becoming code, no build step, no dependencies, nothing to eval — so a page can be generated, stored in a CMS or database, and served under a strict CSP. An honest look alongside React, Angular, and Svelte: where it wins, where it doesn't, and why that matters.

Bundle size

BaseNative ships raw ES modules. No bundler, no tree-shaking needed — what you import is what runs. The runtime is one package you can read end to end.

Runtime weight and dependencies

Measure BaseNative React 19 Angular 22 Svelte 5
Runtime size (min+gz) 9.9 KB ~67.5 KB ~65.7 KB ~9.9 KB
Core production deps 0 2 (react, react-dom) 8 (@angular/* ×6, rxjs, tslib) 0
Build step None Required (JSX) Required (TS + AOT) Required (compiler)
Runtime source you can read 2,775 lines ~20K lines ~51K lines ~16K lines

BaseNative's runtime is measured by scripts/bundle-size.js — the same gzipped build CI holds to a 10 KB budget — so this row is the number the package actually ships, not a target. Competitor figures are what a minimal hello-world app ships through each framework's own production pipeline, min+gzip, measured 2026-10-20 against React 19.3.1 · Angular 22.2.3 · Svelte 5.57.2. Svelte has no fixed runtime — its compiler ships only what the app uses — and at hello-world scale that lands level with BaseNative's whole runtime; the tradeoff is the compiler it needs to get there, and a figure that grows with the app.

"Zero dependencies" is a claim about @basenative/runtime, and only about it. Across all published @basenative/* packages there are 7 third-party production dependencies in 5 packages — server parses HTML, og-image rasterises cards, wrangler-preset wraps Wrangler, and eslint-config extends ESLint. Install only the runtime and you install nothing else; the rest of the toolkit is not dependency-free.

Templates are data

BaseNative expressions are interpreted by a hand-written parser — a tokenizer, a recursive-descent grammar, a scope object. There is no eval and no Function constructor anywhere in the shipped runtime or server; the count is taken from source on every build, and it is 0. A BaseNative page runs under script-src 'self' with no 'unsafe-eval' — and unlike the compiled frameworks, that does not depend on a build having happened first.

Because a template is never compiled into code, a template is data. It can live in a CMS, come out of a database, or be written by a model, and rendering it cannot turn it into an injection: the parser interprets a deliberate subset — property access, calls into the provided scope, operators, ternaries — and blocklists prototype access. React, Angular and Svelte are safe the opposite way: their templates become code at build time, which is exactly why a template has to go through the build before it can run at all.

What that posture costs and buys

Measure BaseNative React 19 Angular 22 Svelte 5
eval / Function constructor in shipped code 0 0 — after its compiler runs 0 — after AOT compilation 0 — after its compiler runs
Template stays data at runtime Yes — parsed, never compiled to code No — JSX compiles to JavaScript No — templates compile at build time No — .svelte compiles to JavaScript
A stored template (CMS, database, model output) renders as-is Yes — interpreted against a scope, prototype access blocklisted No — it must go through the build first No — it must go through the build first No — it must go through the build first

The narrow, measured version of that claim: an LLM wrote the same two apps twice, in BaseNative 2.1.0 and in React 19.3.1 — a server-rendered catalog and an interactive counter-and-list page, sharing one dataset, with identical behavior tests on both sides and every fix logged. With no build pipeline in the way, the BaseNative side needed no tooling fixes at all. Both implementations passed every test. What differed was the path, and the code-size hypothesis failed in public:

An LLM wrote the same two apps in both

Measure BaseNative React
Build and tooling fixes before tests passed 0 4
App-code fixes 1 0
Production dependencies (interactive task) 1 3
Hand-written lines (both tasks) 95 114
Approx. code tokens (both tasks) 827 795

The code-size hypothesis failed: fewer lines, slightly more tokens, because HTML templates carry closing tags. The 2,590-token llms.txt that teaches a model the BaseNative API has no break-even through code savings at this task size; what it buys is avoided errors. The run's only app-code bug was BaseNative's — an effect subscribed to both a signal and a computed derived from it fired twice per change. The runtime now settles that pattern in one run. The historical count of one app-code fix stands. The updated scorecard is on /ai.

First run in October 2026, against BaseNative 0.6.4. Re-verified 2026-10-20 against the published 2.1.0 packages, with React still at 19.3.1 — no measured value changed.

Full method, results and the fix-by-fix log: the benchmark write-up.

API surface

Fewer primitives means less to learn and less to break. BaseNative's entire reactivity model fits on a whiteboard.

Concepts and model

Measure BaseNative React 19 Angular 22 Svelte 5
Core concepts to learn 6 15+ hooks 30+ concepts ~8 runes
Reactivity model Signals (push) Virtual DOM (pull) Signals (push) Runes/compiler (push)
Template syntax Valid HTML JSX (not HTML) Extended HTML Custom (.svelte)
TypeScript Optional Optional Required Optional

The 6 primitives are signal(), computed(), effect(), batch(), hydrate(), render() — counted from the modules that export them.

Counter: the same app, four ways

A reactive counter shows each framework's mental model. BaseNative uses plain HTML with signal expressions — no compilation, no special file format.

index.html
<div :data="{ count: 0 }">
  <p>Count: {{ count }}</p>
  <button @click="count++">+1</button>
</div>
<script type="module">
  import { hydrate } from '/basenative.js?v=72245475d1';
  hydrate(document.body, { count: 0 });
</script>

Valid HTML. No build. Drop a script tag and go.

SSR and hydration

BaseNative includes server rendering and 4 built-in lazy hydration strategies out of the box. Most frameworks require extra packages or custom implementations for selective hydration. Server and client interpret the same expressions through the same shared parser, so the markup the server renders is the markup the client hydrates — there is no second template dialect to drift.

Rendering and hydration

Measure BaseNative React 19 Angular 22 Svelte 5
SSR built-in Yes Via Next.js / manual Yes (built-in SSR) Via SvelteKit
Lazy hydration 4 strategies built-in Manual / React.lazy @defer (partial) Manual
Hydration strategies idle, interaction, media, viewport N/A @defer on viewport N/A
CSP-safe expressions Yes (no eval/Function) Yes (JSX compiled) Yes (AOT compiled) Yes (compiled)

Developer experience

The place BaseNative is furthest behind. None of this is close, and pretending otherwise would waste your afternoon.

Day-to-day workflow

Measure BaseNative React 19 Angular 22 Svelte 5
Time to first render Open HTML file npm create vite@latest ng new + ng serve npx sv create
Hot reload HMR (@basenative/hmr) Fast Refresh HMR HMR
Ecosystem packages Growing Massive Large Moderate
Component model Semantic HTML — W3C primitives are the component model Components + hooks Components + DI Components
Community size Solo project Millions Millions Hundreds of thousands

Honest tradeoffs

BaseNative isn't trying to replace React or Angular for every use case. Here's where it genuinely excels and where you should think twice.

Where BaseNative wins

  • Zero build, zero core deps — ship an HTML file
  • The reactivity core is 150 lines; the whole runtime is 2,775
  • 4 built-in lazy hydration strategies
  • CSP-safe without compilation
  • Valid HTML templates that work without JS
  • 6.8× smaller than React, 6.6× smaller than Angular
  • No lock-in: the component model is semantic HTML itself — walk away and your markup is still just HTML

Where others win

  • The component model is the platform itself — semantic HTML composed as native DOM, with no framework component layer (or component library ecosystem) on top
  • Ecosystem of one — no third-party component libs
  • Runtime expression parsing has overhead vs compiled output
  • Svelte has the better-polished DX and the mature compiler toolchain
  • No React DevTools, no Angular CLI, no Svelte inspector
  • Solo-maintained — bus factor of one
  • Almost nobody has heard of it — hiring and onboarding start from zero

When to choose BaseNative

Good fit

  • Content sites that need light interactivity
  • Projects where you want to own every line
  • Edge-deployed apps on Cloudflare Workers
  • Teams tired of build tool churn
  • Prototypes that need to ship in minutes
  • Embedded widgets in existing pages

Probably not

  • Large team apps that need enforced architecture
  • Projects requiring deep third-party integrations
  • Apps where a mature devtools inspector is critical workflow
  • Enterprise apps with strict hiring pool requirements
  • Complex SPAs with hundreds of components

Try it

The reactivity core is 150 lines. Read it, understand it, then decide.