Migrating from UniTask to OnityTask

Use this page to replace UniTask 2.5.11 with OnityTask (Onity.Unity.Async) by renaming. PlayerLoop timings and timers, composition, cancellation helpers, completion sources, thread switches, Unity operations, coroutines, lifecycle and message triggers, UnityEvent and uGUI events, async LINQ streams, channels and async reactive properties keep UniTask’s shapes under Onity names. The remaining gaps are listed on the comparison page; UniTask’s External integrations (Addressables, DOTween, TextMeshPro) are out of scope. After the renames, read the behavior differences and, when you come from Onity 0.5, the upgrade notes.

Like UniTask, async OnityTask methods do not flow AsyncLocal<T> values across awaits by default. Set OnityTask.FlowExecutionContext = true before any async Onity method starts to opt in; on Unity’s Mono class library that costs an execution-context allocation per suspension only once a thread has stored an AsyncLocal<T> value.

For a task-oriented introduction, read Async with OnityTask. For the measured Release Player results and the feature coverage, read OnityTask vs UniTask.

Pooled-task safety: cancelable frame waits, timed waits, delays, predicates, AsyncOperation.AsOnityTask() and suspended async methods return single-consumer values, as in UniTask. Await each value once. If several consumers must share the operation, call Preserve() once before sharing its returned OnityTask, or call AsTask() once and share the returned Task. In Play, a frame wait without a cancelable token and Yield() are stateless and may be awaited by any number of consumers.

On this page: Namespaces and assembly references, API mapping, Behavior differences, Upgrading from Onity 0.5, Scene loading, Unity operations and web requests, Reactive and messaging bridges, Fire and forget, Guidance.

Namespaces and assembly references

using Onity.Unity.Async;            // OnityTask, timings, composition, streams, channels, UI events
using Onity.Unity.Async.Triggers;   // lifecycle and MonoBehaviour message triggers

Unity assembly references are not transitive. An assembly definition that calls Onity.Unity.Async extension methods must reference Onity.Reactive as well as Onity.Unity, and Onity.Messaging when it uses the messaging bridges: several extension names (AsOnityAsyncEnumerable, BindTo, ToOnityTask, WaitAsync) have overloads whose receiver or parameters are Onity.Reactive types, and the compiler reports CS0012 when it has to examine one without the reference. Code that touches Unit (OnityAsyncEnumerable.EveryUpdate(), AsUnitTask(), IOnityObservable<Unit>) also needs Onity.Core, where Unit lives. Add Onity.Unity.UGUI and UnityEngine.UI for the uGUI extensions.

API mapping

UniTask names map one to one unless a row says otherwise. A replacement of UniTask with OnityTask, UniTaskAsyncEnumerable with OnityAsyncEnumerable and IUniTask... with IOnity... covers most code.

Core

UniTask 2.5.11 Onity
UniTask, UniTask<T>, async UniTask OnityTask, OnityTask<T>, async OnityTask
UniTaskVoid, async UniTaskVoid OnityTaskVoid, async OnityTaskVoid
UniTask.CompletedTask, FromResult, FromException(<T>), FromCanceled(<T>) same names on OnityTask
UniTask.Create, Defer, Never, Lazy same names on OnityTask; AsyncLazy(<T>) is OnityAsyncLazy(<T>), task.ToAsyncLazy()
UniTask.Void, UniTask.Action, UniTask.UnityAction OnityTask.Void, OnityTask.Action, OnityTask.UnityAction
task.Status, UniTaskStatus, UniTaskStatusExtensions task.Status, OnityTaskStatus (Pending, Succeeded, Faulted, Canceled), OnityTaskStatusExtensions
task.Preserve() task.Preserve()
task.AsUniTask() on UniTask<T>, implicit UniTask<T> to UniTask task.AsOnityTask(), implicit OnityTask<T> to OnityTask
task.AsAsyncUnitUniTask(), AsyncUnit task.AsUnitTask(), Onity.Core.Unit

PlayerLoop timing

