Paying $20 a month on Vercel or babysitting a dedicated VPS just to host a marketing site or portfolio built with Next.js is overkill. If your pages don’t require per-request server-side rendering, export the whole thing to flat HTML, dump it on cheap Hostinger shared hosting, point Namecheap DNS, and slap StackPath in front for global edge caching.
I migrated one of my content sites from dynamic Node.js rendering to a static export last month. The dynamic setup was chewing through 400MB of RAM on the box and idling around 300ms time to first byte. Once I exported everything to plain HTML and cached it at the edge, response times plummeted to 38ms.

Configure Next.js for Pure Static Export
Ever since Next.js 13.3, static exports are baked right into the config file—no clunky next export CLI script required. Open your next.config.mjs (or next.config.js) and tell Next to emit flat static files during the build.
Add output: 'export' and turn on trailingSlash: true so Apache doesn’t choke trying to resolve subfolder paths:
/** @type {import('next').NextConfig} */
const nextConfig = { output: 'export', trailingSlash: true, images: { unoptimized: true }
}; export default nextConfig;You have to set unoptimized: true inside the images block unless you’re routing through an external image service like Cloudinary or Imgix. By default, next/image expects an active Node.js server to resize images on the fly. If you leave that out, next build will crash with a fatal error the second it hits an image.
To see what’s off-limits in an export (like middleware and dynamic Route Handlers), check the official Next.js static exports documentation.
Build the Export and Inspect the Output Folder
Kick off a production build locally to make sure every route compiles clean into HTML, CSS, and client-side JS bundles.
Run the build script from your terminal:
npm run buildNext.js dumps the entire compiled artifact into an out directory at your project root. (The Pages router behaves the exact same way here.) Take a look inside to confirm your routes and assets actually generated:
Inspect the output directory structure:
ls -la out/You should see index.html, 404.html, a _next folder packed with hashed chunks, and folders for each route. If you have an about page, you’ll see out/about/index.html thanks to that trailingSlash: true setting.
Prepare the Hostinger .htaccess File
Hostinger’s shared hosting runs on LiteSpeed and Apache. When someone hits a route without typing index.html or misses a slash, the server needs clear rules so it doesn’t throw a bogus 404.
Drop a .htaccess file directly into your local public directory. Everything inside public gets copied straight into the out folder during the build.
Here’s the rewrite and caching config you need:
RewriteEngine On
RewriteBase / # Redirect direct HTML file requests to clean URLs
RewriteCond %{THE_REQUEST} ^[A-Z]{3,}\s([^.]+)\.html [NC]
RewriteRule ^ %1/ [R=301,L] # If requested directory exists, look for index.html
RewriteCond %{REQUEST_FILENAME} -d
RewriteCond %{REQUEST_FILENAME}/index.html -f
RewriteRule ^(.*)$ $1/index.html [L] # Fallback 404 page
ErrorDocument 404 /404.html # Force long-term caching for Next.js immutable assets
ExpiresActive On ExpiresByType text/html "access plus 0 seconds" ExpiresByType text/css "access plus 1 year" ExpiresByType application/javascript "access plus 1 year" ExpiresByType image/webp "access plus 1 year" ExpiresByType image/svg+xml "access plus 1 year"
If you want to dial in your cache headers even further, check out our guide on fixing static asset caching on Hostinger with .htaccess.
Upload Static Files to Hostinger hPanel
Now move the contents of your local out directory over to Hostinger. You can do this via rsync, SFTP, or the hPanel File Manager UI.
- Log into Hostinger hPanel and head to Websites.
- Pick your domain, click Manage, and open the File Manager.
- Drill down into
public_html. - Delete any default file Hostinger put there, like
default.php. - Zip up your local
outfolder, upload the archive intopublic_html, and extract it right into the root.
If you have SSH access enabled, rsync is a lot faster:
rsync -avz -e "ssh -p 65002" ./out/ u123456789@your-server-ip:~/domains/yourdomain.com/public_html/Double-check your file permissions once the transfer wraps up. Files need to be 644 and directories 755. If the zip extraction botched the permissions, fix them fast over SSH:
find . -type f -exec chmod 644 {} + && find . -type d -exec chmod 755 {} +Configure Namecheap DNS Records
If your domain is parked on Namecheap, you have two routes: hand nameserver authority over to Hostinger, or keep Namecheap BasicDNS and manage records yourself. Sticking with Namecheap BasicDNS makes placing a CDN in front much simpler.
- Log into Namecheap and pull up your Domain List.
- Click Manage on your domain and head over to the Advanced DNS tab.
- Grab your Hostinger server’s IP address from hPanel (you’ll see it under Server Details in the sidebar).
Set up these initial records to verify that Hostinger is serving your site cleanly before you flip on the CDN:
- Type: A Record | Host: @ | Value:
185.199.108.153(use your actual Hostinger IP) | TTL: Automatic - Type: CNAME Record | Host: www | Value:
yourdomain.com.| TTL: Automatic
If you’re dealing with an apex domain and need root CNAME behavior down the line, take a look at how to point a root domain to a CNAME in Namecheap with ALIAS records.
Configure StackPath CDN as the Reverse Proxy
Putting StackPath in front of Hostinger takes all asset delivery off your shared hosting plan, adds edge SSL, and keeps your site fast during traffic spikes.
- In the StackPath portal, hit Create Site.
- Choose CDN as the site service.
- Enter your domain (e.g.,
example.com). - Under Origin Settings, select Direct to IP Address and paste your Hostinger server IP.
- Set Origin Port to
443for HTTPS. Always use443so the edge-to-origin link stays fully encrypted.
StackPath will hand you an Edge CNAME address (like example.stackpathdns.com) along with an Anycast edge IP. Head back into Namecheap Advanced DNS and swap your records over:
- Point your root
@A record to the StackPath edge IP from your dashboard. - Update the
wwwCNAME record to target your StackPath edge hostname (e.g.,example.stackpathdns.com).
If your origin logs look off after routing through the proxy, read through our guide to restore real visitor IP addresses behind StackPath CDN.
Create StackPath Edge Rules for Next.js Static Files
Every Next.js build creates fingerprinted asset chunks inside /_next/static/*. Because these hashes update whenever the code changes, you can tell StackPath to cache them aggressively at the edge forever.
In StackPath, go to Edge Rules and add your first rule:
- Rule Name: Cache Next.js Static Chunks
- Condition: If Request URL matches regex
.*/_next/static/.* - Action 1: Override Edge Cache TTL -> 1 Year (31536000 seconds)
- Action 2: Override Browser Cache TTL -> 1 Year (31536000 seconds)
Now make a second rule for your HTML files so you don’t end up serving stale pages right after a deploy:
- Rule Name: Stale While Revalidate HTML
- Condition: If Request URL matches regex
.*.html$OR Request Path matches/ - Action: Set Edge Cache TTL to 600 seconds and Browser Cache TTL to 0 seconds.
For more details on how browsers and proxies juggle these directives, check the MDN documentation on Cache-Control directives.
The Trailing Slash Gotcha and How I Fixed It
When I first pushed this setup live, visiting example.com/about/ loaded fine, but requesting example.com/about triggered an infinite redirect loop or a blank 404 depending on the CDN’s cache state.
Apache sees about as a physical directory on disk and tries to force a slash onto it. Meanwhile, StackPath had an edge setting turned on to strip trailing slashes. Both systems ended up bouncing the request back and forth:
- The browser asks for
/about. - Hostinger’s Apache setup detects a folder and responds with a 301 redirect to
/about/. - StackPath intercepts, strips the trailing slash, and requests
/aboutagain from Hostinger. - The user’s browser bombs out with
ERR_TOO_MANY_REDIRECTS.
To kill the loop, align both sides. Keep trailingSlash: true in next.config.mjs, uncheck “Strip Trailing Slash” in StackPath, and paste this block at the very top of your public_html/.htaccess file on Hostinger:
# Prevent Apache directory slashes from conflicting with CDN edge
DirectorySlash Off # Manually route directories with index.html internally without external 301
RewriteCond %{REQUEST_FILENAME} -d
RewriteCond %{REQUEST_FILENAME}/index.html -f
RewriteRule [^/]$ %{REQUEST_URI}/index.html [L]The DirectorySlash Off directive stops Apache from throwing an HTTP 301 when someone requests a folder name without a slash. The rewrite rule quietly serves the inner index.html file without changing the URL bar or sending the CDN into a redirect spiral.
If you ever find yourself needing a full server-side runtime on Hostinger instead, take a look at our guide on how to deploy a full Node.js app on Hostinger with Namecheap and StackPath.
Verify Cache Hits and Response Headers
Once DNS updates propagate, fire up your terminal and run curl to make sure everything’s routing through the CDN and serving from cache.
Send a request to one of your static assets:
curl -I https://yourdomain.com/_next/static/chunks/main.jsLook through the response headers. Run it a second time and look for StackPath’s cache confirmation:
HTTP/2 200
date: Wed, 18 Oct 2023 14:22:10 GMT
content-type: application/javascript; charset=UTF-8
server: NetDNA-cache/2.2
x-cache: HIT
cache-control: public, max-age=31536000, immutableSeeing x-cache: HIT means StackPath handled the asset directly at the edge without touching Hostinger. Your shared server only does work on cache misses or new deployments, which keeps CPU and memory usage down near zero.
Frequently Asked Questions
Can I use Server Actions or API routes with a static export?
No. A static export runs without a Node.js runtime. Server Actions, API routes, middleware, and helper utilities like headers() from next/headers will fail during npm run build. If you need dynamic backends, spin them up on a dedicated API service or serverless functions, then fetch data client-side with fetch or SWR.
How do I update my site after pushing changes to GitHub?
Set up a simple GitHub Actions workflow. Have it run npm run build, use an SSH or rsync action to push the out/ directory into Hostinger’s public_html, and finish by hitting the StackPath API to purge the edge cache so visitors see your changes right away.
Why does StackPath return an SSL handshake error 521?
A 521 error almost always means StackPath tried to talk to Hostinger over port 443, but Hostinger didn’t have an active SSL certificate configured for that domain. Jump into hPanel, issue a free Let’s Encrypt certificate, verify that direct HTTPS works, and then re-check your StackPath origin settings.
Do I need trailingSlash: true if I do not have subdirectories?
For a basic single-page landing site, no. But the minute you introduce routes like /pricing or /blog, trailingSlash: true forces Next.js to produce /pricing/index.html instead of pricing.html. Traditional web servers handle directory indexes far more gracefully than loose HTML files without messy rewrites.
Next Steps for Your Static Stack
Now you’ve got a fast, edge-cached Next.js site running on minimal hosting spend. If you want to segment your services or spin up dedicated landing hubs under the same umbrella, read our guide on how to point a Namecheap subdomain to Hostinger without touching your main site.

