UE5 Networking in 2026
Multiplayer in Unreal Engine 5 has matured significantly. The core replication framework remains server-authoritative (as it has been since Unreal Engine 3), but the tooling, online services integration, and network prediction systems have evolved.
This guide covers what you need to know to build multiplayer games in UE5 today — whether you're adding co-op to an existing project or building a multiplayer-first game.
Architecture Overview
The Server-Authoritative Model
UE5's networking is fundamentally server-authoritative:
- Clients send input to the server
- Server processes game logic and updates the world state
- Server replicates relevant state changes to each client
- Clients receive updates and display the result
This prevents cheating (clients can't directly modify game state) but introduces latency. The gap between player input and visual feedback is the core challenge of multiplayer game development.
Server Types
Dedicated Server:
- Headless process running only game logic
- No rendering overhead
- Players connect as remote clients
- Best for competitive games, MMOs, persistent worlds
- Requires server hosting infrastructure
Listen Server:
- One player acts as both host and server
- Host has zero latency (local authority)
- Other players connect to the host
- No hosting costs
- Best for co-op games, casual multiplayer, LAN play
Peer-to-Peer (via EOS relay):
- Clients communicate through a relay server
- No player needs to host
- Higher latency but NAT traversal is handled
- Good for small player counts (2-4 players)
For most indie games, Listen Server for co-op and Dedicated Server for competitive is the right architecture.
Replication Fundamentals
Replicating Actors
Mark an actor as replicated in its constructor:
AMyActor::AMyActor()
{
bReplicates = true;
bAlwaysRelevant = false; // Only replicate to nearby clients
NetUpdateFrequency = 30.0f; // Updates per second
MinNetUpdateFrequency = 2.0f; // Minimum when nothing changes
}
Replicating Properties
Use UPROPERTY(Replicated) or UPROPERTY(ReplicatedUsing=OnRep_FunctionName):
// Header
UPROPERTY(ReplicatedUsing = OnRep_Health)
float Health;
UFUNCTION()
void OnRep_Health();
// Source
void AMyCharacter::GetLifetimeReplicatedProps(TArray<FLifetimeProperty>& OutLifetimeProps) const
{
Super::GetLifetimeReplicatedProps(OutLifetimeProps);
DOREPLIFETIME(AMyCharacter, Health);
// Or with conditions:
DOREPLIFETIME_CONDITION(AMyCharacter, Ammo, COND_OwnerOnly);
DOREPLIFETIME_CONDITION(AMyCharacter, TeamId, COND_InitialOnly);
}
void AMyCharacter::OnRep_Health()
{
// Update health bar UI on clients
UpdateHealthBar(Health);
}
Replication Conditions
| Condition | Description | Use Case |
|---|---|---|
COND_None | Always replicate | Shared state (health, position) |
COND_OwnerOnly | Only to owning client | Ammo, inventory, private stats |
COND_SkipOwner | Everyone except owner | States the owner already knows |
COND_InitialOnly | Once on spawn | Team ID, character class, appearance |
COND_SimulatedOnly | Simulated proxies only | Cosmetic-only state |
COND_AutonomousOnly | Autonomous proxy only | Client-specific correction data |
RPCs (Remote Procedure Calls)
RPCs let you call functions across the network:
// Client → Server (request)
UFUNCTION(Server, Reliable, WithValidation)
void Server_RequestFire(FVector AimLocation);
// Server → All Clients (broadcast)
UFUNCTION(NetMulticast, Unreliable)
void Multicast_PlayFireEffect(FVector MuzzleLocation, FRotator MuzzleRotation);
// Server → Owning Client only
UFUNCTION(Client, Reliable)
void Client_NotifyHitConfirmed(float DamageDealt);
Reliable vs Unreliable:
- Reliable: Guaranteed delivery, ordered. Use for important gameplay events (damage, pickups, state changes)
- Unreliable: May be dropped, faster. Use for cosmetic effects (particles, sounds, animations)
The Authority Pattern
Always check authority before modifying game state:
void AMyCharacter::TakeDamage(float Damage, AActor* DamageCauser)
{
// Only the server should modify health
if (!HasAuthority()) return;
Health = FMath::Max(0.0f, Health - Damage);
if (Health <= 0.0f)
{
// Server handles death
HandleDeath(DamageCauser);
}
// Health replicates to clients via OnRep_Health
}
Epic Online Services (EOS)
EOS provides free backend services for multiplayer games:
What EOS Provides
- Matchmaking: Find and connect players
- Lobbies: Pre-game rooms for party formation
- P2P Relay: NAT traversal for peer-to-peer connections
- Voice Chat: Built-in voice communication
- Achievements: Cross-platform achievement tracking
- Leaderboards: Global and friends leaderboards
- Player Sanctions: Anti-cheat and moderation tools
- Analytics: Player behavior tracking
EOS Integration
UE5 includes the Online Subsystem EOS plugin:
- Enable the Online Subsystem EOS plugin
- Configure in
DefaultEngine.ini:
[OnlineSubsystem]
DefaultPlatformService=EOS
[OnlineSubsystemEOS]
ProductId=your_product_id
SandboxId=your_sandbox_id
DeploymentId=your_deployment_id
ClientId=your_client_id
ClientSecret=your_client_secret
- Register your product at dev.epicgames.com
Session Management with EOS
// Create a session
void UMyGameInstance::CreateOnlineSession(int32 MaxPlayers)
{
IOnlineSubsystem* OnlineSub = Online::GetSubsystem(GetWorld());
IOnlineSessionPtr Sessions = OnlineSub->GetSessionInterface();
FOnlineSessionSettings SessionSettings;
SessionSettings.NumPublicConnections = MaxPlayers;
SessionSettings.bShouldAdvertise = true;
SessionSettings.bUsesPresence = true;
SessionSettings.bUseLobbiesIfAvailable = true;
Sessions->CreateSession(0, NAME_GameSession, SessionSettings);
}
Common Multiplayer Patterns
Movement Prediction
UE5's Character Movement Component has built-in client prediction:
- Client predicts movement locally (feels responsive)
- Server simulates the same movement
- If results differ, server sends a correction
- Client smoothly interpolates to the corrected position
For custom movement (vehicles, flying, swimming), you may need to implement your own prediction using FSavedMove_Character subclasses.
Inventory Replication
For inventories, replicate the container, not individual items:
USTRUCT()
struct FInventorySlot
{
GENERATED_BODY()
UPROPERTY()
int32 ItemId = 0;
UPROPERTY()
int32 Quantity = 0;
};
UPROPERTY(Replicated)
TArray<FInventorySlot> InventorySlots;
Use DOREPLIFETIME with fast array serialization for large inventories to minimize bandwidth.
Lag Compensation
For hit-scan weapons, the server needs to "rewind" the world to the client's perspective at the time they fired:
- Client sends fire request with timestamp
- Server rewinds hitboxes to that timestamp
- Server performs the trace against rewound positions
- Server applies damage based on rewound result
UE5 doesn't provide lag compensation out of the box — you'll need to implement it for competitive shooters.
Spawn Ownership
When spawning actors on the server:
// Spawn with owner (for replication ownership)
FActorSpawnParameters SpawnParams;
SpawnParams.Owner = PlayerController;
SpawnParams.Instigator = PlayerCharacter;
AMyProjectile* Projectile = GetWorld()->SpawnActor<AMyProjectile>(
ProjectileClass, SpawnLocation, SpawnRotation, SpawnParams);
The owner determines which client has autonomous proxy status (can predict and send RPCs).
Bandwidth Optimization
Property Quantization
Reduce bandwidth by quantizing replicated values:
// Instead of replicating a full float rotation
UPROPERTY(Replicated)
FRotator AimRotation; // 12 bytes per update
// Use compressed rotation
UPROPERTY(Replicated)
uint8 CompressedYaw; // 1 byte, 256 discrete values (1.4° precision)
Relevancy
Not every actor needs to replicate to every client. Use relevancy to limit replication:
bAlwaysRelevant = false+NetCullDistanceSquaredfor distance-based relevancy- Override
IsNetRelevantFor()for custom relevancy logic - Use
bOnlyRelevantToOwnerfor player-specific actors
Net Update Frequency
Tune NetUpdateFrequency per actor type:
- Player characters: 60-100 Hz
- Projectiles: 30-60 Hz
- AI characters: 15-30 Hz
- Static interactables: 2-10 Hz
- Ambient objects: 1-2 Hz
Testing Multiplayer
PIE Settings
In Editor Preferences → Play:
- Set Number of Players to 2-4
- Enable Run Dedicated Server to test with a headless server
- Use Additional Launch Parameters for network simulation
Network Emulation
Enable packet loss and latency simulation:
NetEmulationPktLag=100 // 100ms added latency
NetEmulationPktLoss=5 // 5% packet loss
NetEmulationPktIncomingLoss=2 // 2% incoming loss
Always test with simulated lag. Your game will work perfectly on localhost but break with real-world latency.
Common Testing Scenarios
- Player joins mid-game (late join state sync)
- Player disconnects and reconnects
- Host migration (listen server host leaves)
- High latency (200ms+) gameplay
- Packet loss (10%+) during critical events
- Two players interact with the same object simultaneously
- Rapid-fire RPCs (input spam)
Practical Advice for Indie Teams
Start multiplayer from day one: Retrofitting multiplayer into a single-player codebase is 5-10x harder than building with it from the start. Even if you're "just adding co-op later," structure your code for server authority from the beginning.
Use listen servers for co-op: You don't need dedicated server infrastructure for 2-4 player co-op. Listen servers with EOS relay handle NAT traversal and keep costs at zero.
Test with real latency early: Your game feels great on localhost. Test with 100ms latency on day one, not the week before launch.
Keep your replicated property count low: Every replicated property costs bandwidth. Replicate state, not events. Replicate results, not intermediate calculations.
Multiplayer development is complex, but UE5 provides solid foundations. Build on them, test relentlessly, and ship games that people can play together.