Framework
camlworks/dream avatar
camlworks/dream

Dream: one OCaml module across three packages

Tidy, feature-complete Web framework

1,895 stars164 forksOCamlMIT

At a glance

What is it?
Dream is an MIT licensed OCaml web framework presented as a single flat module with a single page of documentation and a tutorial made of numbered examples. It ships as three opam packages so you can swap the HTTP stack underneath, and 1.0.0 landed on 2026-10-07 after two years of alphas.
Who is it for?
Adopt Dream if you are writing an OCaml or ReasonML service and want WebSockets, GraphQL and templates without assembling a stack yourself. Skip it if you want a framework that hides its HTTP layer rather than letting you replace it, since the whole design leans on that swap.
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 1 day ago.
What is it written in?
Mainly OCaml, according to GitHub's language statistics.

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

Editorial analysis

The smallest complete server is seven lines

The README's first example is a whole HTTP server: a function returning HTML, composed with a logger and a router, and started with Dream.run. Nothing else is required to serve a page.

ocaml
let hello who =
  <html>
  <body>
    <h1>Hello, <%s who %>!</h1>
  </body>
  </html>

let () =
  Dream.run
  @@ Dream.logger
  @@ Dream.router [
    Dream.get "/" (fun _ -> Dream.html (hello "world"));
  ]

The style is deliberate. Handlers are just functions, middleware and routes compose with the @@ operator, and the API stays on base OCaml types like string and list. The README notes that some of Dream's own types are abbreviations for bare functions, which is why the surface fits on one page.

That readability is the product. If you have read the reference once you are meant to remember it, and the tutorial exists to do that memorising through worked examples.

One module on top, three opam packages underneath

The presentation is a single flat module in a single package. The repository root tells a different story: there are three opam files, dream.opam, dream-httpaf.opam and dream-pure.opam, and the Makefile builds exactly that set.

makefile
PACKAGES := dream-pure,dream-httpaf,dream

The sub-libraries under src/ are split by their dependency sets, so the same application can be ported to a different environment by swapping which package it links. The README also mentions running Dream as a quite bare abstraction over its underlying HTTP libraries, where it acts only as minimal glue between their slightly different interfaces.

So there are two layers of choice here. Normally you install the full package and use the convenient API. If you need to change the HTTP implementation or trim dependencies, the sub-packages are there, and that is the case for reading src/ rather than the reference page.

The tutorial is twenty numbered directories

Instead of prose chapters, the tutorial is a sequence of example directories, each runnable on its own:

The tutorial is a sequence of example directories, each runnable on its own, starting at 1-hello, then 2-middleware, 3-router, 4-counter, 5-promise and 6-echo, continuing through 7-template, 8-debug, 9-error, a-log, b-session, c-cookie, d-form, e-json, f-static, g-upload, h-sql, i-graphql, j-stream, k-websocket and l-https. There are separate full stack examples for Melange, ReScript and js_of_ocaml clients, plus one for TyXML, one for esy and one for bundling assets into a single binary.

The progression is deliberate. You hit a router before middleware depth, sessions and cookies before forms, and GraphQL only after JSON and SQL. Security topics are covered in the early half rather than bolted on, and the README says the tutorial threads through the first several examples touching all the basic topics including security.

The examples double as the documentation links. Every feature bullet in the README points at a specific folder in example/, so a claim about WebSockets and a claim about sessions lead to the same kind of artifact: a small directory you can read end to end.

opam or esy, with a one-line quick start

The fastest path is a shell command that fetches and builds the first tutorial example, which is worth knowing exists but is not something to paste blindly into a workstation:

bash
bash -c "$(curl -fsSL https://raw.githubusercontent.com/camlworks/dream/master/example/quickstart.sh)"

The opam path is the one to use properly. You create a project directory with a local switch, then install the framework:

bash
mkdir project
cd project
opam switch create . 5.1.0
eval $(opam env)
opam install dream

After that you copy any example directory locally and run it with dune, for instance `dune exec ./middleware.exe` from the 2-middleware example. esy is supported as well: each example carries an esy.json, installed with `npx esy` and started with `npx esy start`.

