Cloudflare
Cloudflare is the clearest first platform for OpenNav: Pages already deploys a finished folder, Workers can serve static assets from a configured directory, and AI Gateway teams are already thinking about agent cost, routing, and observability.
OpenNav currently ships the static agent-readable layer. It does not install Worker middleware or configure AI Gateway. Start by publishing the files agents can discover today, then use the server-side roadmap when runtime Markdown responses are available.
Cloudflare Pages is the first platform with a built-in OpenNav platform
default. Passing platform: "cloudflare-pages" in the SDK, Astro, or Next, or
--platform cloudflare-pages in the CLI, creates the Pages _headers artifact
by default. Additional platform defaults are planned as OpenNav adds first-class
support for more static hosts.
Install
Section titled “Install”Install OpenNav in the project that owns the Cloudflare build command.
npm install @opennav-ai/opennavpnpm add @opennav-ai/opennavyarn add @opennav-ai/opennavbun add @opennav-ai/opennavChoose Your Cloudflare Path
Section titled “Choose Your Cloudflare Path”| Cloudflare path | OpenNav setup |
|---|---|
| Pages with any static output folder | Run the CLI after your normal build. |
| Pages with Astro | Use OpenNavAstro after astro build. |
| Pages with Next.js static export | Use OpenNavNext with output: "export". |
| Pages with a custom build script or monorepo | Use the TypeScript SDK from the script that knows the output folder. |
| Workers static assets | Run OpenNav before wrangler deploy uploads the configured assets directory. |
| AI Gateway or agent experiments | Fetch the generated OpenNav files from Pages or Workers assets; AI Gateway remains the AI app proxy and observability layer. |
Cloudflare Pages With The CLI
Section titled “Cloudflare Pages With The CLI”Cloudflare Pages lets you configure a build command and an output directory. Use the same output directory for both OpenNav and the Pages publish directory.
{ "scripts": { "build": "astro build && opennav build --static --output dist --site-url https://example.com --site-name \"Example Docs\" --platform cloudflare-pages" }}In Cloudflare Pages:
| Pages setting | Value |
|---|---|
| Build command | npm run build |
| Build output directory | dist |
Use the deployed production URL for --site-url, including the protocol and
host. In monorepos, make --output relative to the project root that Pages uses
for the build command.
Run a dry run locally when you want to preview the file plan before changing the build command:
opennav build --static \ --output dist \ --site-url https://example.com \ --site-name "Example Docs" \ --platform cloudflare-pages \ --dry-run--platform cloudflare-pages is enough to create or update _headers; the
older explicit --static-headers flag is not required for Cloudflare Pages.
Astro On Cloudflare Pages
Section titled “Astro On Cloudflare Pages”Astro static builds usually publish dist. Add OpenNavAstro to the Astro
config, then let Pages run the normal Astro build.
import { defineConfig } from "astro/config";import { OpenNavAstro } from "@opennav-ai/opennav/astro";
export default defineConfig({ site: "https://example.com", integrations: [ OpenNavAstro({ siteName: "Example Docs", mode: "static", platform: "cloudflare-pages", }), ],});In Cloudflare Pages:
| Pages setting | Value |
|---|---|
| Build command | npm run build |
| Build output directory | dist |
Use this path for Astro sites that produce static HTML. Server-side Astro on Cloudflare is part of the server-side roadmap, not the current static profile.
To keep the Cloudflare platform setting without writing _headers, opt out in
the integration:
OpenNavAstro({ siteName: "Example Docs", mode: "static", platform: "cloudflare-pages", staticHeaders: { enabled: false, },});Next.js Static Export On Cloudflare Pages
Section titled “Next.js Static Export On Cloudflare Pages”OpenNav supports Next.js static export builds. Configure Next with
output: "export" and publish the generated out folder.
import { OpenNavNext } from "@opennav-ai/opennav/next";import type { NextConfig } from "next";
const nextConfig: NextConfig = { output: "export",};
export default OpenNavNext({ siteName: "Example Docs", siteUrl: "https://example.com", mode: "static", platform: "cloudflare-pages",})(nextConfig);In Cloudflare Pages:
| Pages setting | Value |
|---|---|
| Build command | npm run build |
| Build output directory | out |
Use this path for exported static routes. Next.js server output, route handlers, and request-time dynamic pages are not covered by the current static profile.
To keep the Cloudflare platform setting without writing _headers, opt out in
the config wrapper:
OpenNavNext({ siteName: "Example Docs", siteUrl: "https://example.com", mode: "static", platform: "cloudflare-pages", staticHeaders: { enabled: false, },})(nextConfig);Custom SDK Or Monorepo Builds
Section titled “Custom SDK Or Monorepo Builds”Use the root SDK when a custom script already knows which folder Cloudflare will publish.
import { OpenNavStaticSite } from "@opennav-ai/opennav";
const result = await new OpenNavStaticSite({ siteName: "Example Docs", siteUrl: "https://example.com", outputDirectory: "dist", platform: "cloudflare-pages",}).build();
if (result.isErr()) { console.error(result.error.message); process.exit(1);}Then call that script after the framework build and before Pages uploads the output folder.
{ "scripts": { "build": "npm run build:site && node scripts/opennav.mjs" }}Set staticHeaders: { enabled: false } in the SDK options when you want to keep
platform: "cloudflare-pages" for future Cloudflare-specific behavior but do
not want OpenNav to create or edit _headers.
Cloudflare Pages Headers
Section titled “Cloudflare Pages Headers”Cloudflare Pages can read a _headers file from the deployed output directory
and attach response headers to matching routes. When
platform: "cloudflare-pages" is configured, OpenNav creates or updates an
OpenNav-managed block in that file by default.
| Entry point | Cloudflare Pages header behavior |
|---|---|
CLI with --platform cloudflare-pages | Creates or updates _headers by default. |
OpenNavStaticSite({ platform: "cloudflare-pages" }) | Creates or updates _headers by default. |
OpenNavAstro({ platform: "cloudflare-pages" }) | Creates or updates dist/_headers by default. |
OpenNavNext({ platform: "cloudflare-pages" }) | Creates or updates _headers in the static export folder by default. |
SDK, Astro, or Next with staticHeaders: { enabled: false } | Does not create or edit _headers. |
The default is enabled only for currently supported platforms that have a known static header file format. Today that is Cloudflare Pages. More platform support is planned.
dist/ _headers llms.txt llms-full.txt .well-known/opennav.json index.mdThe generated _headers block sets:
| Route pattern | Response header behavior |
|---|---|
/*.md | Serves generated Markdown mirrors as text/markdown; charset=utf-8. |
/llms.txt, /llms-full.txt, and .well-known copies | Serves generated indexes as text/plain; charset=utf-8. |
/.well-known/opennav.json | Serves the compatibility manifest as application/json; charset=utf-8. |
HTML page routes such as /, /docs/page, or /docs/page/ | Adds HTTP Link headers pointing to that page’s generated Markdown alternate and the root llms.txt index. |
OpenNav also sets X-Content-Type-Options: nosniff for those generated
artifacts. In a request flow, an agent can fetch https://example.com/llms.txt
or https://example.com/docs/page/index.md, and Cloudflare Pages will return
the file with a concrete content type instead of relying on generic static-file
detection.
For HTML responses, the generated page route block looks like this:
/docs/page Link: <https://example.com/docs/page.md>; rel="alternate"; type="text/markdown" Link: <https://example.com/llms.txt>; rel="index"; type="text/plain"For a small site with a home page and one docs page, the complete generated
dist/_headers file can look like this:
# Begin OpenNav AI# opennav compatible="true" version="1.0" profile="static-agent-ready" build-fingerprint="sha256:123456789abc" manifest="/.well-known/opennav.json"/llms.txt Content-Type: text/plain; charset=utf-8 X-Content-Type-Options: nosniff
/llms-full.txt Content-Type: text/plain; charset=utf-8 X-Content-Type-Options: nosniff
/.well-known/llms.txt Content-Type: text/plain; charset=utf-8 X-Content-Type-Options: nosniff
/.well-known/llms-full.txt Content-Type: text/plain; charset=utf-8 X-Content-Type-Options: nosniff
/.well-known/opennav.json Content-Type: application/json; charset=utf-8 X-Content-Type-Options: nosniff
/*.md Content-Type: text/markdown; charset=utf-8 X-Content-Type-Options: nosniff
/ Link: <https://example.com/index.md>; rel="alternate"; type="text/markdown" Link: <https://example.com/llms.txt>; rel="index"; type="text/plain"
/docs/page Link: <https://example.com/docs/page.md>; rel="alternate"; type="text/markdown" Link: <https://example.com/llms.txt>; rel="index"; type="text/plain"# End OpenNav AIThat does not implement runtime Accept: text/markdown negotiation. It gives
agents a response-header discovery path for the same Markdown alternate and
site index that OpenNav already advertises inside the HTML <head>.
OpenNav preserves caller-owned _headers rules and replaces only the block
between # Begin OpenNav AI and # End OpenNav AI. If an existing caller-owned
route overlaps OpenNav’s generated header routes, OpenNav leaves _headers
untouched and reports a warning so the site owner can resolve the conflict
intentionally. This applies to any header on the overlapping route, not only
Content-Type.
Cloudflare documents the file format, comment behavior, and route/header limits in Pages Headers.
Workers Static Assets
Section titled “Workers Static Assets”Workers can deploy static assets from a configured directory. Run OpenNav before
wrangler deploy so the assets directory already contains the generated
OpenNav files.
{ "$schema": "./node_modules/wrangler/config-schema.json", "name": "example-docs", "compatibility_date": "2026-05-01", "assets": { "directory": "./dist" }}{ "scripts": { "build": "astro build && opennav build --static --output dist --site-url https://example.com --site-name \"Example Docs\"", "deploy": "npm run build && wrangler deploy" }}If your Worker code serves assets through a binding, keep the binding pointed at the same directory OpenNav updates. OpenNav writes files only; it does not change Worker routing.
AI Gateway And Agent Experiments
Section titled “AI Gateway And Agent Experiments”AI Gateway is useful for observing and controlling AI application traffic. It does not publish website content. Pair it with OpenNav by having the agent fetch the generated files from a Cloudflare Pages site or a Workers static-assets deployment:
| Agent need | OpenNav file |
|---|---|
| Find the readable site index | https://example.com/llms.txt |
| Read page content without visual HTML | https://example.com/path/index.md |
| Verify generated files and static compatibility | https://example.com/.well-known/opennav.json |
| Read content-use guidance | https://example.com/robots.txt when accessGuidance is configured |
Use this when you are testing agent workflows, token cost, or browser fallback behavior around Cloudflare-hosted sites.
What Gets Published
Section titled “What Gets Published”After OpenNav runs, the same Cloudflare deployment includes the agent-readable files beside your normal site:
dist/ llms.txt llms-full.txt _headers .well-known/llms.txt .well-known/llms-full.txt .well-known/opennav.json index.md docs/getting-started/index.md robots.txtSee the generated files reference for the full file behavior and ownership rules.