Verse Wiki — the Verse handbook for Blueprint authors
Advanced · EXTRA

The Model Beneath the Flow of Time: Concurrency Is Control Flow on the Time Axis

In Blueprints, making several things happen at once means assembling Event Dispatchers, timers and Timelines by hand; Verse can make "at once" a keyword. Epic's official Unreal Fest 2023 talk explains why: promote "time flow" to a language concept on equal footing with "control flow." This page distills the core model from the talk and the official docs, plus a small execution-order experiment you can reason through by hand.

1. Control Flow vs Time Flow

Epic's official talk “Verse Concurrency — Time Flow: Everything, Everywhere in UEFN, All at Once” offers a lovely analogy: normally when you wire nodes, Branch / ForEach decide which nodes get executed — that's control flow; Verse's concurrency nodes (spawn / race / sync / branch / rush) decide when nodes execute — they are Branch / ForEach on the time axis. In Blueprints, making several things happen at once usually means piecing it together from Event Dispatchers, Timelines, and Delays, each minding its own corner; in Verse, time flow grows straight out of the language's bones — a first-class citizen as built-in and ready to use as a Branch.

Underneath this design sits cooperative scheduling: only one task executes at any given moment, and a task yields control only voluntarily, at its suspension points (Sleep, Await, and friends) — there is no preemption, so nothing can barge in and cut another task off mid-stride. No preemption means no data fights of the "someone jumped the queue while my value was half-changed" kind — so nothing needs locking; and no callbacks nested inside callbacks either: "wait for A, then wait for B" is just two nodes wired one after the other down the exec line. The <suspends> you learned in Lesson 23 is exactly the admission ticket this system issues to every function.

2. Two Iron Laws: Sprint on Start, Resume in Order

Iron law one: any new exec line forked by a concurrency node runs on the spot, in one breath, up to its first node that waits — only then does control return to the line that started it. In other words, the new line doesn't "queue up to run later"; it sprints immediately until it slams into its first Sleep (Delay) / Await. Watch this little experiment:

order_demo_device.verse
using { /Fortnite.com/Devices }
using { /Verse.org/Simulation }
using { /UnrealEngine.com/Temporary/Diagnostics }

order_demo_device := class(creative_device):

    Talker()<suspends>:void =
        Print("1. Talker is born and sprints to the first suspension point")
        Sleep(0.0)
        Print("3. Next frame, Talker wakes up")

    OnBegin<override>()<suspends>:void =
        spawn{ Talker() }
        Print("2. Only after spawn does the main line continue")

The output order is always 1 → 2 → 3: the instant spawn forks Talker off, Talker runs in one breath up to Sleep(0.0) (the Delay) and suspends; only then does control return to OnBegin (Event BeginPlay) to print line 2; on the next simulation frame, Talker wakes and prints line 3. Once "sprint on start" clicks, a whole class of seemingly mystical ordering puzzles can be reasoned out in a single step.

Iron law two: resume order is deterministic. The official Signal API docs are explicit: the lines woken by an event (think an Event Dispatcher's Signal / Call) resume one by one, in the order they originally suspended, and each runs until its own next node-that-waits before the next line gets a turn. Determinism means the same input always produces the same execution order — concurrency bugs reproduce reliably, instead of becoming a Schrödinger-style disaster of "worked yesterday, crashes today."

3. Cancellation Happens at Suspension Points Too

The talk's other puzzle piece is cancellation: every concurrency node corresponds to a task line, and when that line is canceled — most typically by losing next lesson's race — it is not snipped on the spot at whatever node it happens to be on; it runs on to its next node that waits and exits quietly there. In other words, nodes that wait aren't just where control gets yielded — they're also the checkpoint where a line's life is handed over. This design guarantees that the stretch between two waiting nodes always runs to completion, never leaving a half-finished mess behind — exactly where the predictability of "structured concurrency" comes from, and Lesson 24 leans on it again and again.

Put the three pieces together: every line yields only at nodes that wait, resume order is deterministic, and cancellation happens at those nodes too — Verse's time-flow model boils down to "everything is bounded by the nodes that wait." When wiring async graphs like these, keep your eyes on every Sleep (Delay) and Await, and you can read the whole graph's footwork along the time axis like a story.

In a function that can wait, you place a spawn{ Talker() } (forking a new line); the very next node is a Print String "main line". Inside Talker, the first node is a Print String "born" and the second is a Sleep(0.0) (Delay). Which prints first?

Sources

This page draws on Epic's official talk and documentation: