Library / SDK
frejs/fre avatar
frejs/fre

Fre: a tiny concurrent UI library with Fiber, reviewed for adoption

:ghost: Tiny Concurrent UI library with Fiber.

3,763 stars348 forksJavaScriptMIT

At a glance

What is it?
Fre is a small JavaScript UI library that implements a Fiber-style keyed reconciler, a time-slicing scheduler and a React-like hooks API. It suits teams that want a VDOM runtime they can read end to end, and it is a poor fit for anyone who needs a large ecosystem or documented migration paths.
Who is it for?
Fre fits teams building small to medium interfaces who want a readable VDOM runtime and are willing to compile JSX with jsxFactory set to h and jsxFragment set to Fragment. It does not fit projects that depend on a broad third-party component ecosystem, or that need a documented migration path from React, because the README does not describe one.
Can I use it commercially?
Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 53 days ago.
What is it written in?
Mainly JavaScript, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 1, 2026, and from our analysis. They are not legal advice.

Editorial analysis

The problem Fre solves: a readable VDOM runtime instead of a framework platform

Most React-like libraries ask you to accept a large dependency tree in exchange for a component model. Fre takes the opposite position. The README describes it as a "Tiny Concurrent UI library with Fiber", and the package ships virtual DOM rendering, a hooks API, Suspense, Fragments, ErrorBoundary and Fre.memo. The pitch is that you get the rendering model without the surrounding platform.

The intended audience is narrow but real. If you are writing a widget, an embedded view, a demo, or an internal tool where bundle size and source readability matter more than ecosystem breadth, a runtime you can read in an afternoon has value. If you are building a product where you expect to pull in a component library, a router, a form layer and a data-fetching layer, Fre gives you none of that and the README does not pretend otherwise.

The interesting part is not the size claim, which the README supports only with a brotli badge pointing at unpkg. It is that the repository ships a test suite and a demo workspace, so the behaviour is at least pinned by tests rather than asserted in prose.

How the Fiber reconciler, keyed diff and time slicing fit together

Fre's architecture follows the React Fiber model closely enough that the vocabulary transfers. The README lists a "Keyed reconcilation algorithm" with a "minimal diff algorithm" that supports keyed updates, pre-process, offscreen rendering and SSR hydration. Concurrent Mode is described as a coroutine scheduler implemented in JavaScript, also called time slicing.

In practice that means renders are interruptible work units rather than one synchronous pass. The scheduler yields between units, which is what makes Suspense and offscreen rendering possible in the same runtime. The trade-off is the same one React accepted: interruptible rendering makes it harder to reason about exactly when a DOM mutation lands, and any code that reads layout during render is more fragile than it would be in a synchronous renderer.

The hooks layer sits on top of that. useState, useEffect, useReducer, useLayout, useCallback, useMemo, useRef and useContext are all documented in the README with examples. useLayout is described as "sync and blocking UI", which is the escape hatch when you need the mutation to happen before paint. Note that useContext is used with a provider written as a plain element, <ThemeContext value="dark">, rather than the .Provider suffix React uses. That is a real API difference and it will bite anyone porting code by find-and-replace.

Installing Fre and rendering a first component

The README gives a single install command and a single usage example. There is no create-fre-app scaffolding tool documented, so you wire up your own bundler.

bash
yarn add fre

The README example imports render and useState from fre, defines a component returning a fragment, and mounts it onto document.body.

js
import { render, useState } from 'fre'

function App() {
  const [count, setCount] = useState(0)
  return <>
      <h1>{count}</h1>
      <button onClick={() => setCount(count + 1)}>+</button>
    </>
}

render(<App/>, document.body)

If your bundler does not already know how to compile JSX against Fre, the README gives a Vite example that injects the factory and fragment imports globally.

js
export default {
  esbuild: {
    jsxFactory: 'h',
    jsxFragment: 'Fragment',
    jsxInject: `import { h, Fragment } from 'fre'`,
    target: 'es2020',
    format: 'esm'
  }
}

What you should see after this: a heading reading 0 and a button that increments it. The package also exposes ./jsx-runtime and ./jsx-dev-runtime export entries with matching .d.ts files, so automatic JSX runtimes are supported, but the README documents the classic factory route and does not explain when to prefer one over the other. The repository also contains a demo workspace with its own package.json and vite.config.js, and a tui directory with a demo.js that runs via node tui/demo.js.

Where Fre breaks down: documentation depth and the missing migration story

The README is a feature tour, not a manual. It shows useState, useReducer, useEffect, useLayout, useMemo, useCallback, useRef and useContext with short snippets, and it links to Suspense, memo and ErrorBoundary anchors that resolve to example blocks rather than explanatory prose. Several behaviours that matter in production are simply not covered.

