Mobile optimization in Unity usually feels like trying to pack a king-sized mattress into a suitcase — frustrating, cramped, and if you force it, something is going to snap. In our studio, we've stopped treating optimization as a "final polish" phase. It's the heartbeat of the project. If your game runs at 60 FPS but turns a player's phone into a hand warmer, they're going to hit uninstall before they finish the first level.
Here's the human side of the 10 techniques we swear by — and why we refuse to ship without them.
1. The Move to URP — Because Legacy is Heavy
We made the switch to the Universal Render Pipeline because the old Built-in renderer feels like trying to run a marathon in work boots. It's clunky and carries way too much baggage for a smartphone.
The reason we chose URP comes down to one thing: the SRP Batcher. It's like having a personal assistant who organises all your messy tasks into a single efficient list. It lets us push beautiful post-processing — soft Bloom, cinematic Color Grading — without the device's frame rate falling off a cliff. It's the foundation that makes our games look great on a $200 Android and a $1,200 iPhone alike.
What is URP?
URP (Universal Render Pipeline) is Unity's modern, lightweight rendering system designed to work well across all platforms — especially mobile. Unlike the older Built-in renderer, URP includes the SRP Batcher which significantly reduces the CPU cost of drawing objects to screen, and gives you access to performant post-processing effects that would otherwise tank frame rate on a phone.
2. Aggressive Texture Compression (ASTC)
Textures are the biggest memory hogs in any mobile game. We don't just import an image and call it a day — we obsess over ASTC compression.
Ever played a mobile game that randomly crashes after ten minutes? That's usually RAM running out of breath. ASTC keeps images crisp while shrinking file size significantly. We want the game to look high-res, but we also want it to stay open when the player gets a text message. It's about being a good neighbour to the phone's operating system.
What is ASTC compression?
ASTC (Adaptive Scalable Texture Compression) is a GPU texture format supported on all modern Android and iOS devices. It compresses image data so textures take up far less RAM at runtime — without visibly degrading quality. It's the standard choice for mobile because it offers the best balance of quality, file size, and broad hardware support.
3. The Magic of Baked Lighting
Real-time shadows are a luxury mobile hardware simply can't afford. We disable them almost entirely and rely on baked lightmaps instead.
Baking lights is like painting the shadows directly onto the floor. At runtime, the phone doesn't have to do any math — it just shows a picture. And it actually looks better. You get warm, bounced light and soft corners that real-time lighting on mobile struggles to hit. It's the secret to making a scene feel cosy instead of flat.
What is a lightmap?
A lightmap is a pre-rendered texture that stores lighting and shadow information for a scene. Unity calculates it once during the build process and bakes it onto surfaces. At runtime the phone just reads that image — no shadow calculations happen at all, saving significant GPU work every single frame.
4. Intelligent Batching — The Conversation Saver
Every draw call is a conversation between the CPU and GPU. If you have 500 rocks in a scene, that's 500 individual "hey, draw this" messages. That's exhausting for a phone processor.
We use Static Batching and GPU Instancing to group those conversations. Now the CPU just says: "draw all these rocks at once." We do this because it prevents the stutter players feel when they turn the camera — that subtle wrongness they feel but can't name. It keeps gameplay buttery smooth even when the screen is packed.
What is a draw call?
A draw call is a command from the CPU telling the GPU to render an object. Every unique mesh, material, or object that isn't batched costs one draw call. On mobile, keeping draw calls under 100 per frame is a common target. Static Batching merges objects that never move into one, and GPU Instancing lets the GPU draw hundreds of identical objects in a single call.
5. Physics: Simplicity Over Ultra-Realism
Nobody playing a mobile game needs per-pixel collision physics. We swap complex Mesh Colliders for simple boxes and spheres wherever we can.
We also bump the Fixed Timestep from 0.02 to 0.04. This tells the phone to check physics 25 times a second instead of 50. Your players won't feel the difference — but the phone's processor will breathe a quiet sigh of relief. It's about choosing where to spend your performance budget wisely.
What is Fixed Timestep in Unity?
Fixed Timestep controls how often Unity runs its physics simulation. The default value of 0.02 means 50 physics updates per second. Raising it to 0.04 halves that to 25 updates per second — which is imperceptible to players in most genres but meaningfully reduces CPU load, especially on low-end Android devices.
6. The Multi-Canvas UI Strategy
Unity's UI system has a frustrating quirk: if a single tiny XP bar moves, Unity tries to re-draw every button and panel on screen. It's incredibly wasteful.
We split our UI into Static (stuff that stays still) and Dynamic (stuff that moves or animates). This way the phone only works on what's actually changing. It sounds small, but in a game with a busy HUD it's the difference between a smooth UI and a laggy mess that quietly kills the experience.
Why does Unity's UI rebuild the whole canvas?
Unity's UI system marks an entire Canvas as "dirty" whenever any element inside it changes — even a single pixel of animation. This triggers a full layout and mesh rebuild for every element on that canvas. Splitting UI elements into separate Canvases means only the Canvas containing the changed element gets rebuilt, leaving everything else untouched.
Optimization is invisible art. When it's done right, nobody notices it. When it's missing, everyone feels it — even if they can't explain why they hit uninstall.
7. Caching Everything — Stop the Searching
Using GetComponent inside an Update() loop is like searching your entire house for your keys every single morning. It's a waste of time your phone doesn't have.
We have a strict "cache it in Awake()" rule across the studio. Find the reference once, store it in a variable, use it forever. When you stop making the CPU hunt for references 60 times a second, the whole game feels more responsive — in a way players notice even if they can't identify why.
Why is GetComponent in Update() expensive?
GetComponent searches through all the components attached to a GameObject every time it is called. In an Update() loop running 60 times per second, that's 60 searches per frame for every call. Caching the result in Awake() or Start() means the search happens exactly once — the component reference is stored in memory and accessed directly from then on.
8. Hunting Down Overdraw
Overdraw is when you stack too many transparent things — smoke, glass, UI layers — on top of each other. The GPU has to paint the same pixel over and over again.
This is the number one cause of thermal throttling: where a phone gets so hot it slows its own processor down to cool off. We use Unity's Overdraw View regularly to simplify particle effects and transparent materials. We want the game to stay fast for an hour-long session, not just the first five minutes.
What is thermal throttling?
When a mobile device overheats, the OS forcibly reduces CPU and GPU clock speeds to lower the temperature. The result is frame rate drops, input lag, and battery drain — appearing only after the player has been enjoying your game for a while. Overdraw from stacked transparent layers is the most common trigger in mobile games.
9. Addressables: Loading On-Demand
You shouldn't force a phone to carry the weight of your entire game in RAM. We use the Addressables System to load and unload assets as the player moves through the game.
It's like a revolving door for memory — load the level you're in, dump the one you just left. This keeps the game lightweight and actually lets us use higher-quality assets, because we're not trying to fit everything into memory at once. As a bonus, it makes the initial download significantly faster.
What is the Addressables system?
Unity's Addressables system lets you tag assets with an address (a string key) and load or unload them at runtime on demand, rather than loading everything upfront. This gives you precise control over what's in memory at any given moment — essential on mobile where RAM is limited and crashes from memory pressure are one of the top reasons for bad app store reviews.
10. ScriptableObjects as the Backbone
Instead of every enemy carrying its own heavy list of stats, we use ScriptableObjects to store shared data in one central place. If you have 100 enemies, they all just point to one file.
It's cleaner, faster, and makes balancing so much easier. Change the health value in one place and the whole game updates. It's as much about keeping the developer sane as it is about keeping the game performant — and those two things are more connected than most people realise.
What is a ScriptableObject?
A ScriptableObject is a Unity data container that lives as an asset in your project, independent of any scene or GameObject. Instead of each enemy MonoBehaviour holding its own copy of stats data, every instance references the same shared ScriptableObject. This reduces memory usage, eliminates data duplication, and makes runtime data changes and balancing dramatically simpler.
We don't optimize because we like following rules. We optimize because we love the players — we want them to get lost in the world we built, without a lag spike reminding them they're just running on a piece of hardware.
Optimization is the invisible craft that makes a game feel premium. Not a checklist you run at the end — a habit you build from day one.