If your Next.js site does not need a server at request time, you can export it as static files. The result runs on any hosting plan, needs no Node.js on the server and is served very fast by LiteSpeed. This guide shows how to export, upload and fix the usual issues.
Before you start
- A Next.js project (App Router or Pages Router) that builds locally.
- A hosting account with File Manager or FTP access.
What a static export cannot do
- API routes and Route Handlers that read the request.
- Server Actions, middleware, cookies/headers in server components.
- Incremental Static Regeneration and on-demand rendering.
- The default image optimiser (
next/imageneeds a setting, below).
If you need these, deploy with Node.js instead: Next.js on cPanel or Next.js on a VPS.
Configure the export
Edit next.config.js:
module.exports = {
output: 'export',
trailingSlash: true,
images: { unoptimized: true },
};trailingSlash: true creates about/index.html instead of about.html, so URLs work on Apache and LiteSpeed without rewrite rules.
Build the site
npm run buildThe finished site is in the out folder. Dynamic routes such as /blog/[slug] must list their pages with generateStaticParams (App Router) or getStaticPaths (Pages Router), or the build fails.
Upload to cPanel
- Zip the contents of
out(not the folder itself). - Open cPanel → Files → File Manager, go to
public_html(or the addon domain's document root) and click Upload. - Select the zip, then right-click it and choose Extract. Delete the zip afterwards.
- Visit your domain. AutoSSL gives you HTTPS automatically.
Add a custom 404 page and redirects
Next.js writes 404.html. Tell the server to use it by adding to public_html/.htaccess:
ErrorDocument 404 /404.htmlForce HTTPS at the same time if you like:
RewriteEngine On
RewriteCond %{HTTPS} off
RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]Troubleshooting
- Pages 404 on refresh — enable
trailingSlashand rebuild, or you uploaded theoutfolder insidepublic_htmlinstead of its contents. - Build error about
next/image— addimages: { unoptimized: true }. - Old version still shows — clear LiteSpeed cache or your browser cache, and check you overwrote the files.
