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:
- Grid cell size: Smaller cells (e.g., 128m × 128m) load faster but create more streaming overhead. Larger cells (512m × 512m) reduce overhead but take longer per load. For most open world games, 256m is a good starting point.
- Loading range: Set this to at least 2× the grid cell size beyond the player’s maximum view distance. If the player can see 500 meters and cells are 256m, set the loading range to at least 750m.
- Per-actor overrides: Heavy actors (large meshes, complex Blueprints) can have their own streaming distance set higher so they begin loading even earlier.
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:
- Foliage-heavy cells: Hierarchical Instanced Static Meshes with thousands of instances. Consider reducing foliage density or using impostor billboards at distance.
- Blueprint-heavy cells: Complex Blueprints with many components that run construction scripts during load. Move heavy initialization to
BeginPlayinstead of the construction script. - Large texture references: Actors referencing 4K textures that aren’t using texture streaming. Enable virtual textures or reduce texture quality for distant objects.
- Audio banks: Sound cues referencing large audio files. Use the audio streaming system rather than loading entire banks into memory.
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.