Repository F# setup
open System
open System.IO
open System.Threading
open System.Threading.Tasks
open Axial
open Axial.Layers
open Axial.Console
open Axial.FileSystem
open Axial.Hosting
open Axial.Hosting.Browser
open Axial.Hosting.Node
open Axial.PlatformService
open Axial.State
open Axial.Telemetry
open Axial.Telemetry.JavaScriptEffect-TS Comparison
Axial and Effect-TS both model typed effects. Axial runs on .NET and through Fable, so an F# application can use the same Flow model on server, Node, and browser targets without adopting Effect-TS for JavaScript deployment.
Shared model
Both libraries provide concepts for:
- typed success and expected-error channels
- explicit services and dependency provisioning
- cold, compositional workflows
- cancellation and structured concurrency
- resource scopes and deterministic cleanup
- retries, schedules, and timeouts
- streams
- runtime observability
The names and exact semantics differ. This list describes the areas of overlap, not API compatibility.
Why use Axial from F#
Axial keeps the workflow and domain model in F#:
flow { }uses F# computation-expression syntax.Flow<'env, 'error, 'value>exposes dependencies, expected errors, and success in an F# type.ResultandAsyncbind directly on .NET and Fable; .NET targets bindColdTaskfor cold, cancellation-aware task factories. RawTaskandValueTaskvalues require explicit started-work adapters.- On Fable,
Asyncis the Flow-facing bridge for JavaScript asynchronous work. Promise-returning APIs can be adapted toAsyncand then bound inflow { }; application code does not need Effect-TS merely to await a Promise. - Environment records and layers use ordinary F# values rather than a JavaScript-facing context boundary.
FlowStreamuses the same environment, error, cancellation, and runtime model on .NET and Fable.- Node and browser hosting packages connect Flow interruption to platform lifecycle signals.
- Fable telemetry integrates with the JavaScript observability platform without changing the application workflow.
Shared F# code can retain Axial's typed effects, concurrency, streams, and observability across the generated-JavaScript boundary without translating workflows into Effect-TS.
The concrete Promise adapter is Fable's Async.AwaitPromise; because flow { } binds Async directly, an adapted
Promise is one let! away:
open Fable.Core
let awaitPromise (promise: JS.Promise<'T>) : Async<'T> =
Async.AwaitPromise promise
let readRemote : Flow<unit, string, 'T> =
flow {
let! value = awaitPromise (loadRemote ()) // loadRemote returns JS.Promise<'T>
return value
}When Effect-TS is still the natural boundary
Use Effect-TS when the workflow is owned by TypeScript or must compose directly with an existing Effect-TS application and its services. Calling that application from generated F# may be a legitimate integration boundary. The JavaScript deployment target alone does not require Effect-TS as the runtime for F# code.
Use Axial when F# owns the application workflow and the code needs to run on .NET, Node, the browser, or a combination
of those targets. The same Flow API then remains the application model rather than an adapter on the way to a second
effect system.
Compare concrete requirements
Compare the application's requirements:
- which language owns orchestration and service definitions
- whether workflows are shared between .NET and Fable
- which platform APIs require adapters
- which concurrency and stream operators the application actually uses
- which telemetry backend and hosting lifecycle own execution
For an F#-owned application, use Axial on every supported target. Introduce an Effect-TS boundary only when the application must participate in TypeScript code that already uses Effect-TS.

