Build full-stack web apps. Stay in F#.

Build reactive UIs, call server functions directly, and share types across your application - all with the power of F# and .NET.

Get started
$ dotnet new install WebSharper.Templates
[<JavaScript>]
module Client =
    type IndexTemplate = Template<"wwwroot/index", ClientLoad.FromDocument>

    let People =
        ListModel.FromSeq [
            "John"
            "Paul"
        ]

    [<SPAEntryPoint>]
    let Main () =
        let newName = Var.Create ""
        IndexTemplate.Main()
            .ListContainer(
                People.View.DocSeqCached(fun (name: string) -> 
                    IndexTemplate.ListItem().Name(name).Doc()
                )
            )
            .Name(newName)
            .Add(fun _ ->
                People.Add(newName.Value)
                newName.Value <- ""
            )
            .Doc()
        |> Doc.RunById "main"
Terminal
VITE v6.3.5 ready in 663 ms
➜ Network: use --host to expose
➜ press h + enter to show help
█

Trusted by fast-growing companies around the world

How it works

Write your app once in C# or F#, or in OCaml. The compiler emits a native .NET or OCaml server and a JavaScript client that share both their data types and the metadata that connects them.

DSLs via source code generators F# source one codebase C# source OCaml source WebSharper.OCaml toolchain WebSharper compiler + metadata Native .NET server sitelets · remoting · JSON Your application DOM · reactive UI · WebSockets Native OCaml server sitelets · remoting · JSON

Shared types and typed calls across the boundary — no hand-written serialization or fetch glue.

Functional, reactive applications with WebSharper.UI

Bind composite data models to your reactive user interfaces. The flow of reactive values through the code yet concise, readability.

let x = Var.Create 1
let y = Var.Create 1

let addNumbers =
    div [] [
        p [] [text "x "; Doc.InputType.IntUnchecked [] x]
        p [] [text "y "; Doc.InputType.IntUnchecked [] y]
        p [] [
            textView (View.Map2 (fun x y -> $"x + y = {x + y}") x.View y.View)
        ]
    ]

addNumbers |> Doc.RunById "main"
Search

Powerful UI abstractions

Declare full interactive forms in just a few lines of code with WebSharper Forms.

let LoginForm () =
    Form.Return (fun user pass -> user, pass)
    <*> (Form.Yield ""
        |> Validation.IsNotEmpty "Must enter a username")
    <*> (Form.Yield ""
        |> Validation.IsNotEmpty "Must enter a password")
    |> Form.WithSubmit
    |> Form.Run (fun (u, p) ->
        JS.Alert("Welcome, " + u + "!")
    )
    |> Form.Render (fun user pass submit ->
        form [] [
            div [] [label [] [text "Username: "]; Doc.InputType.Text [] user]
            div [] [label [] [text "Password: "]; Doc.InputType.Password [] pass]
            Doc.Button "Log in" [] submit.Trigger
            div [] [
                Doc.ShowErrors submit.View (fun errors ->
                    errors
                    |> Seq.map (fun m -> p [] [text m.Text])
                    |> Doc.Concat)
            ]
        ]
    )
    
LoginForm() |> Doc.RunById "main"
Search

Web Workers without hassle

Write client-side parallel code directly in your code.

The compiler automatically creates the separate trimmed JavaScript file for the web worker.

Worker.fs
let worker = new Worker(fun self ->
  // This code runs in the worker:
  self.OnMessage <- fun e ->
      Console.Log(
        "Received message from main thread: " 
        + string e.Data
      )
)

// This code runs in the main thread:
worker.PostMessage("Hello, worker!")
index.js
var worker = new Worker("worker.js");
worker.postMessage("Hello, worker!");
worker.js
self.onmessage = function (e) {
    console.log(
       "Received message from main thread: "
           + e.data.toString());
}
Terminal

Get Started

Instant access to the power of WebSharper

Get started
$ dotnet new install WebSharper.Templates