Skip to content

Legacy: Frequently Asked Questions

Archived answers for the original Orleans.FSharp authoring API.

This archived FAQ describes the original Orleans.FSharp authoring surface. Current answers live in Frequently Asked Questions.

Note. Grain authoring has two models. The grain { } CE shown on this page still compiles and runs, but its public surface now carries [<Obsolete>] (warning, not error); new code should use the functional grain runtime (grainContract / grainFor / FunctionalGrain.ref / AddFunctionalGrain). See functional-grains.md. siloConfig { }, clientConfig { } and eventSourcedGrain { } are unaffected.

Orleans.FSharp is an idiomatic F# API layer for Microsoft Orleans, the virtual actor framework by Microsoft. It provides the functional grain runtime (grainContract / grainFor / journaledGrainFor) plus the siloConfig { } and clientConfig { } hosting computation expressions, so you define distributed actors in pure F# — no C# boilerplate needed. It has Orleans 10 parity and 2,500+ tests across unit and integration suites.

Install the package and use the grain {} computation expression:

Terminal window
dotnet add package Orleans.FSharp
dotnet add package Orleans.FSharp.Runtime
dotnet add package Orleans.FSharp.Abstractions
open Orleans.FSharp
[<GenerateSerializer>]
type CounterState =
| [<Id(0u)>] Zero
| [<Id(1u)>] Count of int
[<GenerateSerializer>]
type CounterCommand =
| [<Id(0u)>] Increment
| [<Id(1u)>] Decrement
| [<Id(2u)>] GetValue
let counter =
grain {
defaultState Zero
handle (fun state cmd ->
task {
match state, cmd with
| Zero, Increment -> return Count 1, box 1
| Zero, Decrement -> return Zero, box 0
| Count n, Increment -> return Count(n + 1), box(n + 1)
| Count n, Decrement when n > 1 -> return Count(n - 1), box(n - 1)
| Count _, Decrement -> return Zero, box 0
| _, GetValue ->
let v = match state with Zero -> 0 | Count n -> n
return state, box v
})
persist "Default"
}

See the Getting Started guide for a full walkthrough.

Functional-runtime equivalent (the current authoring model — same increment/decrement/value domain, a typed API record instead of a boxed message):

open System.Threading.Tasks
open Orleans.FSharp
type CounterActor = private CounterActor of unit
[<NoEquality; NoComparison>]
type CounterApi =
{ increment: unit -> Task<int>
decrement: unit -> Task<int>
value: unit -> Task<int> }
[<RequireQualifiedAccess>]
module CounterApi =
let contract =
grainContract<CounterActor, string, CounterApi> {
grainType "counter"
version 1
stringKey
}
let ref = FunctionalGrain.ref contract
let counterDefinition =
grainFor CounterApi.contract {
defaultState (fun () -> 0)
handle (_.increment) (fun _context state () -> task { let next = state + 1 in return next, next })
handle (_.decrement) (fun _context state () -> task { let next = max 0 (state - 1) in return next, next })
handle (_.value) (fun _context state () -> task { return state, state })
}

Register with siloBuilder.AddFunctionalGrain(counterDefinition), then call it as let api = CounterApi.ref factory "my-counter" in api.increment () — no boxed reply, no separate handle type. See Getting Started for the complete functional-first walkthrough.

How does Orleans.FSharp compare to using Microsoft Orleans from C#?

Section titled “How does Orleans.FSharp compare to using Microsoft Orleans from C#?”

Orleans.FSharp provides the same functionality as the C# Microsoft Orleans API but with idiomatic F# syntax. Instead of inheriting from Grain base classes and writing imperative C#, you use computation expressions. Key differences:

FeatureC# OrleansOrleans.FSharp
Grain definitionClass inheritancegrainContract + grainFor (current); grain { } CE (deprecated)
State managementMutable propertiesImmutable state returned from handlers
ConfigurationExtension method chainssiloConfig { } CE
Type safetyRuntime errorsCompile-time constraints, typed API records
TestingManual mockingTestingHost + GrainArbitrary + FsCheck

