Open-source project
reflex-frp/reflex avatar
reflex-frp/reflex

Reflex: a deterministic FRP engine for Haskell, and the platforms built on it

Interactive programs without callbacks or side-effects. Functional Reactive Programming (FRP) uses composable events and time-varying values to describe interactive systems as pure functions. Just like other pure functional code, functional reactive code is easier to get right on the first try, maintain, and reuse.

1,119 stars150 forksHaskellBSD-3-Clause

At a glance

What is it?
Reflex is a fully-deterministic, higher-order Functional Reactive Programming interface for Haskell together with an engine that implements it, describing interactive systems as pure functions over composable events and time-varying values. The library itself is deliberately small, and the frameworks around it, Reflex-DOM and Obelisk, are where most applications actually live.
Who is it for?
Reflex suits a Haskell developer building an interactive application, a game or a long-lived client, who wants the determinism that pure functional reactive code gives and is prepared to learn a different way of describing state.
Can I use it commercially?
Yes. BSD-3-Clause 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 2 days ago.
What is it written in?
Mainly Haskell, according to GitHub's language statistics.

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

Editorial analysis

What the library actually claims

The README opens with a sentence that is a complete description of the project. Interactive programs without callbacks or side-effects. Functional Reactive Programming, or FRP, uses composable events and time-varying values to describe interactive systems as pure functions. The claim that follows is about the engineering rather than the theory, that just like other pure functional code, functional reactive code is easier to get right on the first try, maintain, and reuse. Then the README makes the more precise technical statement, that Reflex is a fully-deterministic, higher-order Functional Reactive Programming interface and an engine that efficiently implements that interface. Two halves, then. The interface is the set of types and combinators a program is written against, and the engine is the machinery that runs a network of those things. The determinism is what distinguishes it from a general reactive framework, and it is a property of the interface rather than a feature of the implementation.

Why callbacks and side effects are the thing being removed

The phrase without callbacks or side-effects is doing the real work in the description, so it is worth being concrete about what it rules out. A conventional interactive program, a GUI with a button that updates a label, is built by attaching a handler to the button, and the handler mutates the label. That shape has two well known costs. The behaviour of the program depends on the order in which handlers happen to fire, which means it is difficult to reason about and hard to test, and the state is scattered across whatever variables the handlers close over, so there is no single description of what the program is currently showing. A functional reactive program describes the same system as a function from a network of events and time-varying values to a network of outputs, and the two costs disappear because there is no ordering to get wrong and no shared mutable state to scatter. The README's promise that the code is easier to get right on the first try is a claim about exactly this.

The core library is small, and that is deliberate

The repository layout shows how little is in the core package. There is a src/ directory holding the library, a reflex.cabal file, a ChangeLog.md, a Quickref.md at the top level, a bench/ directory with a bench-cbits/ subdirectory for benchmarks, a test/ directory, a Setup.hs for the Cabal build, a cabal.project and a cabal.haskell-ci file for the CI matrix, a .stylish-haskell.yaml for the formatter, and a stylize script. There is also a dep/ directory, a nixpkgs/ directory, an overlay.nix, a src.nix, a release.nix and a shell.nix, so the project is buildable with Nix and with a pinned nixpkgs rather than only with Cabal. The small surface area of the core is the point of the design. A framework that defines an interface and an engine, and then leaves the concrete widgets, the layout and the networking to the layers above, can keep a small, stable core, and the presence of the Quickref file as a first-class document is a sign of how the interface is meant to be learned.

Reflex-DOM and Obelisk are where applications actually get built

The Resources section is the most useful part of the README for an evaluator, because it shows that Reflex is a foundation rather than a product. Reflex-DOM is a framework built on Reflex that facilitates the development of web pages, including highly interactive single-page apps. Obelisk is a framework built on Reflex and Reflex-DOM for functional reactive web and mobile applications, with batteries included, and the description deliberately flags that it goes further than the web. Then there is reflex-platform, described as the place to get started with Reflex, and the official website, which carries more information, tutorials, documentation and examples. The practical reading is that the reflex package itself is an interface plus an engine, and a project that needs widgets, routing and a development server is expected to pick Obelisk or Reflex-DOM rather than to assemble one on the raw core.

The determinism claim, and what it buys you in testing

