Functional Orleans actors with typed F# APIs and explicit state transitions.
Orleans.FSharp keeps the Microsoft Orleans runtime and gives it an F#-first authoring model: grain APIs are records of functions, behavior is expressed as state transitions, and Orleans continues to own routing, activation, clustering, persistence, streams, and transactions.
Documentation · Getting started · Examples · Release status
This README documents Orleans.FSharp 5.0.2 (release date: 2 November 2026). Applications upgrading from 4.x should review the breaking changes and Legacy migration guide.
Version 5.0.2 retains the Orleans 10.1.0 minimum, with compatibility verified through 10.4.2. It aligns copier nullable contracts without adding runtime features or changing the public F# API or wire format. See compatibility notes for the update's scope.
- F# APIs stay F#. A grain surface is a typed record of functions using records, discriminated unions, options, results, and domain-specific keys.
- State changes are visible. Handlers return the next state or emitted events instead of mutating an actor object implicitly.
- Orleans semantics remain native. Versioning, placement, transactions, streams, reminders, persistence, and log-consistency providers still use Orleans underneath.
- No application-specific bridge project. Functional references use a fixed transport shipped with the library; there is no grain interface or generated proxy to maintain per actor.
- C# can call the same actor. A typed C# facade binds to the same contract without changing the F# domain model.
Define the public API, its stable Orleans contract, and the behavior in one place:
open System.Threading.Tasks
open Orleans.FSharp
type CounterActor = private CounterActor of unit
[<NoEquality; NoComparison>]
type CounterApi =
{ increment: unit -> Task<int>
value: unit -> Task<int> }
[<RequireQualifiedAccess>]
module Counter =
let contract =
grainContract<CounterActor, string, CounterApi> {
grainType "counter"
version 1
stringKey
readOnly (_.value)
}
let definition =
grainFor contract {
defaultState (fun () -> 0)
handle (_.increment) (fun _ state () ->
task {
let next = state + 1
return next, next
})
handleQuery (_.value) (fun _ state () -> task { return state })
}
let ref = FunctionalGrain.ref contractRegister the definition in a silo, then call the returned API record:
open Microsoft.Extensions.Hosting
open Orleans.FSharp
open Orleans.FSharp.Runtime
let addCounter (builder: HostApplicationBuilder) =
builder.UseOrleans(fun silo ->
silo.AddFunctionalGrain(Counter.definition) |> ignore)
|> ignore
let callCounter (grainFactory: Orleans.IGrainFactory) =
task {
let counter = Counter.ref grainFactory "counter-42"
let! next = counter.increment ()
let! current = counter.value ()
return next, current
}counter is a typed client facade. Calling one of its fields still crosses Orleans routing and
activation boundaries; it is not an in-process function call.
For a complete host, persistence, and tests, continue with Getting started.
Start a working solution with the 5.0.2 template:
dotnet new install Orleans.FSharp.Templates@5.0.2
dotnet new orleans-fsharp -n MyApp
cd MyApp
dotnet build
dotnet test
dotnet run --project src/MyApp.SiloThe 5.0.1 template includes the startup correction. If you already generated an application with the 5.0.0 template, apply the one-line source correction; updating packages does not rewrite existing application files.
Or add the packages to an existing application:
dotnet add package Orleans.FSharp --version 5.0.2
dotnet add package Orleans.FSharp.Runtime --version 5.0.2Add testing support when needed:
dotnet add package Orleans.FSharp.Testing --version 5.0.2Orleans.FSharp.Abstractions, which contains the fixed transport and precompiled Orleans
proxies, arrives transitively. Applications do not reference it directly.
To run the repository examples:
git clone --branch v5.0.2 https://github.com/Neftedollar/orleans-fsharp.git
cd orleans-fsharp
dotnet build Orleans.FSharp.slnx
dotnet run --project examples/feature-tour/src/FeatureTour| Building block | Responsibility |
|---|---|
| API record | The operations callers can invoke |
grainContract |
Actor identity, key encoding, contract version, and call policies |
grainFor / journaledGrainFor |
State, handlers, persistence, lifecycle, and event application |
FunctionalGrain.ref |
A typed API record bound to an Orleans IGrainFactory and grain key |
| Area | Highlights | Guide |
|---|---|---|
| Contracts | Typed keys, operation policies, version routing, C# facades | Contracts and keys |
| State | Ephemeral, persistent, transactional, per-state codecs and upcasters | State and lifecycle |
| Communication | Calls, observers, streams, broadcast channels, server-streaming replies | Calls and delivery |
| Scheduling | Activation hooks, lifecycle stages, timers, and reminders | State and lifecycle |
| Distribution | Stateless workers, Orleans placement strategies, activation migration | Placement and transactions |
| Event sourcing | Orleans log-consistency providers, pure event folds, schema evolution, snapshots | Event sourcing |
| Evolution | Rolling upgrades, versioned transport, state and event upcasters | Compatibility |
| Operations | Dashboard, health checks, security, testing, and observability | Documentation |
The complete functional runtime reference lists every builder operation, invariant, and known boundary.
| Example | Start here when you need… |
|---|---|
| Feature Tour | A live matrix of the supported Orleans surface |
| Chat Room | Persistence, observers, one-way calls, and a C# caller |
| Bank Account | Event sourcing and replay with journaledGrainFor |
| Order Processing | Domain-oriented F# with DUs, typed failures, and durable workflow state |
See all runnable examples, including transactions, Dashboard, SignalR, Fable, and type-safe IDs.
| Goal | Read |
|---|---|
| Build a first actor | Getting started |
| Understand the model | Functional runtime overview |
| Copy a focused recipe | How-to guides |
| Configure a host or client | Silo configuration · Client configuration |
| Choose serialization and persistence formats | Serialization |
| Add streams or streaming replies | Streams · Server-streaming replies |
| Test deployment compatibility | Testing · Release status |
| Look up an API | API reference |
| Package | Purpose |
|---|---|
Orleans.FSharp |
Contracts, functional definitions, references, streaming, and serialization |
Orleans.FSharp.Runtime |
Silo/client configuration and functional grain registration |
Orleans.FSharp.Testing |
Test helpers, FsCheck support, and log capture |
Orleans.FSharp.Analyzers |
F#-specific correctness diagnostics |
Orleans.FSharp.Templates |
The matching dotnet new project template |
Version-by-version upgrade notes do not live in this README:
- Migrate from Orleans.FSharp 4.x and earlier
- Archived documentation for the earlier authoring model
- Release-by-release changes
The Legacy archive is retained for migration only and does not receive new features, compatibility work, or security fixes.
- Security policy and deployment guidance: Security and SECURITY.md
- Contributions: issues and pull requests are welcome on GitHub
- License: MIT