FsFlow 0.3.0

dotnet add package FsFlow --version 0.3.0
                    
NuGet\Install-Package FsFlow -Version 0.3.0
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="FsFlow" Version="0.3.0" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="FsFlow" Version="0.3.0" />
                    
Directory.Packages.props
<PackageReference Include="FsFlow" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add FsFlow --version 0.3.0
                    
#r "nuget: FsFlow, 0.3.0"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package FsFlow@0.3.0
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=FsFlow&version=0.3.0
                    
Install as a Cake Addin
#tool nuget:?package=FsFlow&version=0.3.0
                    
Install as a Cake Tool

FsFlow

API Still stabilising - wait for 1.0 to avoid breaking changes

<picture> <source media="(prefers-color-scheme: dark)" srcset="docs/content/img/fsflow-readme-dark.svg"> <source media="(prefers-color-scheme: light)" srcset="docs/content/img/fsflow-readme-light.svg"> <img alt="FsFlow" src="docs/content/img/fsflow-readme-light.svg" width="160"> </picture>

FsFlow is a single model for Result-based programs in F#. Write validation and typed-error logic once, keep it as plain Result while the code is pure, then lift the same logic into Flow, AsyncFlow, or TaskFlow when the boundary needs environment access, async work, task interop, cancellation, or runtime policy.

ci NuGet License

Core Model

FsFlow is built around one progression:

Validate -> Result -> Flow -> AsyncFlow -> TaskFlow

The validation vocabulary stays the same while the execution context grows.

  • Start with plain Result and pure validation helpers.
  • Use flow {} when the boundary needs typed failure and environment, but not async runtime.
  • Use asyncFlow {} when the boundary is naturally Async.
  • Use taskFlow {} when the boundary is naturally .NET Task.
  • Keep expected failures typed all the way through instead of switching helper families at each runtime shape.

This is the key difference from split models like Result, Async<Result<_,_>>, and Task<Result<_,_>> that need separate helper modules, separate builders, and repeated adaptation at the boundary.

Install

  • FsFlow for Flow and AsyncFlow
  • FsFlow.Net for TaskFlow

Example

Start with pure validation:

open System.Threading.Tasks
open FsFlow.Validate

type RegistrationError =
    | EmailMissing
    | SaveFailed of string

let validateEmail (email: string) : Result<unit, RegistrationError> =
    email
    |> okIfNotBlank
    |> Result.map ignore
    |> orElse EmailMissing

Use the same Result directly inside a task-oriented workflow:

open System.Threading.Tasks
open FsFlow.Net

type User =
    { Email: string }

type RegistrationEnv =
    { LoadUser: int -> Task<Result<User, RegistrationError>>
      SaveUser: User -> Task<Result<unit, RegistrationError>> }

let registerUser userId : TaskFlow<RegistrationEnv, RegistrationError, unit> =
    taskFlow {
        let! loadUser = TaskFlow.read _.LoadUser
        let! saveUser = TaskFlow.read _.SaveUser

        let! user = loadUser userId
        do! validateEmail user.Email

        return! saveUser user
    }

validateEmail is just Result<unit, RegistrationError>. taskFlow lifts it directly with do!. There is no separate task-result validation vocabulary to learn first.

Semantic Boundary

FsFlow is for short-circuiting, ordered workflows:

  • Validate, Result, Flow, AsyncFlow, and TaskFlow stop on the first typed failure.
  • They are for orchestration, dependency access, async or task execution, and runtime concerns.
  • They are not accumulated validation builders.

If you need accumulated validation, keep that explicit with a dedicated validation library or bridge it in at the edge.

What You Get

FsFlow stays close to standard F# and .NET:

  • flow { ... } binds to Result and Option
  • asyncFlow { ... } also binds to Async and Async<Result<_,_>>
  • taskFlow { ... } binds to Task, ValueTask, Task<_>, ValueTask<_>, and ColdTask
  • Validate works as plain Result logic before lifting into a workflow

Because tasks are hot, FsFlow includes ColdTask: a small wrapper around CancellationToken -> Task. taskFlow handles token passing for you and keeps reruns explicit.

This is the file-oriented example shape. The full runnable example is in examples/FsFlow.ReadmeExample/Program.fs.

dotnet run --project examples/FsFlow.ReadmeExample/FsFlow.ReadmeExample.fsproj --nologo

Supporting types in the full example are just:

  • ReadmeEnv = { Root: string }
  • FileReadError = NotFound
let readTextFile (path: string) : TaskFlow<ReadmeEnv, FileReadError, string> =
    taskFlow {
        // In production, map access and path exceptions separately at the boundary.
        do! okIf (File.Exists path) |> orElse (NotFound path) // from Validate

        return! ColdTask(fun ct -> File.ReadAllTextAsync(path, ct)) // ColdTask<string>
    }

let program : TaskFlow<ReadmeEnv, FileReadError, string * string> =
    taskFlow {
        let! root = TaskFlow.read _.Root                       // ReadmeEnv.Root -> string
        let settingsFile = Path.Combine(root, "settings.json")
        let featureFlagsFile = Path.Combine(root, "feature-flags.json")

        let! settings = readTextFile settingsFile              // TaskFlow<ReadmeEnv, FileReadError, string>
        let! featureFlags = readTextFile featureFlagsFile      // TaskFlow<ReadmeEnv, FileReadError, string>

        return settings, featureFlags                          // TaskFlow<ReadmeEnv, FileReadError, string * string>
    }

It reads Root from 'env, performs two file reads in one taskFlow {}, and keeps failure typed at the boundary.

Getting Started

Product Compatible and additional computed target framework versions.
.NET net5.0 was computed.  net5.0-windows was computed.  net6.0 was computed.  net6.0-android was computed.  net6.0-ios was computed.  net6.0-maccatalyst was computed.  net6.0-macos was computed.  net6.0-tvos was computed.  net6.0-windows was computed.  net7.0 was computed.  net7.0-android was computed.  net7.0-ios was computed.  net7.0-maccatalyst was computed.  net7.0-macos was computed.  net7.0-tvos was computed.  net7.0-windows was computed.  net8.0 is compatible.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed.  net9.0 was computed.  net9.0-android was computed.  net9.0-browser was computed.  net9.0-ios was computed.  net9.0-maccatalyst was computed.  net9.0-macos was computed.  net9.0-tvos was computed.  net9.0-windows was computed.  net10.0 was computed.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
.NET Core netcoreapp3.0 was computed.  netcoreapp3.1 was computed. 
.NET Standard netstandard2.1 is compatible. 
MonoAndroid monoandroid was computed. 
MonoMac monomac was computed. 
MonoTouch monotouch was computed. 
Tizen tizen60 was computed. 
Xamarin.iOS xamarinios was computed. 
Xamarin.Mac xamarinmac was computed. 
Xamarin.TVOS xamarintvos was computed. 
Xamarin.WatchOS xamarinwatchos was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages (1)

Showing the top 1 NuGet packages that depend on FsFlow:

Package Downloads
FsFlow.Net

.NET task-oriented workflows, task interop, and task-specific runtime helpers for FsFlow.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
0.3.0 106 5/1/2026
0.2.0 80 4/27/2026

Split task-oriented workflows into FsFlow.Net while keeping sync and Async core concepts in the FsFlow package.