Reference Verse

branch: Fire-and-Forget Concurrency in Verse

Sometimes you want a task to run in the background — a platform that fades back in after a delay, a warning countdown, a cosmetic effect — while your main game logic keeps rolling. The `branch` expression is Verse's built-in tool for exactly this: fire-and-forget concurrency inside a structured context.

Updated
The code on this reference page is provided as-is and did not pass the latest compile check — treat the examples as a starting point and verify in your project.
Watch the Knotbranch_fire_and_forget in ~90 seconds.

Overview

branch is not a placed device — it's a core Verse expression for concurrency. When execution hits a branch block, Verse immediately kicks off that block as an independent background task and then, without waiting, continues to the very next line. The branched work runs on its own; your main flow never pauses for it.

The game problem it solves: async work that shouldn't block. Imagine a disappearing platform. A player steps on a trigger, the platform hides instantly, and then — after a random delay — it reappears. If you called Sleep() directly in your event handler, the whole handler would stall for the duration of the sleep. With branch, you launch the "wait then reappear" task in the background and immediately return, keeping the trigger responsive for the next player.

Reach for branch when:

  • You want to start a delayed or looping task and keep going.
  • You don't need the task's result (fire-and-forget).
  • You'd otherwise be tempted to spawn a function just to avoid blocking.

Because branch calls async code, it must appear inside a <suspends> context (like OnBegin or a <suspends> method). The branched body can call things like Sleep() and device methods such as a prop's Show()/Hide() or a Patchwork tile's Trigger().

API Reference

(API surface could not be resolved for this device.)

Walkthrough

Let's build a disappearing platform. A trigger device fires when a player steps on the platform prop. The platform hides instantly, and a background branch task waits a random amount of time, then shows it again — all without blocking the trigger for other players.

using { /Fortnite.com/Devices }
using { /Fortnite.com/Devices/Patchwork }
using { /Verse.org/Simulation }
using { /Verse.org/Random }

disappearing_platform_device := class(creative_device):

    # The trigger the player steps on (a Patchwork trigger with TriggeredEvent).
    @editable
    StepTrigger : trigger_device = trigger_device{}

    # The platform prop that disappears and reappears.
    @editable
    Platform : creative_prop = creative_prop{}

    # Shortest reappear delay in seconds.
    @editable
    MinDelay : float = 2.0

    # Longest reappear delay in seconds.
    @editable
    MaxDelay : float = 5.0

    OnBegin<override>()<suspends>:void =
        # Wire the trigger's event to our handler.
        StepTrigger.TriggeredEvent.Subscribe(OnStepped)

    # Handler runs when a player steps on the trigger.
    OnStepped(Agent : agent):void =
        # Hide the platform right away.
        Platform.Hide()
        # Fire-and-forget: launch the reappear task in the background.
        # The handler returns immediately; the wait happens off to the side.
        branch:
            ReappearAfterDelay()

    # Async task: wait a random time, then bring the platform back.
    ReappearAfterDelay()<suspends>:void =
        Delay := GetRandomFloat(MinDelay, MaxDelay)
        Sleep(Delay)
        Platform.Show()

Line by line:

  • The using lines pull in creative_device/trigger_device/creative_prop (Devices), the Patchwork trigger event, Sleep (Simulation) and GetRandomFloat (Random).
  • @editable fields expose the trigger, the platform prop, and two delay tuning floats in UEFN's Details panel. You must declare devices as fields to call them — a bare Trigger.Method() fails with 'Unknown identifier'.
  • OnBegin is our <suspends> entry point. We subscribe the TriggeredEvent to the OnStepped method. Subscription is done here, once.
  • OnStepped(Agent : agent) is the event handler method at class scope. It calls Platform.Hide() immediately.
  • The branch: block launches ReappearAfterDelay() as a background task. OnStepped then finishes right away — it does not wait for the sleep.
  • ReappearAfterDelay is <suspends> because it calls Sleep. It picks a random delay with GetRandomFloat, waits, then calls Platform.Show() to restore the platform.