UniTask 2.5.11 Onity
PlayerLoopTiming.Update OnityPlayerLoopTiming.UpdateBegin
PlayerLoopTiming.FixedUpdate OnityPlayerLoopTiming.FixedUpdateBegin
Any other PlayerLoopTiming.X OnityPlayerLoopTiming.X
UniTask.Yield(), Yield(timing) (YieldAwaitable) OnityTask.Yield(), Yield(timing) (OnityYieldAwaitable)
UniTask.Yield(ct, cancelImmediately), Yield(timing, ct, cancelImmediately) same shapes
UniTask.NextFrame(timing, ct, cancelImmediately) same shapes
UniTask.DelayFrame(count, timing, ct, cancelImmediately) OnityTask.DelayFrame(...), or Onity’s DelayFrames(count, ct)
UniTask.WaitForFixedUpdate(ct, cancelImmediately) same; NextFixedFrame(ct) resumes earlier, right after the fixed scripts
UniTask.WaitForEndOfFrame(this, ct, cancelImmediately) same, or OnityTask.WaitForEndOfFrame(ct)
UniTask.Post(action, timing) OnityTask.Post(action, timing)
PlayerLoopHelper.AddAction, AddContinuation, IPlayerLoopItem OnityTaskPlayerLoop.AddAction, AddContinuation, IOnityPlayerLoopItem
PlayerLoopHelper.Initialize(ref loop, injectTimings) OnityTaskPlayerLoop.Initialize(params timings) or InitializeAll(); Onity patches the current loop and installs other timings on first use
PlayerLoopHelper.IsInjectedUniTaskPlayerLoop(), DumpCurrentPlayerLoop() OnityTaskPlayerLoop.IsInjected(timing), DumpCurrentPlayerLoop()
PlayerLoopHelper.IsMainThread, MainThreadId, UnitySynchronizationContext same names on OnityTaskPlayerLoop

Timed waits, timers and timeouts

UniTask 2.5.11 Onity
UniTask.Delay(int millisecondsDelay, ...) OnityTask.Delay(TimeSpan.FromMilliseconds(ms), ...); no integer overload, because OnityTask.Delay(2) means two seconds
UniTask.Delay(TimeSpan, bool ignoreTimeScale, timing, ct, cancelImmediately) same shape
UniTask.Delay(TimeSpan, DelayType, timing, ct, cancelImmediately), DelayType Delay(TimeSpan, OnityDelayType, ...), OnityDelayType
UniTask.WaitForSeconds(float or int, ...) OnityTask.WaitForSeconds(...)
UniTask.WaitUntil / WaitWhile (predicate or state, timing, ct, cancelImmediately) same shapes
UniTask.WaitUntilCanceled(ct, timing, completeImmediately) same
UniTask.WaitUntilValueChanged(target, monitor, timing, comparer, ct, cancelImmediately) same
PlayerLoopTimer.Create, StartNew, Restart, Stop, Dispose OnityPlayerLoopTimer
cts.CancelAfterSlim(TimeSpan or int, DelayType, timing) same with OnityDelayType
TimeoutController OnityTimeoutController
task.Timeout(TimeSpan, DelayType, timing, cts), TimeoutWithoutException(...) same with OnityDelayType; Onity also has Timeout(float seconds, bool useUnscaledTime = true)

Threading

UniTask 2.5.11 Onity
UniTask.SwitchToMainThread(ct), SwitchToMainThread(timing, ct) same
await using (UniTask.ReturnToMainThread()) await using (OnityTask.ReturnToMainThread())
UniTask.SwitchToThreadPool() OnityTask.SwitchToThreadPool(ct); WebGL Players reject it
UniTask.SwitchToTaskPool(), SwitchToSynchronizationContext, ReturnToSynchronizationContext, ReturnToCurrentSynchronizationContext same
UniTask.RunOnThreadPool(action, configureAwait, ct) and its 8 shapes OnityTask.RunOnThreadPool(action, returnToMainThread, ct) and the same shapes; returnToMainThread: true (the default) resumes on Unity’s main thread

Composition

UniTask 2.5.11 Onity
UniTask.WhenAll(params or IEnumerable) same
var (a, b) = await UniTask.WhenAll(t1, t2) (2 to 15 typed arguments) same; same-type arguments also return a tuple
UniTask.WhenAny(t1, t2, ...) with mixed types same: (int winArgumentIndex, T1 result1, ...)
UniTask.WhenAny(UniTask<T> left, UniTask right) same: (bool hasResultLeft, T result)
UniTask.WhenAny(params UniTask<T>[]) same: (int winnerIndex, T result)
UniTask.WhenEach(...), WhenEachResult<T> OnityTask.WhenEach(...), OnityWhenEachResult<T>
await (t1, t2), await tasks same
enumerable.Select(x => SomeAsync(x)) same (OnityEnumerableAsyncExtensions)

Cancellation

