Skip to main content

Command Module

The Command module provides functions for performing side effects in your Elmish Land application. Commands are used to trigger asynchronous operations, send messages, navigate between pages, and communicate between components.

Where is this defined?​

The Command module is automatically generated during the build process:

  • Generated Location: .elmish-land/Base/Command.fs (in your project)
  • Generated By: Running elmish-land restore, elmish-land server and elmish-land build commands
  • Namespace: ElmishLand

The Command type is implemented as a discriminated union that wraps Elmish's standard Cmd<'msg> type, adding support for routing messages to Shared state and parent Layouts.

warning

The .elmish-land/Base/Command.fs file is auto-generated and should not be edited directly. Any changes will be overwritten on the next build.

Command.none​

Returns a command that does nothing. Use this when your init or update functions doesn't need to perform any side effects.

Signature​

Command.none : Command<'msg, 'sharedMsg, 'layoutMsg>

Example​

let update msg model =
match msg with
| Increment ->
{ model with Count = model.Count + 1 },
Command.none

Command.ofMsg​

Creates a command that dispatches a message immediately after the current update completes.

Signature​

Command.ofMsg : 'msg -> Command<'msg, 'sharedMsg, 'layoutMsg>

Parameters​

  • msg - The message to dispatch

Example​

let init () =
{ Users = []; Loading = true },
Command.ofMsg LoadUsers

Command.batch​

Combines multiple commands into a single command that executes all of them.

Signature​

Command.batch : Command<'msg, 'sharedMsg, 'layoutMsg> list -> Command<'msg, 'sharedMsg, 'layoutMsg>

Parameters​

  • commands - List of commands to execute

Example​

let init () =
model,
Command.batch [
Command.ofMsg LoadUsers
Command.ofMsg LoadSettings
Command.ofShared CheckAuthStatus
]

Command.ofPromise​

Executes a promise and dispatches a message with the result. Throws an exception if the promise fails.

Signature​

Command.ofPromise :
task: ('arg -> JS.Promise<'result>)
-> arg: 'arg
-> ofSuccess: ('result -> 'msg)
-> Command<'msg, 'sharedMsg, 'layoutMsg>

Parameters​

  • task - Function that returns a promise
  • arg - Argument to pass to the task function
  • ofSuccess - Function that converts the result into a message

Example​

type Msg =
| LoadUsers
| UsersLoaded of User list

let fetchUsers () =
promise {
let! response = Fetch.fetch "/api/users"
return! response.json<User list>()
}

let update msg model =
match msg with
| LoadUsers ->
{ model with Loading = true },
Command.ofPromise fetchUsers () UsersLoaded

| UsersLoaded users ->
{ model with Users = users; Loading = false },
Command.none

Command.tryOfPromise​

Executes a promise and dispatches different messages based on success or failure. Does not throw exceptions.

Signature​