Deployment is treated as a first class concern rather than an afterthought, with instructions and sample CI scripts for Digital Ocean, Heroku and Fly.io.

HTTPS without a proxy, and crypto you can rotate

Two features exist specifically to remove infrastructure from a small deployment. Dream serves HTTPS and HTTP/2 directly, and the README states that it runs without a proxy, which for a single service on a small VPS means no Caddy or nginx in front of it.

The second is cryptography. There are helpers for cryptography, key rotation and a chosen cipher, plus helpers for secure cookies and CSRF-safe forms. Sessions come with pluggable storage back ends, so the session store is a decision rather than a fixed choice.

Both of those are areas where a framework can quietly take a decision away from you. Here the framing is that the machinery is available and documented, which still means you have to pick a cipher and a session back end yourself.

Where Dream is the wrong choice

It is wrong if you do not want a low level framework. The README calls Dream low-level and unopinionated, and that is a commitment, not modesty. You can replace its conveniences, for instance using TyXML with server-side JSX instead of the built-in templates, so a team that expected batteries-included conventions will find fewer of them than the feature list implies.

It is also OCaml only. There is no story for a mixed stack where the server is written in another language, and while the framework is happy to serve JavaScript clients compiled by Melange, ReScript or js_of_ocaml, that is a client story rather than a polyglot one.

The types stick to string and list, which keeps things simple and also means you convert at the boundary yourself.

Finally, the release history shows a gap between 1.0.0-alpha8 in December 2024 and 1.0.0 in October 2026. Code written against an alpha may need changes.

Licence, build tooling and release state

Dream is MIT licensed, in LICENSE.md at the repository root, so commercial use and modification carry only the usual notice requirement.

The build is dune throughout, with .ocamlformat present, so formatting is enforced by the repository's own configuration. The Makefile targets are conventional: build, watch, deps, deps-no-test, test, test-watch, coverage-serve, promote, docs, docs-watch, docs-serve, docs-publish and clean.

The test target is more interesting than usual. It instruments the build with bisect_ppx, runs the test suite, then calls bisect-ppx-report html and bisect-ppx-report summary, writing to _coverage/index.html. Coverage is browsable through `dune exec -- dream-serve -p 8082` from that directory.

Version 1.0.0 was published on 2026-10-07, one week before the last push. CHANGES.md sits at the repository root, and that is the file to read before migrating off an alpha.

Editorial conclusion

Adopt Dream if you are writing an OCaml or ReasonML service and want WebSockets, GraphQL and templates without assembling a stack yourself. Skip it if you want a framework that hides its HTTP layer rather than letting you replace it, since the whole design leans on that swap. Verify first which of the three packages your use case needs, dream, dream-httpaf or dream-pure, and read CHANGES.md before moving from a 1.0.0-alpha build to 1.0.0.

Frequently asked questions

How do I install Dream for OCaml?

Create a project directory and a local switch with opam switch create . 5.1.0, run eval $(opam env), then opam install dream. Afterwards you can copy any example directory and start it with dune, for example dune exec ./middleware.exe.

Does Dream need a reverse proxy for HTTPS?

No. The README states that Dream offers easy HTTPS and HTTP/2 support and runs without a proxy. It also ships cryptography helpers, key rotation and a chosen cipher, which you configure yourself.

What is the difference between the dream, dream-httpaf and dream-pure packages?

They are the sub-libraries the framework is factored into, split by dependency so applications can be ported to different environments. The Makefile builds all three, while ordinary use installs the single dream package as one flat module.

Is Dream 1.0.0 stable?

Version 1.0.0 was released on 2026-10-07 after a series of 1.0.0 alphas, with 1.0.0-alpha8 dated 2024-12-01. Read CHANGES.md before moving from an alpha, since API changes accumulated over that period.

Official sources

  1. camlworks/dream 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/camlworks-dream.svg)](https://hysenlabs.com/projects/camlworks-dream)

Was this useful?