# Deploy Next.js (static export) to thin.host

Turn on output: 'export', build Next.js to out/, and deploy the static site to thin.host. thin.host serves the static files and gives you a live URL right away. Your agent can do every step for you through the thin.host MCP server, or you can run one `curl` command.

## At a glance

| Step | Next.js (static export) |
|---|---|
| Build command | `npm run build` |
| Folder to deploy | `out/` |
| Preview build (served at `/s/my-site/`) | `BASE_PATH=/s/my-site npm run build` |
| Deploy | `curl -F file=@site.zip -H "Authorization: Bearer $THINHOST_API_KEY" https://thin.host/v1/websites/archive` |
| Live URL | `https://thin.host/s/my-site/`, or your own domain |

## Before you start

- **Requires:** Node.js 20.9 or later.
- **A thin.host account.** [Sign up](https://thin.host/signup), then create an API key under Settings (for `curl` and the local MCP server), or connect your agent with OAuth as shown in [Quickstart (MCP)](https://thin.host/docs/quickstart-mcp).

## Create a project (skip if you have one)

```bash
npx create-next-app@latest
```

## Make the build fully static

Static export is opt-in. Set output to 'export'; with the default image loader, also set images.unoptimized because there is no image server.

```javascript
// next.config.mjs
/** @type {import('next').NextConfig} */
const nextConfig = {
  output: 'export',
  images: { unoptimized: true },
  basePath: process.env.BASE_PATH ?? '',
};

export default nextConfig;
```

## Set the base path

Until a domain points at it, a thin.host site lives under a sub-path: `https://thin.host/s/<slug>/`. The basePath option prefixes routes and assets. It must start with a slash and must not end with one; leave it empty for a custom domain. next/link adds it for you, but next/image src values and files in public/ need the prefix written in.

```javascript
// next.config.mjs
basePath: process.env.BASE_PATH ?? '',
```

| Where readers will look | Build with |
|---|---|
| The preview URL `https://thin.host/s/my-site/` | `BASE_PATH=/s/my-site npm run build` |
| A custom domain, or a free `<name>.thin.host` subdomain | `npm run build` (base path `/`) |

Pick the slug (`my-site` here) before you build the preview, and pass the same slug when you deploy.

## Build

```bash
npm run build
```

The finished site is in `out/`. That folder is what you deploy.

## Deploy from your agent (MCP)

Connect thin.host to Claude Code, Claude Desktop, Cursor, VS Code, Windsurf, Codex or ChatGPT once ([setup for each client](https://thin.host/docs/quickstart-mcp)), then ask:

> Build this Next.js (static export) project for thin.host with the slug my-site and publish the out/ folder.

With the local server (`uvx thinhost-mcp`) the agent runs the build and calls `publish_website` with the absolute path of `out/`; large builds are split across requests automatically. Later changes go out with `update_website` and `sync=true`, which also removes files the new build dropped.

The hosted connector (`https://thin.host/mcp`, used by claude.ai and ChatGPT) cannot read your disk. From a coding agent it uploads with the REST call below; otherwise it publishes from a public link to a zip or HTML file with `publish_website_from_url`.

## Deploy with curl

```bash
cd out && zip -r ../site.zip . && cd -
curl -F file=@site.zip -F title="My Next.js (static export) site" -F slug=my-site \
  -H "Authorization: Bearer $THINHOST_API_KEY" \
  https://thin.host/v1/websites/archive
```

The JSON response includes `url`, the live address (`https://thin.host/s/my-site/`). To redeploy, upload the new zip to the site's archive endpoint; pages and assets missing from it are removed:

```bash
curl -F file=@site.zip \
  -H "Authorization: Bearer $THINHOST_API_KEY" \
  https://thin.host/v1/websites/my-site/archive
```

A single upload can be up to 30 MB. See the [REST API reference](https://thin.host/docs/api) for every field.

## Add a custom domain

1. Open the site in the [dashboard](https://thin.host/dashboard) and add your hostname under **Custom Domains**, for example `www.example.com`. A `<name>.thin.host` subdomain is free and works immediately.
2. Create the DNS record the dashboard shows: a `CNAME` pointing at `cname.thin.host`. TLS is issued automatically once DNS resolves.
3. Rebuild with the base path `/` (`npm run build`) and redeploy.

Pages on a custom domain get a canonical tag, a generated `robots.txt` and a `sitemap.xml`.

## Next.js (static export) notes

- Static export has no server: Route Handlers that read the request, Proxy (formerly middleware), rewrites/redirects/headers in next.config, ISR, Server Actions, cookies and dynamic routes without generateStaticParams are not available.
- Each route becomes route.html (or route/index.html with trailingSlash: true); thin.host serves both at /route.

## FAQ

**Do API routes and middleware work with a Next.js static export?**

No. output: 'export' produces only static files, so anything that needs a server at request time is unavailable. Keep those parts on a server platform and host the static front end on thin.host.

**Why are my next/image images broken after export?**

The default image loader needs a server. Set images: { unoptimized: true } or configure a custom loader.

**Why does the preview URL load without styles or scripts?**

The site is served under /s/<slug>/ until a custom domain points at it, so a build that references /assets/... asks the thin.host root for files that live under the sub-path. Build with the base path set to /s/<slug>/ for the preview, or map a domain (a free <name>.thin.host subdomain works) and build with base /.

**How do I redeploy?**

Rebuild, zip the output folder again and POST it to /v1/websites/<slug>/archive, or ask your agent to run update_website with sync=true. Sync removes files the new build no longer contains, so old hashed bundles do not pile up.

**How large can a site be?**

A single archive upload can be up to 30 MB. The local MCP server (uvx thinhost-mcp) reads the build folder directly and splits large sites across requests, up to 150 MB.

## Sources

Commands and options checked against the official Next.js (static export) docs on 2026-10-14:

- [Next.js: Static exports](https://nextjs.org/docs/app/guides/static-exports)
- [Next.js config: basePath](https://nextjs.org/docs/app/api-reference/config/next-config-js/basePath)
- [Next.js config: trailingSlash](https://nextjs.org/docs/app/api-reference/config/next-config-js/trailingSlash)

Other frameworks: [all deploy guides](https://thin.host/guides). Coming from another host? [Compare thin.host](https://thin.host/compare).

---
Canonical page: https://thin.host/guides/deploy-nextjs
