A product that feels instant on office fibre in Kampala can be genuinely unusable on a 3G connection upcountry, or on a shared connection at a busy school during peak hours. These are the concrete budgets and techniques we hold every build to, not vague "make it fast" advice.
Set an actual byte budget, not a vibe
We target a total page weight — HTML, CSS, JavaScript, images, fonts, everything — of well under 1MB for a first load, and closer to 300–500KB where the audience is mostly mobile. That number becomes a real constraint the whole team designs against, not an afterthought discovered when a client complains the site is slow.
Images are almost always the biggest cost
Serve modern formats (WebP or AVIF) with sizes matched to where the image is actually displayed — a 2MB photo shrunk visually to 300 pixels wide in CSS still costs 2MB to download. Lazy-load anything below the first screen, and always set explicit width and height so the page doesn't visibly jump around as images arrive.
Self-host fonts and limit the weights you load
Pulling four font weights from an external font service adds a DNS lookup, a connection, and a render-blocking wait on a slow network — before a single word of your content appears. We self-host a small number of font files (usually two or three weights, not the full family) directly from our own server, with `font-display: swap` so text remains readable while the custom font finishes loading.
Question every script before you ship it
Every analytics tag, chat widget and "helpful" third-party script is a separate network request and a chunk of code the browser has to download and run before the page feels responsive — and on a weak connection, that tax is paid in full seconds, not milliseconds. We default to no JavaScript framework at all for content-led sites; where interactivity is genuinely needed, hand-written, minimal script beats a large general-purpose library almost every time.
Design offline behaviour on purpose, not as a patch
For anything involving data entry — field reporting, sales capture, inventory — assume the connection will drop mid-task, because it will. Store submissions locally first and sync in the background when a connection reappears, with a visible, honest indicator of sync status so users trust the tool instead of re-submitting out of anxiety that it didn't save.
Cache aggressively, and cache the right things
Static assets — CSS, JavaScript, images, fonts — should carry long cache lifetimes so a returning visitor re-downloads almost nothing. Combined with server-side compression, a well-cached repeat visit on the same weak connection can be five to ten times faster than the first load, which matters enormously for a tool people are meant to use daily.
Why we hold ourselves to this
A beautiful, fast site that only works well on the connection it was designed on isn't fast — it's fast in a lab. Every website and mobile app we ship gets tested against a deliberately throttled connection before launch, because that's closer to the reality most of our users are actually in.