There is no documented migration path from React. Nothing in the README describes how to move an existing component tree across, which is a problem given that the provider syntax for context differs and that hooks rules are described only loosely. The README says useMemo "has the same rules as useEffect", which is a statement about the dependency array, not about memoisation semantics, and a reader could easily take it the wrong way.

Error handling is another thin spot. ErrorBoundary appears as a component with a fallback prop in one example. The README does not say what it catches, whether it resets, or how it interacts with the scheduler. If your application depends on recovering from render errors, that gap is the thing to probe before committing.

Finally, the package.json lists fre itself as a dependency at ^2.8.9, which is a self-reference worth noticing if you are auditing the dependency tree.

Fre compared with Preact: same size argument, different priorities

Preact is the obvious comparison and the difference is not size, it is what each project spends its complexity budget on. Preact prioritises React compatibility and ships a separate compatibility layer so that React code and React ecosystem packages can run with minimal changes. Fre prioritises a small, readable core with its own concurrent scheduler and its own diff algorithm, and it does not advertise a React compatibility layer in the README.

That means the choice is about which kind of risk you prefer. With Preact you inherit a compatibility surface you did not write and cannot fully audit, but you keep access to a large body of existing components. With Fre you get a codebase small enough to read, and you accept that you are writing your own router, your own form handling and your own everything else.

There is a second difference in the rendering model. Fre's time slicing is a first-class part of the pitch, tied to Suspense and offscreen rendering. Preact's core rendering is synchronous, with concurrency available through separate mechanisms. If interruptible rendering is the reason you are looking at Fre, that is the actual differentiator, not the byte count.

Maintenance, release cadence and what the MIT licence leaves you

The repository is not archived and the last push was on 2026-08-09. Releases are infrequent rather than regular: 2.8.5 on 2025-09-08, 2.8.8 on 2025-09-17, and 2.8.9 on 2026-06-08. That is a nine-month gap between the last two releases, which tells you something about the pace you should expect for fixes. If you adopt Fre, plan to vendor or patch it yourself rather than wait on a patch release for a blocking bug.

Upgrade cost is low by construction. The public surface is a handful of named exports plus two JSX runtime entry points, and the package is ESM-first with a UMD fallback through the require condition. There are no documented breaking-change notes in the README, so you should read the diff between tags before bumping, particularly around the reconciler, where changes are hard to detect through tests alone.

Fre is MIT licensed, which permits commercial use, modification and redistribution provided the copyright notice and permission notice are retained. That is the extent of what the licence file supports saying here; whether a particular distribution arrangement satisfies it is a question for your own counsel, and the README adds nothing beyond the MIT identifier and the author attribution.

Editorial conclusion

Fre fits teams building small to medium interfaces who want a readable VDOM runtime and are willing to compile JSX with jsxFactory set to h and jsxFragment set to Fragment. It does not fit projects that depend on a broad third-party component ecosystem, or that need a documented migration path from React, because the README does not describe one. Before adopting, verify three things on your own machine: that your bundler picks up the jsx-runtime export map entry, that the hooks you actually use behave as the README describes, and that you can live with the release cadence, which shipped 2.8.8 in September 2025 and 2.8.9 in June 2026.

Frequently asked questions

How do I install Fre?

The README gives a single command, yarn add fre, and then imports render and useState from the fre package. There is no scaffolding CLI documented, so you configure JSX compilation yourself.

How do I configure JSX for Fre with Vite?

The README's Vite example sets esbuild options with jsxFactory set to 'h', jsxFragment set to 'Fragment', and jsxInject importing both from 'fre'. The package also exposes ./jsx-runtime and ./jsx-dev-runtime entries for automatic runtimes.

Is Fre a React drop-in replacement?

The README does not document a migration path from React, and at least one API differs: context providers are written as <ThemeContext value="dark"> rather than with a .Provider suffix. Treat it as a separate library with a familiar model.

What hooks does Fre provide?

The README lists useState, useEffect, useReducer, useLayout, useCallback, useMemo, useRef and useContext, each with a short example. useLayout is described as sync and blocking UI, unlike useEffect.

What is Fre licensed under?

Fre is MIT licensed, attributed to yisar in the README. The repository also carries a FOSSA status badge, but the licence terms themselves come from the MIT identifier.

Official sources

  1. frejs/fre on GitHub
  2. License: MIT
  3. Project website
  4. README
  5. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/frejs-fre.svg)](https://hysenlabs.com/projects/frejs-fre)