UniTask 2.5.11 Onity
this.GetCancellationTokenOnDestroy() (MonoBehaviour, GameObject, Component) same
cts.RegisterRaiseCancelOnDestroy(component or gameObject) same
task.AttachExternalCancellation(ct), task.SuppressCancellationThrow() same
task.ToCancellationToken(), ToCancellationToken(linkToken) same
ct.ToUniTask() ct.ToOnityTask()
ct.WaitUntilCanceled(), disposable.AddTo(ct), ct.RegisterWithoutCaptureExecutionContext(...), ex.IsOperationCanceledException() same
CancellationTokenEqualityComparer.Default OnityCancellationTokenEqualityComparer.Default

Completion sources

UniTask 2.5.11 Onity
UniTaskCompletionSource, UniTaskCompletionSource<T> OnityTaskCompletionSource, OnityTaskCompletionSource<T>
AutoResetUniTaskCompletionSource(<T>) (Create, CreateFromCanceled, CreateFromException, CreateCompleted, CreateFromResult, TrySet*) OnityAutoResetTaskCompletionSource(<T>); the out tokens are int

Unity operations

UniTask 2.5.11 Onity
asyncOperation.ToUniTask(progress, timing, ct, cancelImmediately), await asyncOperation asyncOperation.AsOnityTask(onProgress or IProgress<float>, ct); polled at Update, no timing or cancelImmediately overloads
await resourceRequest, await assetBundleRequest (asset) request.AsAssetOnityTask() / AsAssetOnityTask<T>()
assetBundleRequest.AwaitForAllAssets() same
await assetBundleCreateRequest request.AsAssetBundleOnityTask()
await request.SendWebRequest() operation.AsWebRequestOnityTask(), or OnityTask.Send(request, onProgress, ct)
UnityWebRequestException OnityUnityWebRequestException
await asyncGpuReadbackRequest request.AsOnityTask(ct)
await instantiateOperation operation.AsInstancesOnityTask() (Unity 2022.3.20+ or Unity 6)
awaitable.AsUniTask() awaitable.AsOnityTask() (Unity 2023.1 or newer)
await jobHandle, jobHandle.WaitAsync(timing, ct), jobHandle.ToUniTask(timing) await handle, handle.WaitAsync(timing, ct), handle.AsOnityTask()
Progress.Create<T>, Progress.CreateOnlyValueChanged<T> OnityProgress.Create<T>, OnityProgress.CreateOnlyValueChanged<T>
await SceneManager.LoadSceneAsync("Game").ToUniTask(...) await OnityTask.LoadScene("Game", onProgress, ct) (see Scene loading)

Coroutines

UniTask 2.5.11 Onity
UniTask.ToCoroutine(factory), task.ToCoroutine(resultHandler, exceptionHandler) same
await enumerator, enumerator.WithCancellation(ct) same
enumerator.ToUniTask(timing, ct), enumerator.ToUniTask(monoBehaviour) enumerator.ToOnityTask(timing, ct), enumerator.ToOnityTask(monoBehaviour)
this.StartAsyncCoroutine(token => ...) same

Triggers and UI events

UniTask 2.5.11 Onity
using Cysharp.Threading.Tasks.Triggers; using Onity.Unity.Async.Triggers;
this.GetAsyncXTrigger(), XAsync(ct), GetXAsyncHandler(ct), IAsyncXHandler same pattern: GetAsync<Name>Trigger(), <Message>Async(ct), Get<Message>AsyncHandler(ct), IOnityAsync<Message>Handler
AwakeAsync, StartAsync, OnDestroyAsync, GetAsyncDestroyTrigger same
AsyncTriggerBase<T>, AsyncTriggerHandler<T>, TriggerEvent<T>, ITriggerHandler<T> OnityAsyncTriggerBase<T>, OnityAsyncTriggerHandler<T>, OnityTriggerEvent<T>, IOnityTriggerHandler<T>
unityEvent.OnInvokeAsync(ct), OnInvokeAsAsyncEnumerable(ct), GetAsyncEventHandler(ct) same
uGUI button.OnClickAsync(ct), slider.OnValueChangedAsync(ct), inputField.OnEndEditAsync(ct), EventSystems triggers same, in the optional Onity.Unity.UGUI assembly
stream.BindTo(text), BindTo(selectable), BindTo(target, action[, ct]) same
TextMeshPro BindTo(TMP_Text) not provided; use stream.BindTo(label, (l, value) => l.text = value.ToString(), ct)

