Skip to content

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 OpenNav in the project that owns the Cloudflare build command.

Terminal window
npm install @opennav-ai/opennav
Cloudflare pathOpenNav setup
Pages with any static output folderRun the CLI after your normal build.
Pages with AstroUse OpenNavAstro after astro build.
Pages with Next.js static exportUse OpenNavNext with output: "export".
Pages with a custom build script or monorepoUse the TypeScript SDK from the script that knows the output folder.
Workers static assetsRun OpenNav before wrangler deploy uploads the configured assets directory.
AI Gateway or agent experimentsFetch the generated OpenNav files from Pages or Workers assets; AI Gateway remains the AI app proxy and observability layer.

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 settingValue
Build commandnpm run build
Build output directorydist

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:

Terminal window
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 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 settingValue
Build commandnpm run build
Build output directorydist

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,
},
});

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 settingValue
Build commandnpm run build
Build output directoryout

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);

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 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 pointCloudflare Pages header behavior
CLI with --platform cloudflare-pagesCreates 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.md

The generated _headers block sets:

Route patternResponse header behavior
/*.mdServes generated Markdown mirrors as text/markdown; charset=utf-8.
/llms.txt, /llms-full.txt, and .well-known copiesServes generated indexes as text/plain; charset=utf-8.
/.well-known/opennav.jsonServes 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 AI

That 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 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 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 needOpenNav file
Find the readable site indexhttps://example.com/llms.txt
Read page content without visual HTMLhttps://example.com/path/index.md
Verify generated files and static compatibilityhttps://example.com/.well-known/opennav.json
Read content-use guidancehttps://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.

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.txt

See the generated files reference for the full file behavior and ownership rules.