Command.tryOfPromise :
task: ('arg -> JS.Promise<'result>)
-> arg: 'arg
-> ofSuccess: ('result -> 'msg)
-> ofError: (exn -> 'msg)
-> Command<'msg, 'sharedMsg, 'layoutMsg>

Parameters​

  • task - Function that returns a promise
  • arg - Argument to pass to the task function
  • ofSuccess - Function that converts successful results into a message
  • ofError - Function that converts errors into a message

Example​

type Msg =
| LoadUsers
| UsersLoaded of User list
| LoadError of exn

let fetchUsers () =
promise {
let! response = Fetch.fetch "/api/users"
return! response.json<User list>()
}

let update msg model =
match msg with
| LoadUsers ->
{ model with Loading = true; Error = None },
Command.tryOfPromise
fetchUsers
()
UsersLoaded
LoadError

| UsersLoaded users ->
{ model with Users = users; Loading = false },
Command.none

| LoadError error ->
{ model with Loading = false; Error = Some error },
Command.none

Command.ofAsync​

Executes an F# async workflow and dispatches a message with the result. Throws an exception if the async operation fails.

This function work seamlessly with Fable.Remoting for type-safe server communication and any F# libraries that return Async<'T> types.

Signature​

Command.ofAsync :
task: ('arg -> Async<'result>)
-> arg: 'arg
-> ofSuccess: ('result -> 'msg)
-> Command<'msg, 'sharedMsg, 'layoutMsg>

Parameters​

  • task - Function that returns an async workflow
  • arg - Argument to pass to the task function
  • ofSuccess - Function that converts the result into a message

Example, Fable.Remoting​

// Shared API definition
type IUserApi = {
getUsers: unit -> Async<User list>
}

// Client code
type Msg =
| LoadUsers
| UsersLoaded of User list

let userApi =
Remoting.createApi()
|> Remoting.buildProxy<IUserApi>

let update msg model =
match msg with
| LoadUsers ->
{ model with Loading = true },
Command.ofAsync userApi.getUsers () UsersLoaded

| UsersLoaded users ->
{ model with Users = users; Loading = false },
Command.none

Command.tryOfAsync​

Executes an F# async workflow and dispatches different messages based on success or failure. Does not throw exceptions.

This function work seamlessly with Fable.Remoting for type-safe server communication and any F# libraries that return Async<'T> types.

Signature​

Command.tryOfAsync :
task: ('arg -> Async<'result>)
-> arg: 'arg
-> ofSuccess: ('result -> 'msg)
-> ofError: (exn -> 'msg)
-> Command<'msg, 'sharedMsg, 'layoutMsg>

Parameters​

  • task - Function that returns an async workflow
  • arg - Argument to pass to the task function
  • ofSuccess - Function that converts successful results into a message
  • ofError - Function that converts errors into a message

When to Use​

Use Command.tryOfAsync when you need to handle errors explicitly in your application. This is especially useful with:

  • Fable.Remoting for type-safe server communication
  • F# libraries that return Async<'T> types
  • .NET async APIs

Use Command.tryOfPromise when working with JavaScript libraries and browser APIs.

Example, Fable.Remoting with Error Handling​

// Shared API definition
type IWeatherApi = {
getWeatherForecast: unit -> Async<WeatherForecast list>
}

// Client code
type Msg =
| LoadWeather
| WeatherLoaded of WeatherForecast list
| LoadError of exn

let weatherApi =
Remoting.createApi()
|> Remoting.buildProxy<IWeatherApi>

let update msg model =
match msg with
| LoadWeather ->
{ model with Loading = true; Error = None },
Command.tryOfAsync
weatherApi.getWeatherForecast
()
WeatherLoaded
LoadError

| WeatherLoaded forecasts ->
{ model with Forecasts = forecasts; Loading = false },
Command.none

| LoadError error ->
{ model with Loading = false; Error = Some error },
Command.none

Command.ofShared​

Sends a message to the Shared module, allowing pages and layouts to update shared state.

Signature​

Command.ofShared : 'sharedMsg -> Command<'msg, 'sharedMsg, 'layoutMsg>

Parameters​

  • sharedMsg - The message to send to the Shared module

Example​

// In a Page.fs file
type Msg =
| SignOutClicked
| LayoutMsg of Layout.Msg

let update msg model =
match msg with
| SignOutClicked ->
model,
Command.ofShared SharedMsg.SignOut

| LayoutMsg _ ->
model, Command.none

See Shared State for more details.

Command.ofLayout​

Sends a message from a page to its layout.

Signature​

Command.ofLayout : 'layoutMsg -> Command<'msg, 'sharedMsg, 'layoutMsg>

Parameters​

  • layoutMsg - The message to send to the layout

Example​

// In a Page.fs file
type Msg =
| UpdateTitle of string
| LayoutMsg of Layout.Msg

let update msg model =
match msg with
| UpdateTitle title ->
model,
Command.ofLayout (Layout.SetTitle title)

| LayoutMsg _ ->
model, Command.none

See Layouts - Sending messages for more details.

Command.navigate​

Navigates to a different page in your application.

Signature​

Command.navigate : Route -> Command<'msg, 'sharedMsg, 'layoutMsg>

Parameters​

  • route - The route to navigate to (from the generated Route discriminated union)

Example (Static Route)​

type Msg =
| LoginSuccessful of User
| LayoutMsg of Layout.Msg

let update msg model =
match msg with
| LoginSuccessful user ->
model,
Command.navigate (Route.Dashboard ())

| LayoutMsg _ ->
model, Command.none

Example (Dynamic Route)​

Navigate to routes with parameters:

// Navigate to /#users/123
Command.navigate (Route.UsersId { Id = "123"; Query = [] })

// Navigate to /#blog/my-post?highlight=true
Command.navigate (
Route.BlogSlug {
Slug = "my-post"
Query = [ "highlight", "true" ]
}
)

See Linking and Navigating for more details.

Command.ofCmd​

Converts an Elmish Cmd<'msg> to an Elmish Land Command<'msg, 'sharedMsg, 'layoutMsg>. This is useful when integrating with libraries that return standard Elmish commands.

Signature​

Command.ofCmd : Cmd<'msg> -> Command<'msg, 'sharedMsg, 'layoutMsg>

Parameters​

  • cmd - The Elmish command to convert

Example​

open Elmish

let update msg model =
match msg with
| UseElmishLibrary ->
let elmishCmd = SomeLibrary.createCommand ()
model,
Command.ofCmd elmishCmd

Best Practices​

Prefer tryOfPromise/tryOfAsync over ofPromise/ofAsync​

Always use Command.tryOfPromise or Command.tryOfAsync instead of their non-try counterparts in production code to handle errors gracefully:

// Good - Handles errors (Promise-based)
Command.tryOfPromise fetchData () DataLoaded LoadError

// Good - Handles errors (Async-based)
Command.tryOfAsync fetchData () DataLoaded LoadError

// Avoid - Errors will crash the application
Command.ofPromise fetchData () DataLoaded
Command.ofAsync fetchData () DataLoaded

When you need to perform multiple side effects, use Command.batch to keep your code organized:

let init () =
model,
Command.batch [
Command.tryOfAsync loadUser () UserLoaded LoadError
Command.tryOfAsync loadSettings () SettingsLoaded LoadError
Command.ofShared CheckAuthStatus
]

Use Specific Message Types​

Create specific message types for different command results rather than reusing generic ones:

// Good
type Msg =
| UsersLoaded of User list
| SettingsLoaded of Settings
| ProfileLoaded of Profile

// Avoid
type Msg =
| DataLoaded of obj

This improves type safety and makes your code more maintainable.