First of all, you should know that Factorio is one of the few game projects where the technical requirements are so unusual that writing a custom engine actually made sense. The core of Factorio is written in C++, and the developers are using a lot of low-level optimization tricks to make that humongous number of entities moving around and doing stuff in a large-scale factory work as well as it does. Their development blog (linking to the beginning) is a really interesting read for every game developer.
That being said, it should be possible to create a similar game experience in Unity, as long as you are willing to make a couple concessions to the size of factories and the number of items moving around them.
But you will still have to do a couple optimizations, because representing every single item as a full-fledged gameObject will create far too much overhead.
The entity-component-system architecture would be great for this use-case, but it is still in beta and we already established in the comments that you don't feel brave enough to face it in its current state. Which I fully understand after doing a couple experiments in it myself.
But we can still apply a couple of its principles in the regular Unity architecture.
Logical representation
For example, instead of each item being represented with a gameObject with a transform, a rigidbody and a collider, we can represent it with a plain old C# object and have each conveyor belt own a couple of those. And the conveyor belts themselves could also be represented by plain old C# objects owned by a global BeltSystem
MonoBehaviour
. This system could store all the belts in a two-dimensional array with tile indices mapping to array indices. That makes it very easy to acquire the belt on a specific tile and then the items currently on that belt.
Visual representation
But you still need to render all those belts and items.
The belts don't move (although they might be animated) and are arranged in a grid, which means that using a Tilemap is likely the most optimized way of rendering them.
But for the items you are going to need SpriteRenderers, which require GameObjects. But you only need those for those items which are actually on the screen. So it might be possible to decouple the logical representation of items from their visual representation by having an object with a SpriteRenderer following the position of each item currently on a belt which is on-screen.
But Instantiate
ing and Destroy
ing objects frequently also causes performance issues due to the garbage and memory fragmentation they cause. A good way to handle this problem could be to use an object pool of objects with SpriteRenderers attached. When a belt or items is on-screen, you request a render-object from the object pool. When the item is destroyed or moves off-screen, you return that render-object back to the pool.
I wish you the best of luck with your project. You are going to need it!