If you have priced hosting for a client project in Ethiopia, you already know the pattern: reliable shared cPanel hosting is everywhere, but almost none of it gives you a Node.js server to run alongside it. That one fact shapes many of our decisions on Ab Tech projects, especially anything built with a modern React framework such as Next.js. This article explains how we ship Next.js sites on ordinary shared hosting, what you give up, and how to add dynamic features back.
The problem with the "normal" Next.js setup
Most tutorials assume you will deploy to a platform such as Vercel, or to a server that can keep next start running. For many of our clients, such as churches, small businesses and organisations, neither is realistic. They already pay for cPanel hosting from a local provider and cannot justify a second bill for a Node server, especially when the exchange rate makes anything priced in dollars expensive.
Static export as the middle ground
Next.js can compile a site into plain HTML, CSS and JavaScript files with no server process. You keep the developer experience of React, file-based routing and reusable components, but the output is something any shared host can serve.
// next.config.js
/** @type {import('next').NextConfig} */
const nextConfig = {
output: 'export', // generate static files in /out
trailingSlash: true, // /about/ -> about/index.html, friendlier on Apache
images: { unoptimized: true } // the image optimiser needs a server
};
module.exports = nextConfig;
Running npm run build then produces an out folder. Upload its contents into public_html using the cPanel File Manager or FTP, and the site is live.
What you give up
Static export has real limits, and it is better to know them before you start.
- No server-side rendering at request time, and no API routes inside the Next.js app.
- No built-in image optimisation, so you must resize and compress images yourself (see website speed basics).
- Anything that must change without a rebuild, such as authentication, a database or an admin panel, cannot live inside the app itself.
- Dynamic routes need their pages known at build time.
Handle routing on Apache
With trailingSlash: true, each page becomes a folder with an index.html, which Apache serves without extra rules. If you use client-side routes that do not exist as files, add a fallback and a custom 404 page. Test deep links by opening them directly rather than only by clicking through from the homepage.
Firebase or a small PHP API fills the gap
For dynamic features we pair the static front-end with a separate backend.
- Firebase: Authentication for admin logins and Firestore for content that must be editable without redeploying, such as gallery images, event listings, sermon notes, a books catalogue or giving-page details. The public pages fetch this data in the browser.
- A lightweight PHP API: where Firebase is not the right fit, a small
/apifolder on the same cPanel account, talking to the MySQL database the host already provides.
Either way the pattern is the same: a static front-end and a dynamic backend attached separately. For help choosing, read Firebase or MySQL?
Content that loads in the browser: what to watch
- Search visibility: content fetched after the page loads may be less visible to search engines than content in the HTML. Keep important text, such as headings and descriptions, in the build output, and fetch only the parts that change often.
- Loading states: show a placeholder while data loads and a clear message if it fails, so visitors on slow networks do not see an empty page.
- Caching: cache static assets for a long time and version file names when they change.
- Security: public Firebase configuration is not secret, so protect data with strict security rules rather than by hiding keys.
A deployment routine that avoids mistakes
- Build locally with
npm run buildand check theoutfolder. - Preview it locally with a simple static server before uploading.
- Back up the current
public_htmlcontents. - Upload the new files, removing old ones that no longer exist so stale files do not linger.
- Test the main pages, a deep link, the 404 page and the forms on the live domain.
- Keep
.htaccessand any API folders when you clear old files.
What this means in practice
For a recent church website project, this setup let us ship a fully bilingual site with an admin-managed hero slideshow, a books section, event and sermon management and a multi-bank giving page, all hosted for the same monthly fee the client already paid for their old static site. There was no server migration, no new hosting contract and no dependency on a platform that bills in dollars.
When this is not the right choice
It is not the setup we would choose if budget and hosting constraints did not exist. If you need server-side rendering, frequent personalised pages or heavy server logic, a Node-capable host or VPS is a better fit. And if the site is only a few pages that rarely change, plain HTML or a simple PHP site may be easier to maintain than a React build.
The short version
Use Next.js static export when you want a modern front-end on ordinary cPanel hosting, and attach Firebase or a small PHP API for anything dynamic. Accept the trade-offs: no server rendering, manual image optimisation and a separate backend.