---
title: "Publishing a Next.js Static Site on Cloudflare Pages for Free"
description: "An experiment log verifying deployment of a Next.js static site to Cloudflare Pages, from local verification and build to production deployment and custom domain setup."
lang: "en"
canonical: "https://llm-lab.dev/en/posts/cloudflare-pages-static-site-deploy/"
source: "https://llm-lab.dev/en/posts/cloudflare-pages-static-site-deploy.md"
publishedAt: "2026-04-11"
updatedAt: "2026-06-17"
category: "Cloudflare"
tags:
  - "cloudflare"
  - "cloudflare-pages"
  - "nextjs"
  - "static-site"
---

# Publishing a Next.js Static Site on Cloudflare Pages for Free

import LinkCard from "../../components/LinkCard.astro";

## Introduction

When starting a side project, one of the first subtle blockers is the hosting environment.

Before building the app itself, I might want a landing page, a tech blog, or a small media site. But once I actually try to launch, a flood of small decisions hits at once: hosting, custom domain, SSL, build settings, environment variables, and deployment methods.

Vercel or Netlify would work right away. But Cloudflare Pages is also a strong option. For static sites, it is easy to publish within the free tier, handles custom domains well, and serves from Cloudflare's CDN.

In this article, I will walk through the flow of publishing a static site to Cloudflare Pages, using a site I actually deployed as the example.

Here is the target site.

<LinkCard
  href="https://bukei-wisdom.com/"
  title="Bukei no Keifu (Lineage of Strategy)"
  description="A treasury of wisdom analyzing the strategic decisions of historical heroes through classical teachings and exploring their modern applications"
  siteName="https://bukei-wisdom.com/"
  image="https://bukei-wisdom.com/images/og-default.webp"
/>

"Bukei no Keifu" is a static site covering Eastern classics and military strategy texts. It is built with Next.js and deployed to Cloudflare Pages.

## What I Published This Time

I published a static site built with Next.js.

```text
Browser
  ↓
Cloudflare Pages
  ↓
Next.js static export
```

The target project lives under the `app` directory of the "Bukei no Keifu" project locally.

```text
bukei_shichisyo/
```

The app itself is under `app`.

```text
bukei_shichisyo/
  app/
    package.json
    wrangler.toml
    out/
```

I verified six things this time.

* Whether the Next.js site displays locally
* Whether the Next.js static build passes
* Whether the sitemap is generated
* Whether the Cloudflare Pages output directory is set to `out`
* Whether the Cloudflare Pages production deployment succeeds
* Whether the site displays on the custom domain `bukei-wisdom.com`

To state the conclusion upfront, the flow of publishing a Next.js static site on Cloudflare Pages works.

However, the Build command and Root directory are not always easy to see on the Cloudflare Dashboard. This article verifies the deployment configuration based on the Wrangler CLI and `wrangler.toml` settings.

## Why Use Cloudflare Pages

For static site hosting, there are several options: Vercel, Netlify, GitHub Pages, and others.

The reason I chose Cloudflare Pages is because it is easy to expand into other Cloudflare services later.

A static site alone is enough to start. But as I keep developing personal projects, I eventually want to add contact forms, image delivery, APIs, authentication, bot protection, and AI features.

Starting with Cloudflare Pages makes it easy to expand into Workers, R2, KV, D1, Turnstile, and AI Gateway. I do not have to use everything from the start, but having room to expand later is reassuring.

For "Bukei no Keifu," I focused on publishing it as a static site first. There is no database or authentication involved; I am just confirming that Cloudflare Pages works as a hosting environment.

## Verifying Locally

First, I display the Next.js site locally.

```bash
cd bukei_shichisyo/app
npm install
npm run dev
```

Locally, it displayed at `localhost:3000`.

![Bukei no Keifu displayed locally](/images/posts/cloudflare-p1-001-pages-static-site/01-local-site.webp)

What I checked here was not the site design itself. Before sending it to Cloudflare Pages, I confirmed that at least the top page renders locally and that the main navigation and cards are not broken.

Keeping a working local state before investigating production issues makes it easier to isolate problems later.

## Building

Next, I build for production.

```bash
npm run build
```

In this project, `next-sitemap` runs after `build`.

In `package.json`, the scripts look like this.

```json
{
  "scripts": {
    "build": "next build",
    "postbuild": "next-sitemap"
  }
}
```

After actually building, I confirmed that `next-sitemap` completed successfully.

![Next.js build and sitemap generation success log](/images/posts/cloudflare-p1-001-pages-static-site/02-build-success.webp)

The screenshot shows `https://bukei-wisdom.com/sitemap.xml` as a generation target.

This is subtle but important. For publishing a static site, having HTML rendered is the bare minimum. But if you care about search traffic, you should verify that the sitemap is generated too.

## Cloudflare Pages Configuration

The Cloudflare Pages configuration is in `app/wrangler.toml`.

