Quick answer: Enable async loading with s.AsyncLoadingThreadEnabled=1, increase your world partition streaming distances so cells load before the player reaches them, and profile with stat streaming to identify oversized cells that need splitting.

Your open world looks fantastic in the editor, but the moment a player starts moving through it at speed, the game hitches every few seconds. Frame times spike from 16ms to 80ms or more, input feels sluggish, and the camera stutters. These hitches are almost always caused by level streaming — the process of loading and unloading chunks of the world as the player moves — happening synchronously on the game thread instead of in the background.

How World Partition Streaming Works

Unreal Engine 5’s World Partition system divides your persistent level into a grid of cells. Each cell contains the actors within its spatial bounds. As the player moves, cells within the streaming distance are loaded, and cells beyond it are unloaded. The streaming source is typically the player camera or pawn.

The problem arises when loading a cell takes longer than a single frame. If the engine decides a cell must be visible right now — because the player is already within its bounds — it will perform a synchronous flush, blocking the game thread until the cell is fully loaded. This is what causes the visible hitch.

The goal is to ensure cells are always loaded asynchronously, finishing their load before the player can see them. This requires a combination of wider streaming distances, async loading configuration, and keeping individual cell load times manageable.

Configuring Async Loading

First, verify that async loading is actually enabled. In your project’s DefaultEngine.ini or via console commands:

; DefaultEngine.ini
[/Script/Engine.StreamingSettings]
s.AsyncLoadingThreadEnabled=1
s.AsyncLoadingTimeLimit=5.0
s.PriorityAsyncLoadingExtraTime=15.0
s.LevelStreamingActorsUpdateTimeLimit=5.0
s.UnregisterComponentsTimeLimit=1.0

s.AsyncLoadingTimeLimit controls how many milliseconds per frame the async loading system is allowed to spend processing loaded packages. The default of 5ms is conservative. On hardware with headroom, you can increase this to 8–10ms to speed up loading without noticeably impacting framerate.

s.PriorityAsyncLoadingExtraTime gives additional time budget to high-priority loads (like cells close to the player). Increasing this helps when the player is moving quickly toward a cell boundary.

The critical thing to avoid is FlushAsyncLoading calls in your game code. Any Blueprint or C++ code that calls FlushAsyncLoading() will force the engine to finish all pending async loads synchronously, causing a massive hitch. Search your codebase for these calls:

// Search your C++ code for synchronous loading calls
// These are the main culprits:
FlushAsyncLoading();
LoadObject<T>();  // Synchronous - use async alternatives
StaticLoadObject();  // Synchronous

// Use these instead:
StreamableManager.RequestAsyncLoad();
LoadPackageAsync();

Tuning Streaming Distances

The streaming distance determines how far ahead of the player cells begin loading. If your cells take 2 seconds to load and the player moves at 20 meters per second, you need at least 40 meters of buffer beyond the visible range. In practice, add 50–100% more as a safety margin.

Configure streaming distances in the World Partition settings or per-actor using Data Layers:

Use stat streaming in-game to see real-time metrics: how many cells are loaded, pending, and the current async loading time budget usage. If you see cells constantly in the “pending” state when they should already be visible, your streaming distance is too tight.

Splitting Oversized Cells

Not all cells are equal. A cell containing a dense village with hundreds of static meshes, particle systems, and AI actors will take significantly longer to load than a cell with rolling hills and a few trees. Profile your cells to find the outliers.

Use Unreal Insights to capture a trace while the player moves through the world. Look at the async loading channel and identify which packages take the longest. Common offenders:

If a single cell consistently causes hitches, split it by reducing the grid cell size in that area (UE5 supports non-uniform grid sizes via HLOD setups) or manually distributing heavy actors across multiple cells using Data Layers.

HLOD and Distance-Based Simplification

Hierarchical Level of Detail (HLOD) is your most powerful tool for reducing streaming hitches. Instead of loading full-detail meshes for distant cells, HLOD generates simplified proxy meshes that represent entire cell contents at a distance. When the player approaches, the HLOD is replaced by the real actors.

Configure HLOD in World Partition settings:

; Ensure HLOD generation is enabled
; Build HLODs via: Tools > World Partition > Build HLODs

; In WorldPartitionRuntimeHash settings:
; - Set HLOD Layer for each grid level
; - Configure simplification settings:
;   Desired Bound Radius: 25600 (for LOD0 HLOD)
;   Transition Screen Size: 0.03

A well-configured HLOD setup means the player only ever sees proxy geometry for distant cells, and by the time they get close enough to need the real actors, async loading has had plenty of time to complete. This eliminates the most common source of streaming hitches — cells popping in at the last moment because they weren’t needed until the player was right on top of them.

Test your streaming setup with the player moving at maximum speed (vehicles, fast travel, mounted movement) in the worst-case direction — typically diagonal across cell boundaries, which triggers loading of the most cells simultaneously. If the game is smooth at maximum speed, it will be smooth at walking pace.

The trick isn’t making cells load faster — it’s making sure they start loading earlier.