Spring Sale: 30% off bundles with SPRINGBUNDLE or 15% off individual products with SPRING15 — ends Apr 15

StraySparkStraySpark
ProductsFree AssetsDocsBlogGamesAbout
StraySparkStraySpark

Game Studio & UE5 Tool Developers. Building professional-grade tools for the Unreal Engine community.

Products

  • Complete Toolkit (Bundle)
  • Procedural Placement Tool
  • Cinematic Spline Tool
  • Blueprint Template Library
  • DetailForge
  • UltraWire
  • Unreal MCP Server
  • Blender MCP Server
  • Godot MCP Server

Resources

  • Free Assets
  • Documentation
  • Blog
  • Changelog
  • Roadmap
  • FAQ
  • Contact

Legal

  • Privacy Policy
  • Terms of Service

© 2026 StraySpark. All rights reserved.

Back to Blog
tutorial
StraySparkApril 11, 20265 min read
World Partition Deep Dive: Streaming, Data Layers, and HLOD for Massive Open Worlds 
Unreal EngineWorld PartitionOpen WorldStreamingOptimization

Beyond the Basics of World Partition

World Partition is UE5's answer to the fundamental problem of open-world development: how do you build a world that's too large to fit in memory? The basic concept is straightforward — divide the world into cells, load cells near the player, unload the rest. But shipping a smooth, hitch-free open world requires mastering the system's deeper features.

This guide goes beyond the setup tutorial and into the decisions that determine whether your open world streams smoothly or stutters every time the player crosses a cell boundary.

Runtime Streaming Architecture

How Cell Loading Works

World Partition divides your level into a grid of streaming cells. Each cell contains the actors within its spatial bounds. At runtime, the Streaming Source (usually the player camera) determines which cells to load.

The loading pipeline:

Player moves → Streaming Source updates position
→ World Partition calculates required cells
→ New cells enter loading range → Async load begins
→ Cell assets load from disk → Actors spawn
→ Old cells exit loading range → Actors destroyed → Memory freed

This happens continuously, every frame. The challenge is making it invisible to the player.

Cell Size Strategy

Cell size is the most impactful configuration decision:

Cell SizeProsConsBest For
Small (64m)Fine-grained streaming, low memory per cellMore cells to manage, more loading operationsDense urban environments
Medium (128m)Good balance of granularity and overhead—Most open-world games
Large (256m)Fewer cells, less management overheadHigher memory per cell, coarser loadingSparse landscapes

The rule: Cell size should be small enough that loading one cell doesn't cause a memory spike, but large enough that cells don't churn (load/unload rapidly) during normal movement.

Loading Range Configuration

The loading range determines how far ahead cells are loaded:

; In WorldPartition settings
RuntimeGrid.CellSize=12800      ; 128 meters
RuntimeGrid.LoadingRange=25600   ; 256 meters (2x cell size)

Loading range should be at least 2x your cell size to ensure cells are fully loaded before the player reaches them. For fast-moving gameplay (vehicles, flying), increase to 3-4x.

Per-Actor Loading Range Overrides

Not every actor needs the same loading range:

// In actor constructor or Blueprint defaults
bOverride_WorldPartitionLoadingRange = true;
WorldPartitionLoadingRange = 50000.f; // 500 meters for large landmarks

Use overrides for:

  • Landmarks: Load from far away so players see distant structures
  • Audio sources: Extend range for distant ambient sounds
  • Gameplay triggers: Ensure triggers load before players can reach them
  • Small props: Reduce range to save memory

Data Layers: Selective Content Loading

Data Layers let you organize actors into logical groups that can be loaded or unloaded independently of spatial streaming.

Use Cases

Game state layers: Load different actor sets based on story progression:

  • DL_Village_Peaceful: NPC merchants, children playing, market stalls
  • DL_Village_Attacked: Burning buildings, enemy soldiers, debris
  • DL_Village_Rebuilt: Construction scaffolding, new buildings, celebration decorations

Time of day layers:

  • DL_Daytime: Daytime NPCs, open shops, farmers
  • DL_Nighttime: Night guards, closed shops, nocturnal creatures

Difficulty layers:

  • DL_Normal: Standard enemy placement
  • DL_Hard: Additional enemies, removed health pickups

Creating and Managing Data Layers

// Activate a data layer at runtime
UWorldPartitionSubsystem* WPSubsystem = GetWorld()->GetSubsystem<UWorldPartitionSubsystem>();

FName LayerName = "DL_Village_Attacked";
WPSubsystem->SetDataLayerRuntimeState(
    UDataLayerAsset::FindDataLayerByName(LayerName),
    EDataLayerRuntimeState::Activated
);

// Deactivate the peaceful layer
WPSubsystem->SetDataLayerRuntimeState(
    UDataLayerAsset::FindDataLayerByName("DL_Village_Peaceful"),
    EDataLayerRuntimeState::Unloaded
);

Data Layer Best Practices

  • Don't overlap spatial content: Two Data Layers shouldn't place different actors in the same physical space (creates visual popping)
  • Transition gracefully: Fade to black or use a loading screen when swapping major Data Layers
  • Keep layer count reasonable: Each active layer adds streaming overhead. 5-10 active layers is manageable; 50 is problematic
  • Test layer combinations: Ensure all valid layer combinations work together without conflicts

HLOD: Hierarchical Level of Detail

HLOD provides simplified representations of distant content. Instead of loading full-detail actors for cells far from the player, HLOD shows merged, simplified geometry.

The HLOD Pipeline

