The Benchmark Nobody Talks About
Performance budgets are usually set against a 4G connection in London or San Francisco. But if your users are in Accra, Nairobi, Lagos, or Kumasi, the real benchmark is a 3G signal that drops to EDGE every time someone walks into a concrete building. A 200 KB JavaScript bundle that loads in 1.2 seconds on a fibre connection can take 8–12 seconds on a congested mobile network — and that is on a good day.
Building for low bandwidth is not a downgrade. It is a discipline. And Next.js, with the right configuration, is one of the best frameworks available for doing it correctly.
Understand What You Are Actually Sending
Before touching a single config file, profile what your app ships. Use the Next.js Bundle Analyzer to get a clear picture:
# Install and configure
npm install @next/bundle-analyzer
# next.config.js
const withBundleAnalyzer = require('@next/bundle-analyzer')({
enabled: process.env.ANALYZE === 'true',
});
module.exports = withBundleAnalyzer({});
# Run analysis
ANALYZE=true npm run build
The visual output routinely reveals the real culprits: a date-picker library at 180 KB, a full icon set where three icons are used, or a charting library loaded on every page even though only the dashboard needs it. Fix these before anything else. No amount of caching saves a bloated initial payload.
Lazy Load Everything That Is Not Immediately Visible
Next.js ships next/dynamic for component-level code splitting. The rule of thumb for low-bandwidth builds: if a component is not visible in the first viewport on a 375px screen, it should not be in the initial bundle.
import dynamic from 'next/dynamic';
const HeavyChart = dynamic(() => import('../components/HeavyChart'), {
loading: () => <p>Loading chart...</p>,
ssr: false,
});
Setting ssr: false is deliberate here. For interactive, data-heavy components like charts, skipping server-side rendering avoids shipping unused hydration code on the initial HTML response. Apply the same pattern to modals, off-canvas menus, rich text editors, and map components.
For images, next/image is non-negotiable. It automatically serves WebP or AVIF where the browser supports it, resizes to the requested display size, and defers loading for off-screen images. On a 3G connection, switching from a 900 KB JPEG to a 90 KB AVIF at the correct dimensions is the single most impactful change most projects can make.
Aggressive, Layered Caching
Bandwidth conservation is not only about what you send on the first visit — it is about what you do not send on the second, third, and tenth visit.
HTTP Cache Headers
Configure Cache-Control headers in next.config.js for static assets. Next.js already hashes JS and CSS filenames at build time, which means you can safely set long-lived caches:
async headers() {
return [
{
source: '/_next/static/:path*',
headers: [
{ key: 'Cache-Control', value: 'public, max-age=31536000, immutable' },
],
},
];
},
For API routes and page responses, use stale-while-revalidate to serve cached content instantly while refreshing in the background. Users on slow connections get a response in milliseconds rather than waiting on a round trip.
Incremental Static Regeneration (ISR)
ISR is one of Next.js's most underrated features for bandwidth-constrained environments. By pre-rendering pages at the CDN edge and revalidating on a schedule, you eliminate server round trips entirely for the majority of users. A news feed, a product listing, or a pricing page has no business hitting an origin server on every request.
export async function getStaticProps() {
const data = await fetchData();
return {
props: { data },
revalidate: 60, // Regenerate at most once per minute
};
}
Offline-First With Service Workers
A user on a matatu in Nairobi does not have a continuous connection. They have bursts of connectivity separated by dead zones. An offline-first PWA treats connectivity as an enhancement, not a requirement.
Use the next-pwa package (backed by Workbox) to add a production-ready Service Worker to your Next.js app with minimal configuration. The key strategy decisions:
- Cache-first for fonts, icons, and static shell assets. Serve from cache immediately; never wait on the network for these.
- Network-first with fallback for API data. Try the network; if it fails or times out (set a timeout of 3–4 seconds for 3G parity), serve the last cached response.
- Background sync for write operations. If a user submits a form while offline, queue the request and replay it when connectivity returns.
A lightweight offline fallback page — a simple HTML shell that acknowledges the connection issue and shows cached data where possible — makes the difference between an app that feels broken and one that feels resilient.
Font and Third-Party Script Discipline
Google Fonts loaded via a standard <link> tag adds a render-blocking cross-origin request. Use next/font instead. It downloads and self-hosts fonts at build time, eliminating the external DNS lookup and connection entirely. On a high-latency 3G connection, removing one cross-origin request can shave 400–800 ms from Time to First Contentful Paint.
Third-party scripts — analytics, chat widgets, A/B testing tools — are bandwidth and CPU tax. Load them with next/script using the lazyOnload strategy, which defers execution until the browser is fully idle. Better still, audit whether each script is earning its weight for your specific audience.
Test With the Network Your Users Actually Have
Chrome DevTools' network throttling presets default to a relatively generous "Slow 3G" (400 Kbps). Real congested mobile networks in West Africa regularly deliver 100–150 Kbps with 400–600 ms latency. Create a custom throttling profile that reflects this. Run Lighthouse against it. The score drop will be instructive and motivating.
WebPageTest allows you to run tests from actual devices in African locations. The results will be humbling — and precise.
Why This Matters for Your Project
If you are building or scaling a SaaS product, a mobile app, or an internal tool for users across the African continent, performance is not a polish item — it is a retention and conversion lever. Every second of load time above three seconds measurably increases drop-off rates. A low-bandwidth-first Next.js architecture, combining aggressive code splitting, layered caching, offline-first Service Workers, and disciplined third-party loading, ensures that the infrastructure you build today can reach and hold users in the markets that matter most to your growth.