Dispatch overhead is small and paid once per call: the repository’s benchmark holds it below 5% of calling the handler function directly, which is unmeasurable next to network latency.

What F# features does Orleans.FSharp support?

Section titled “What F# features does Orleans.FSharp support?”
  • Discriminated unions as grain state with automatic serialization
  • Computation expressions for all grain, silo, and client configuration
  • Pattern matching for message handling
  • Immutability by default — state transitions return new state
  • Property-based testing with FsCheck + GrainArbitrary
  • TaskSeq for streaming (IAsyncEnumerable)
  • FsToolkit.ErrorHandling for taskResult {} error handling

Yes. Orleans.FSharp has:

  • 2,500+ tests across unit and integration suites
  • Full Orleans 10 feature parity (137 CE operations across 8 builders)
  • Zero Unchecked.defaultof in source code
  • TLS/mTLS support, call filters, request context propagation
  • Input validation on all string parameters
  • Security scanning (Gitleaks) in CI

What Microsoft Orleans features are supported?

Section titled “What Microsoft Orleans features are supported?”

All of them. Orleans.FSharp wraps the Orleans 10 feature set:

  • Grain lifecycle (activate, deactivate, timers, reminders)
  • State persistence (memory, Redis, Azure, Cosmos, DynamoDB, ADO.NET)
  • Streaming (memory, Event Hubs, Azure Queue, broadcast channels)
  • Reentrancy, stateless workers, placement strategies
  • Event sourcing (journaledGrainFor over Orleans’ log-consistency providers; the classic eventSourcedGrain { } CE is still shipped)
  • Distributed ACID transactions (transactional + transactionalStateFrom)
  • Observers, call filters, request context
  • Grain directory, grain services, grain extensions
  • TLS/mTLS, health checks, OpenTelemetry
  • Kubernetes clustering, interface versioning

See the API Reference for the complete list of modules and functions.

Terminal window
dotnet new install Orleans.FSharp.Templates
dotnet new orleans-fsharp -n MyApp
cd MyApp
dotnet build && dotnet test && dotnet run --project src/MyApp.Silo

This creates a complete solution with a counter grain, tests, and silo — ready in under 2 minutes. See the full Getting Started tutorial.

What is the difference between Orleans.FSharp and Akkling?

Section titled “What is the difference between Orleans.FSharp and Akkling?”

Akkling is an F# API for Akka.NET (a port of JVM Akka). Orleans.FSharp wraps Microsoft Orleans. Key differences:

Orleans.FSharpAkkling (Akka.NET)
RuntimeMicrosoft Orleans (virtual actors)Akka.NET (classic actors)
Actor modelVirtual — always addressable, auto-activatedClassic — explicit lifecycle management
StateAutomatic persistenceManual persistence
.NET version.NET 10.NET 6+
ClusteringBuilt-in (Redis, Azure, Kubernetes)Akka.Cluster
MaintenanceActive (Orleans 10 parity)Community maintained

What NuGet packages does Orleans.FSharp include?

Section titled “What NuGet packages does Orleans.FSharp include?”
PackageDescription
Orleans.FSharpCore: the functional grain runtime, observers, streaming, serialization, and the deprecated grain { } CE
Orleans.FSharp.RuntimeSilo and client hosting: AddFunctionalGrain, siloConfig { }, clientConfig { }
Orleans.FSharp.AbstractionsThe fixed functional transport and its precompiled Orleans proxies (arrives transitively)
Orleans.FSharp.TestingTestHarness, GrainMock, GrainArbitrary, log capture
Orleans.FSharp.EventSourcingThe classic eventSourcedGrain { } model
Orleans.FSharp.CodeGenOptional per-grain C# code generation for hand-written grain interfaces
Orleans.FSharp.AnalyzersThe OF0001 analyzer with an [<AllowAsync>] opt-out
Orleans.FSharp.TemplatesThe dotnet new orleans-fsharp project template

Orleans.FSharp is open source under the MIT license: github.com/Neftedollar/orleans-fsharp