UI Toolkit has no UniTask counterpart; Onity adds button.OnClickAsync(ct), element.OnEventAsync<TEvent>(ct), field.OnValueChangedAsync(ct), their stream forms and BindTo(TextElement).

Async streams

UniTask 2.5.11 Onity
IUniTaskAsyncEnumerable<T>, IUniTaskAsyncEnumerator<T> IOnityAsyncEnumerable<T>, IOnityAsyncEnumerator<T>
UniTaskAsyncEnumerable.Create, Empty, Return, Range, Repeat, Never, Throw, Merge OnityAsyncEnumerable.X
UniTaskAsyncEnumerable.EveryUpdate, Timer, Interval, TimerFrame, IntervalFrame, EveryValueChanged OnityAsyncEnumerable.X
IAsyncWriter<T> IOnityAsyncWriter<T>
LINQ operators (Select, Where, Buffer, CombineLatest, GroupBy, SumAsync, ToListAsync, …) same names (OnityAsyncEnumerableLinq)
Subscribe, SubscribeAwait same
Publish(), Queue(), IConnectableUniTaskAsyncEnumerable<T> same, IOnityConnectableAsyncEnumerable<T>
IUniTaskOrderedAsyncEnumerable<T> IOnityOrderedAsyncEnumerable<T>
ToLookupAsync returning ILookup / IGrouping IOnityLookup / IOnityGrouping
enumerable.ToUniTaskAsyncEnumerable() (IEnumerable<T>, Task<T>, UniTask<T>) ToOnityAsyncEnumerable()
observable.ToUniTaskAsyncEnumerable() (IObservable<T>) observable.AsOnityAsyncEnumerable(capacity) on an IOnityObservable<T>
stream.ToObservable() stream.AsObservable() (an IOnityObservable<T>)

Channels and async reactive properties

UniTask 2.5.11 Onity
Channel.CreateSingleConsumerUnbounded<T>() OnityChannel.CreateUnbounded<T>(); Onity adds CreateBounded<T>(capacity) with waiting WriteAsync
reader.ReadAsync, TryRead, ReadAllAsync, WaitToReadAsync, Completion same
writer.TryWrite, TryComplete, Complete same
ChannelClosedException OnityChannelClosedException
AsyncReactiveProperty<T>, ReadOnlyAsyncReactiveProperty<T> and their interfaces OnityAsyncReactiveProperty<T>, OnityReadOnlyAsyncReactiveProperty<T>, IOnityAsyncReactiveProperty<T>, IOnityReadOnlyAsyncReactiveProperty<T>
stream.ToReadOnlyAsyncReactiveProperty(ct) same

Scheduler, diagnostics and interop

UniTask 2.5.11 Onity
UniTaskScheduler.UnobservedTaskException, PropagateOperationCanceledException, UnobservedExceptionWriteLogType, DispatchUnityMainThread OnityTaskScheduler.X
task.Forget(), Forget(handler, handleExceptionOnMainThread) same
TaskPool.SetMaxPoolSize(n) OnityTask.SourcePoolCapacity = n, plus RunnerPoolCapacity for async-method runners
TaskTracker and the UniTask Tracker window OnityTaskTracker and Onity/Tools/Task Tracker
task.ContinueWith(...), Unwrap() same
task.AsTask(), task.AsUniTask(useCurrentSynchronizationContext) on a Task AsTask(), task.AsOnityTask(useCurrentSynchronizationContext)
task.AsValueTask(), valueTask.AsUniTask() AsValueTask(), valueTask.AsOnityTask()
observable.ToUniTask(useFirstValue, ct) observable.ToOnityTask(useFirstValue, ct) on an IOnityObservable<T>, or FirstOnityTask(ct)
task.ToObservable() same
await asyncPublisher.PublishAsync(message, ct).AsTask() (MessagePipe) await asyncPublisher.PublishOnityTask(message, ct)

Behavior differences