Full Detail (near) ←→ HLOD Layer 0 (medium) ←→ HLOD Layer 1 (far) ←→ HLOD Layer 2 (very far)
   All actors           Merged meshes           Simplified clusters       Impostors/billboards
   Full materials       Simplified materials    Atlas textures            Single quads
   Full collision       No collision            No collision              No collision

HLOD Layer Configuration

Configure HLOD layers in the World Partition settings:

HLOD Layer 0 (Medium distance):

  • Merge nearby static meshes into single draw calls
  • Simplify materials (remove parallax, reduce texture resolution)
  • Cell size: 2-4x the runtime grid cell size
  • Loading range: 4-8x runtime grid loading range

HLOD Layer 1 (Far distance):

  • Aggressive mesh simplification (10-20% of original triangle count)
  • Single atlas texture per cluster
  • Cell size: 8-16x runtime grid cell size
  • Loading range: 16-32x runtime grid loading range

HLOD Layer 2 (Very far / skyline):

  • Impostor billboards or extremely simplified geometry
  • Minimal material complexity
  • For landmarks and large structures only

Building HLODs

HLODs are generated offline using the World Partition HLOD builder:

# Command line HLOD build
UnrealEditor-Cmd.exe YourProject.uproject -run=WorldPartitionHLODBuilder -Map=/Game/Maps/OpenWorld

Or from the editor:

  1. Open World Partition settings
  2. Navigate to the HLOD section
  3. Click "Build HLODs"

Build time scales with world size. Budget 30 minutes to several hours for large worlds.

HLOD with Nanite

For Nanite-enabled meshes, HLOD takes a different approach:

  • Nanite handles LOD automatically per-mesh
  • HLOD still provides draw call merging (fewer instances at distance)
  • The combination gives you automatic LOD + merged drawing = optimal distance rendering
  • Set HLOD to focus on instance merging rather than mesh simplification for Nanite content

Multi-User Editing with One File Per Actor

The Problem with Traditional Levels

In a traditional .umap level, the entire level is one binary file. Two people editing different corners of the same level creates merge conflicts that can't be resolved.

World Partition's Solution

World Partition stores each actor in its own file (One File Per Actor — OFPA). This means:

  • Artist A edits a building in the north → modifies only that building's actor files
  • Artist B places trees in the south → modifies only those tree actor files
  • No conflict. Both changes merge cleanly.

Setting Up Multi-User Workflows

  1. Enable One File Per Actor: This is automatic with World Partition
  2. Use Perforce or Git: Both support file-level locking for binary assets
  3. Actor locking: The editor shows lock status — locked actors are read-only for other users
  4. Exclusive checkout: For actors that absolutely shouldn't be edited simultaneously

Workflow Tips

  • Divide work by region: Each artist owns a geographic area
  • Use Data Layers for team features: One team's gameplay layer, another team's visual layer
  • Communicate about shared areas: Town centers, dungeons, and boss arenas need coordination
  • Regular integration: Merge everyone's changes daily to catch issues early

Performance Optimization

Streaming Budgets

Set per-frame streaming budgets to prevent hitches:

; Limit how many cells can load per frame
wp.Runtime.MaxStreamingCellsPerFrame=2

; Limit actor spawn count per frame
wp.Runtime.MaxActorsToSpawnPerFrame=10

; Memory budget for streamed content
wp.Runtime.MemoryBudgetMB=2048

Avoiding Streaming Hitches

Common causes of streaming hitches and their fixes:

Large actors straddling cell boundaries: Actor loads when any of its cells load, potentially loading expensive content earlier than expected. Fix: Keep large actors within single cells, or use the bIsSpatiallyLoaded flag for always-loaded actors.

Slow disk I/O: Asset loading is ultimately disk-bound. Fix: Use NVMe storage for development and target platforms. Compress pak files appropriately. Use async loading with priority queues.

Too many actors per cell: Loading a cell spawns all its actors. If one cell has 500 actors, that's a spawn hitch. Fix: Reduce actor density per cell, or use HISM/foliage instances instead of individual actors.

Streaming source prediction: The default streaming source is reactive. By the time the player reaches a cell, it should already be loaded. Fix: Implement predictive streaming based on player velocity and heading.

Profiling World Partition

stat WorldPartition    // Streaming state overview
stat Streaming         // Asset streaming statistics
wp.Runtime.ToggleDrawRuntimeHash2D  // Visualize cell grid in viewport
wp.Runtime.ToggleDrawStreamingSource // Show streaming source and range

Practical Checklist

Before shipping your World Partition world:

  • Cell size tuned for your content density and movement speed
  • Loading ranges set per-actor-type (landmarks far, props near)
  • Data Layers configured for story/state variations
  • HLOD layers built and tested (visual quality at all distances)
  • Streaming budgets set to prevent per-frame hitches
  • Tested on minimum spec hardware with slowest storage
  • Multi-user workflow validated (if team project)
  • No actors at cell boundaries causing premature loading
  • Navigation mesh builds correctly with streamed content
  • Save/load correctly preserves streamed world state

World Partition is the foundation of UE5 open-world development. Master it, and your worlds can be as large as your ambition allows — without compromising the player experience.

Tags

Unreal EngineWorld PartitionOpen WorldStreamingOptimization

Continue Reading

tutorial

Motion Matching and Control Rig in UE5: The Future of Character Animation

Read more
tutorial

CI/CD Build Pipelines for UE5: Unreal Horde, GitHub Actions, and Jenkins

Read more
tutorial

Getting Started with UE5 PCG Framework: Build Your First Procedural World

Read more
All posts