Determinism is the property the README leads with, and it is worth spelling out because it is the practical reason to accept a different programming model. Because the system is described as a pure function over inputs, the same inputs produce the same outputs, always. There is no wall-clock time read inside the description that has to be mocked, no random number generator that has to be seeded, and no ordering of handlers to reproduce. A test can therefore drive the system by feeding it events and then assert on the resulting values, with no special test harness and no mocking framework. The README's Quick Reference, linked at the top of the Resources list, is the artefact to read for the shape of the core types, and it is short by design, which is another way of seeing that the interface is meant to be grasped in one sitting rather than accumulated over months.

Hacking on Reflex, which means working inside reflex-platform

The Hacking section is unusually specific about the workflow, and the reason is that Reflex is not built on its own. From the root of a Reflex Platform checkout, you run the hack-on script targeting the reflex package, which checks out the reflex source code into the haskell-overlays/reflex-packages/dep/reflex directory inside that checkout. You can then point that checkout at your fork, make changes and so on, and the try-reflex or scripts/work-on scripts start a shell in which you can test your changes. So the development loop is a Nix-flavoured overlay workflow rather than a plain cabal one, which reflects that the project ships an overlay.nix, a src.nix and a pinned nixpkgs directory. A contributor is expected to have a Reflex Platform checkout to hand, and the setup is not something you can do from this repository alone.

bash
./scripts/hack-on haskell-overlays/reflex-packages/dep/reflex
./try-reflex
./scripts/work-on

Releases, licence and how the project talks to its users

The releases are v0.9.3.3 on 2025-01-19, v0.9.3.4 on 2025-06-02 and v0.9.4.0 on 2025-10-20, so the version line has been in the 0.9 series for a while and the last release is close to a full point version rather than another patch. The last push to the repository was on 2026-10-15, the repository is not archived, and the default branch is develop, so the tip of the branch is ahead of the last tag. The licence is BSD-3-Clause, which is permissive and the usual choice for a Haskell library of this kind. The community channels are a Matrix room at #reflex-frp:matrix.org, a Reddit community at r/reflexfrp, and an IRC channel on freenode. The last of those three is a good reminder that the communication infrastructure is partly of an earlier era, so for a project evaluating the long term, the Matrix room is the one to check for activity.

Editorial conclusion

Reflex suits a Haskell developer building an interactive application, a game or a long-lived client, who wants the determinism that pure functional reactive code gives and is prepared to learn a different way of describing state. It is the wrong choice for a small script or a typical request-response web service, because the whole model is oriented at continuous interaction rather than discrete requests, and a poor fit for a team that has not already committed to Haskell as a serious dependency. Before adopting it, read the Quickref, which is the shortest route to understanding the core types, and note that the library's own README points to Reflex-DOM and Obelisk as the practical starting points, since the core package on its own is an interface rather than an application framework.

Frequently asked questions

What is Reflex?

It is a fully-deterministic, higher-order Functional Reactive Programming interface for Haskell and an engine that efficiently implements that interface. FRP uses composable events and time-varying values to describe interactive systems as pure functions, without callbacks or side effects, and the licence is BSD-3-Clause.

Is Reflex a web framework on its own?

No. Reflex is an interface and an engine, and the README points to Reflex-DOM, a framework built on Reflex for web pages including single-page apps, and Obelisk, a framework built on Reflex and Reflex-DOM for web and mobile applications with batteries included. The reflex-platform repository is the documented starting point.

What does determinism give you in Reflex?

Because the system is a pure function over its inputs, the same inputs produce the same outputs, with no wall-clock time to mock, no random seed to fix and no handler ordering to reproduce. A test can drive the system by feeding it events and assert on the resulting values without a special harness.

How do I develop on the Reflex source?

From the root of a Reflex Platform checkout you run the hack-on script for the reflex package, which checks out the reflex source into the haskell-overlays/reflex-packages/dep/reflex directory, and you can point that checkout at your fork. The try-reflex and scripts/work-on scripts then start a shell in which you can test your changes.

How is Reflex packaged and built?

The repository has a reflex.cabal file, a cabal.project, a cabal.haskell-ci file for the CI matrix, a Setup.hs, a bench directory, a test directory and a Quickref.md, alongside an overlay.nix, a src.nix, a release.nix, a shell.nix and a pinned nixpkgs directory, so the project builds with both Cabal and Nix. The default branch is develop and the last release was v0.9.4.0 in October 2025.

Official sources

  1. License: BSD-3-Clause
  2. Project website
  3. README
  4. reflex-frp/reflex on GitHub
  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/reflex-frp-reflex.svg)](https://hysenlabs.com/projects/reflex-frp-reflex)

Was this useful?