Timing and frame waits:

  • Onity’s default frame waits (NextFrame, DelayFrames, Yield()) and the timed overloads at their default timing resume at Onity’s Update node, after every MonoBehaviour Update. UniTask’s default PlayerLoopTiming.Update runs before the scripts; use OnityPlayerLoopTiming.UpdateBegin where that order matters. The float-seconds Delay(seconds) and the token-only WaitUntil are ticked by a hidden runner component during the Update scripts.
  • In Play, frame waits without a cancelable token are stateless and may be awaited by any number of consumers; UniTask’s are single-consumer. Waits with a token are single-consumer in both.
  • WaitForFixedUpdate() resumes at LastFixedUpdate, after the physics step, like UniTask and Unity’s coroutine instruction; Onity’s NextFixedFrame() resumes earlier, right after the fixed scripts.
  • DelayFrame(0) waits for the next drain, as in UniTask; Onity’s DelayFrames(0) completes immediately.
  • Onity’s timings other than Update, FixedUpdate and LateUpdate install on first use; there is no InjectPlayerLoopTimings mask to configure.
  • Onity’s pools keep at most 128 runners per async method and 256 sources per source type by default; UniTask keeps everything. Raise OnityTask.RunnerPoolCapacity / SourcePoolCapacity for methods that run in large bursts (see Bursts and pool retention).

Streams and operators:

  • CombineLatest yields one result per arriving item and queues results that arrive between moves, where UniTask overwrites the pending one; a source that ends without an item ends the stream.
  • Publish() buffers every item for each registered enumerator, where UniTask drops items while an enumerator is not waiting, and disposing the connection ends the enumerators normally, where UniTask reports an OperationCanceledException.
  • Join and GroupJoin never match a null key (System.Linq semantics).
  • ToLookupAsync returns IOnityLookup, not System.Linq.ILookup.
  • Numeric aggregates follow System.Linq where UniTask’s template differs: a nullable Sum starts at zero, Average of an empty non-nullable stream faults with InvalidOperationException, and Average accumulates int/long in long and float in double.
  • Index-only SelectAwait(Func<T, int, OnityTask<R>>) and WhereAwait(Func<T, int, OnityTask<bool>>) are not provided; use SelectAwaitWithCancellation((item, index, token) => ...). Onity’s SelectAwait, WhereAwait and ForEachAsync also accept a token-taking delegate, and ForEachAsync(Func<T, OnityTask>) exists so that an async lambda never becomes an async void action.
  • SkipUntilCanceled: the enumeration token cancels a pending move, where UniTask opens the stream.
  • observable.AsOnityAsyncEnumerable(capacity) needs an explicit capacity, faults on overflow after draining the accepted values, and reports cancellation as a faulted OperationCanceledException.

Triggers, events and adapters:

  • A one-shot UnityEvent handler unregisters at its first invocation (UniTask waits until the result is read), and disposing a handler cancels its pending wait.
  • Trigger waits with a pre-canceled token, or started after the handler was disposed, canceled or destroyed, complete as canceled, where UniTask leaves them pending or throws. AwakeAsync on an inactive object completes when it is activated (UniTask only cancels it on destroy).
  • cts.RegisterRaiseCancelOnDestroy(...) ignores a source that was disposed before the object is destroyed.
  • The Unity operation adapters report progress 1 on their already-completed fast path, and AsyncGPUReadbackRequest.AsOnityTask() also checks hasError there.
  • OnityAsyncReactiveProperty<T> rejects a set from a continuation of its own publication before storing the value (UniTask stores it, then throws).

Context and faults:

  • Flow is off by default, as in UniTask; OnityTask.FlowExecutionContext = true is an opt-in. While flow is on, code before an async method’s first await runs without a copy-on-write scope, so an AsyncLocal<T> write there can leak to the caller (UniTask behaves the same when it flows).
  • Forget() without a handler, async OnityTaskVoid faults and unobserved completion-source faults go to OnityTaskScheduler, which drops OperationCanceledException by default, as in UniTask.

Upgrading from Onity 0.5

These 0.6.0 changes can break code written against Onity 0.5:

  • OnityTask.FlowExecutionContext defaults to false. Code that relies on AsyncLocal<T> values (logging scopes, correlation IDs, ambient services) surviving an await inside an async Onity method must set it to true once at startup, before any async Onity method runs.
  • OnityTask.WhenAll(a, b, ...) with 2 to 15 separate typed arguments of the same type now returns a tuple instead of T[]. Pass an array for T[]: OnityTask.WhenAll(new[] { a, b }).
  • OnityTask.WhenAny<T>(OnityTask<T>, OnityTask<T>) returning (int winnerIndex, T result) was removed. Two typed arguments bind to the mixed overload, which returns (int winArgumentIndex, T result1, T result2); pass an array for (winnerIndex, result).
  • OnityTask.Yield() and Yield(timing) return OnityYieldAwaitable. It converts implicitly to OnityTask, but extension methods on OnityTask need .ToOnityTask() first (OnityTask.Yield().ToOnityTask().Timeout(1f)). Yield(default) is ambiguous; pass a named argument (Yield(cancellationToken: ct)).
  • A null literal passed to Select, Where, SelectAwait, WhereAwait or ForEachAsync on an async stream is ambiguous; cast it to the delegate type. The same applies to AsOnityTask(null, ct) on an AsyncOperation and to new OnityChannelClosedException(null).
  • In Play, the default frame waits run on Onity’s PlayerLoop nodes, after the Update scripts, and are no longer canceled by destroying the legacy runner.
  • Forget() without a handler no longer logs OperationCanceledException; set OnityTaskScheduler.PropagateOperationCanceledException = true to report it.
  • Release into a pool that BindPooledFactory(prefab, ...) created throws ObjectDisposedException after the pool’s scope ended, because the scope now disposes that pool.
  • Assemblies that call Onity.Unity.Async extensions need an Onity.Reactive reference (see Namespaces and assembly references).

