The web, end to end, in OCaml
WebSharper turns one language into a whole application — server and browser, routing and serialization, data and UI, all sharing the same types. That language is now OCaml. Write it once; let the compiler keep the two tiers honest.
Coming soon — this page previews what is on the way.
One language, both tiers
Define an endpoint type, return typed content, drop in reactive client-side pieces. The same source becomes a native server and a JavaScript client — with no serialization glue and no hand-written fetch calls.
Call the server as if it were local
Tag a function with [@rpc] and the
compiler writes the client proxy for you. One typed call, and the arguments and results
cross the wire by themselves — no routes to invent, no JSON to hand-roll, no drift between tiers.
Server, shared, browser
Three files, one codebase. A shared module both tiers open, a sitelet that server-renders the page, and a reactive view that the browser hydrates onto those server-rendered nodes. Compile once; both tiers stay in lockstep.
(* Shared by both tiers: one type, one function, server and browser. *)
type todo = { id : int; title : string; done_ : bool }
(* Mark it [@rpc] and the compiler writes the client proxy for you. *)
let[@rpc] addTodo (title : string) : todo =
let id = Id.next () in
Db.save { id; title; done_ = false };
{ id; title; done_ = false }
open WebSharper_Server
open WebSharper_ClientServer
let[@website] main =
Sitelet.infer (fun (_ : endpoint context) ep ->
match ep with
| Home ->
Content.page
~title:"Todos"
[ hydrate (fun () -> Client.view ()) ]
| _ ->
Content.page
~title:"Not found"
[ h1 [] [ text "404" ] ])
open WebSharper_UI
open WebSharper_UI.Html
open WebSharper_UI.Notation
(* `addTodo` runs on the server, but here it is just a typed call. *)
let renderList (ts : todo list) =
String.concat ", " (List.map (fun t -> t.title) ts)
let view () =
let todos : todo list Var.t = Var.create [] in
div []
[ button
[ on.click (fun _ _ -> todos := addTodo "Buy milk" :: !todos) ]
[ text "Add a todo" ];
ul []
[ textView (View.map renderList (Var.view todos)) ] ]
Reactive by default
On the client, every value can be a Var,
every expression a View
— this is the browser-side reactive model (server-rendered pages return plain HTML).
Your document updates itself as the data flows — no virtual DOM, no re-render, just values.
Everything WebSharper gives you
The whole toolset, now from OCaml.
Typed routing
Sitelets turn endpoints into values; links are generated and checked by the compiler.
Reactive UI
WebSharper.UI's HTML combinators and templates, on both tiers, in OCaml.
Remoting & WebSockets
Call server functions, and exchange typed messages, without any plumbing.
Serialization
Your OCaml types become JSON automatically — the same shape on the server and the client.
Client-side testing
Test your browser code in your editor, and run the same suite in QUnit.
Native OCaml server
Your server is a real OCaml web server (websharper-server); only the client is compiled to JavaScript.
Fall in love with full-stack functional programming
One language. Two tiers. Zero glue.