Because the wait is branched off, ten players can all trip the trigger and each hide/reappear cycle runs independently without ever freezing the handler.

Common patterns

Pattern 1 — Branch a Patchwork tile Trigger after a delay

Here we use the Patchwork Trigger() method (which removes the associated tile) fired from a background task, so the main flow isn't held up by the delay.

using { /Fortnite.com/Devices }
using { /Fortnite.com/Devices/Patchwork }
using { /Verse.org/Simulation }

delayed_tile_device := class(creative_device):

    @editable
    Tile : trigger_device = trigger_device{}

    @editable
    ArmDelay : float = 3.0

    OnBegin<override>()<suspends>:void =
        # Kick off an arming task, then keep running other setup.
        branch:
            ArmAndFire()

    ArmAndFire()<suspends>:void =
        Sleep(ArmDelay)
        # Trigger the Patchwork tile after the delay.
        Tile.Trigger()

Pattern 2 — Branch a looping cosmetic while gameplay continues

branch shines for background loops. Here a prop pulses (hide/show) forever without ever blocking OnBegin.

using { /Fortnite.com/Devices }
using { /Verse.org/Simulation }

blinking_prop_device := class(creative_device):

    @editable
    Beacon : creative_prop = creative_prop{}

    @editable
    BlinkRate : float = 1.0

    OnBegin<override>()<suspends>:void =
        # Launch the endless blink loop in the background.
        branch:
            BlinkForever()
        # This line runs immediately, the loop keeps blinking on its own.
        Beacon.Show()

    BlinkForever()<suspends>:void =
        loop:
            Beacon.Hide()
            Sleep(BlinkRate)
            Beacon.Show()
            Sleep(BlinkRate)

Pattern 3 — Fire multiple independent branches from one event

Each branch is its own task, so you can start several at once and they all run in parallel.

using { /Fortnite.com/Devices }
using { /Fortnite.com/Devices/Patchwork }
using { /Verse.org/Simulation }

multi_branch_device := class(creative_device):

    @editable
    StartTrigger : trigger_device = trigger_device{}

    @editable
    PropA : creative_prop = creative_prop{}

    @editable
    PropB : creative_prop = creative_prop{}

    OnBegin<override>()<suspends>:void =
        StartTrigger.TriggeredEvent.Subscribe(OnStart)

    OnStart(Agent : agent):void =
        # Two independent background tasks with different timings.
        branch:
            HideThenShow(PropA, 2.0)
        branch:
            HideThenShow(PropB, 4.0)

    HideThenShow(Prop : creative_prop, Wait : float)<suspends>:void =
        Prop.Hide()
        Sleep(Wait)
        Prop.Show()

Gotchas

  • branch needs a <suspends> context. You can only write branch where async is allowed — inside OnBegin<override>()<suspends> or another <suspends> method. A plain non-suspends event handler like OnStepped(Agent : agent):void can still contain a branch block, but the code the branch calls must itself be <suspends>.
  • Fire-and-forget means no result. branch does not return a value and you can't await it. If you need the result of the async work, use spawn/race/sync structured concurrency instead.
  • The branched task is tied to its scope. When the surrounding structured context ends, outstanding branched tasks may be cancelled. For endless work started in OnBegin, that's typically fine because OnBegin's scope lives with the device.
  • Declare devices as @editable fields. Calling Platform.Hide() only works because Platform is a field on the creative_device class. A bare reference fails with 'Unknown identifier'.
  • No int↔float auto-conversion. GetRandomFloat returns a float; Sleep takes a float. Keep your delay values as floats (2.0, not 2).
  • Unwrap ?agent from listenable events. A listenable(agent) hands the handler a plain agent, but a listenable(?agent) gives you ?agent — unwrap it with if (A := Agent?): before use. The Patchwork TriggeredEvent is listenable(agent), so no unwrap is needed there.

Build your own lesson with branch_fire_and_forget

Generate a personalized, step-by-step lesson plan built around this object — grounded in this exact reference and our compile-verified knowledge base.

Build a lesson →