Scene loading

OnityTask.LoadScene, LoadSceneAdditive, UnloadScene and ActivateScene replace SceneManager.LoadSceneAsync(...).ToUniTask(...) (fragment):

await OnityTask.LoadScene("Gameplay", progress => ShowProgress(progress), ct);
await OnityTask.LoadSceneAdditive("GameplayUI", ct);

For delayed activation, LoadSceneAsync("Gameplay", activateOnLoad: false, cancellationToken: ct) returns the AsyncOperation. After Unity starts the load, the token cannot cancel it, so always activate the returned operation with OnityTask.ActivateScene(operation, CancellationToken.None), including when a later wait for input or a fade is canceled. See Scene loading in the guide.

Unity operations and web requests

Resources.LoadAsync<TextAsset>(path).AsAssetOnityTask<TextAsset>(cancellationToken: ct) returns the asset; the Unity operations table lists every adapter. OnityTask.Send awaits a UnityWebRequest that you own and dispose, and GetJson<TResponse> / PostJson<TRequest, TResponse> wrap JsonUtility DTOs (fragment):

using UnityWebRequest request = UnityWebRequest.Get(url);
UnityWebRequest completed = await OnityTask.Send(request, ct);
string json = completed.downloadHandler.text;

SaveResponse response = await OnityTask.PostJson<SaveRequest, SaveResponse>(url, saveRequest, ct);

A failed request throws OnityUnityWebRequestException (UniTask’s UnityWebRequestException). Use your own serializer around OnityTask.Send when a payload needs features JsonUtility does not support. See Web requests.

Reactive and messaging bridges

UniTask has no reactive property or message bus to await. Onity’s ReactiveProperty<T> (Onity.Reactive) has native waits, any IOnityObservable<T> converts to a task, and the async message channels (Onity.Messaging) publish and subscribe with OnityTask (fragment; the subscription field is disposed with its owner):

int wave = await m_wave.WaitUntilAsync(value => value >= 3, ct);          // ReactiveProperty<int>; completes at once when already true
int report = await m_remainingEnemies.FirstOnityTask(ct);                 // Subject<int>, or any IOnityObservable<T>

await m_savedPublisher.PublishOnityTask(new InventorySaved(1), ct);       // IAsyncPublisher<InventorySaved>
m_subscription = m_savedSubscriber.SubscribeOnityTask(                    // IAsyncSubscriber<InventorySaved>
    async (message, token) => await ShowSavedAsync(message.Slot, token));

subscriber.ReceiveAsync(ct), ReceiveAllAsync(capacity, overflow) and SubscribeQueued(handler, capacity, lifetimeToken) add one-shot receives, buffered streams and queues with backpressure. See Reactive and messaging bridges, Reactive and Events and Messaging.

Fire and forget

OnityTask.LoadScene("Gameplay").Forget(Debug.LogException);

Without a handler, faults go to OnityTaskScheduler, which logs them and drops OperationCanceledException by default. While OnityTaskTracker.IsEnabled is true (the default), forgotten tasks are visible in Onity/Tools/Task Tracker. See Fire and forget.

Guidance

  • Use OnityTask for Unity-facing gameplay async flows.
  • Use normal Task for plain .NET service APIs when that is already the project contract.
  • Keep ValueTask in engine-free low-level messaging paths where it avoids allocation and the API is already shipped.
  • Tie async work to its owner: GetCancellationTokenOnDestroy() for a component, the scope token (IOnityScopeLifetime, GetScopeCancellationToken()) for a service.
  • Do not add UniTask as a runtime dependency just for frame waits, scene loads, web requests, or reactive awaits.

See also