```toml
name = "bukei-wisdom"
compatibility_date = "2024-01-15"
pages_build_output_dir = "out"
compatibility_flags = ["nodejs_compat"]

[env.production]
name = "bukei-wisdom"
compatibility_flags = ["nodejs_compat"]

[env.preview]
name = "bukei-wisdom-preview"
compatibility_flags = ["nodejs_compat"]
```

The actual settings screen looks like this.

![Wrangler configuration for Cloudflare Pages](/images/posts/cloudflare-p1-001-pages-static-site/03-wrangler-config.webp)

The two things to look at here are:

```toml
name = "bukei-wisdom"
pages_build_output_dir = "out"
```

`name` is the Cloudflare Pages project name. `pages_build_output_dir` is the output directory for static files that Cloudflare Pages deploys.

In this project, I am using `out`. Astro often uses `dist`, but Next.js static exports may use `out` depending on the configuration. If this is wrong, the build may pass but Cloudflare Pages will not find anything to serve.

## Deploying

On the Cloudflare Pages side, the project is named `bukei-wisdom`.

![Cloudflare Pages bukei-wisdom project settings screen](/images/posts/cloudflare-p1-001-pages-static-site/04-cloudflare-pages-project.webp)

In this deployment, I could not confirm the detailed values for Build command and Root directory on the Cloudflare Dashboard. This is because the workflow is Wrangler CLI-centered rather than Git-connected build settings.

Therefore, instead of Dashboard build settings, this article relies on two things.

* `pages_build_output_dir = "out"` in `wrangler.toml`
* The Cloudflare Pages scripts in `package.json`

`package.json` has the following scripts for Cloudflare Pages.

```json
{
  "scripts": {
    "pages:build": "npx @cloudflare/next-on-pages",
    "pages:deploy": "npm run pages:build && wrangler pages deploy",
    "deploy:production": "npm run build && npm run pages:build && wrangler pages deploy"
  }
}
```

Deployment basically follows this flow.

```bash
npm run build
npm run pages:build
wrangler pages deploy
```

Or use the combined script.

```bash
npm run deploy:production
```

The Cloudflare Pages production deployment succeeded, and `bukei-wisdom.com` and `bukei-wisdom.pages.dev` are linked.

![Cloudflare Pages production deployment success screen](/images/posts/cloudflare-p1-001-pages-static-site/06-deploy-success.webp)

On this screen, I can confirm the Production environment, main branch, successful deployment status, and published domains.

## Displaying on a Custom Domain

Finally, I verify that it displays on the custom domain.

The production URL is:

```text
https://bukei-wisdom.com/
```

When I actually access it, the "Bukei no Keifu" top page is displayed via Cloudflare Pages.

![Bukei no Keifu published on bukei-wisdom.com](/images/posts/cloudflare-p1-001-pages-static-site/09-bukei-wisdom-production.webp)

On the Pages production deployment screen as well, I can confirm the following two domains.

```text
bukei-wisdom.com
bukei-wisdom.pages.dev
```

On Cloudflare Pages, the `pages.dev` URL alone is enough to publish. But considering search, social sharing, and how visitors perceive the site, setting up a custom domain makes it easier to treat as a proper site.

This time as well, I ultimately assume `bukei-wisdom.com` will be the primary URL.

## Where You Actually Get Stuck

Through this exercise, I found three things to watch out for when publishing a static site on Cloudflare Pages.

The first is the output directory.

Depending on the framework and configuration, the directory to serve changes: `dist` for Astro, `out` for Next.js static export, and so on. In this configuration, `pages_build_output_dir = "out"` in `wrangler.toml` was important.

The second is that the information visible on the Cloudflare Dashboard does not always match the actual deployment workflow.

If you use Git-connected build settings, the Build command and Root directory are easy to see on the Dashboard. But if you deploy Wrangler CLI-centered, the Dashboard alone does not necessarily reveal all settings. This time, I verified the deployment configuration by looking at `wrangler.toml` and the scripts in `package.json`.

The third is the sitemap.

If the site displays, a sitemap is not strictly required. But if you expect search traffic, it is better to verify that `sitemap.xml` is generated. In this build log, I confirmed that `next-sitemap` targeted `https://bukei-wisdom.com/sitemap.xml` for generation.

## What I Learned from This Article

Cloudflare Pages is fully usable for publishing a Next.js static site.

In this real-world example, I verified local display, Next.js build, sitemap generation, Wrangler configuration, Production deployment, and custom domain display.

Especially, explicitly setting `pages_build_output_dir = "out"` in `wrangler.toml` makes it clear what Cloudflare Pages will serve. Trying to track settings through the Dashboard alone leaves blind spots, so keeping configuration in the repository is important.

In personal development, establishing a state where you can publish and continuously fix things matters more than building the site itself.

Once you get a site published through Cloudflare Pages, it becomes a foothold for expanding into Workers, R2, D1, Turnstile, and AI Gateway later. "Bukei no Keifu" was published as a static site this time, but having it on Cloudflare also makes it easier to add forms, analytics, and AI features in the future.

As a side note, it is not great to publish an article with a note saying "screenshots to be added later." Verification articles are stronger when accompanied by proof that everything actually worked.
