home / blog / performance
Published: 2 May 2026 11 min read performance
What I learned after a DOTS/ECS migration

What I learned after a DOTS/ECS migration

We moved part of a production project to ECS and frame time dropped by 34%. But the win did not come from where we expected.

Why we migrated

We had close to 3,000 moving entities on screen at once, and the same thing sat at the top of the profiler every time: the sum of MonoBehaviour.Update calls and the cache misses they caused.

The goal was never to move everything to ECS. We moved only what was crowded, uniform and numerous: projectiles, swarm units, particle logic.

The real win is memory layout

Everybody talks about Burst and SIMD. In our measurements the difference did not come from there; it came from the data sitting contiguously in memory.

The gap between reading 3,000 objects individually from the heap and reading 3,000 positions sequentially from one array produced up to an 8× time difference for identical maths.

The cost of a hybrid architecture

Because we did not go fully ECS, we had to bridge two worlds. That bridge turned out to be far more work than we had budgeted for.

My advice: draw the line clearly up front. Which systems live on the ECS side, which stay classic, and is the data flow between them one-way — decide all of this before writing code.

MoveSystem.cs
[BurstCompile] public partial struct MoveSystem : ISystem { [BurstCompile] public void OnUpdate(ref SystemState state) { float dt = SystemAPI.Time.DeltaTime; foreach (var (xf, vel) in SystemAPI.Query<RefRW<LocalTransform>, RefRO<Velocity>>()) { xf.ValueRW.Position += vel.ValueRO.Value * dt; } } }
csharpMoveSystem.cs

When it is not worth it

If your entity count does not pass a few hundred, the complexity ECS brings outweighs the gain. If the team does not know ECS, count the learning cost too.

I use a simple threshold to decide: if more than 500 objects run the same behaviour and update every frame, it is worth moving.

← All posts