LSN 05/10 ▸PAGES 12 MIN TIER FREE
Pages: hosting your first site
Connect a Git repo, get a built static site at the edge, attach a custom domain. The path-of-least-resistance hosting on Cloudflare.
Before this: 04 DNS, the part you'll touch daily
Pages is Cloudflare’s static-site hosting product. You connect a Git repository, Cloudflare runs your build, and the resulting static files get served from every Pages edge worldwide. This is the path of least resistance for shipping a site on Cloudflare.
This site (cloudflare.too.foo) is a Pages project. So is everything
else under too.foo.
Creating a project
From the dashboard, Workers & Pages → Create → Pages → Connect to Git. Authorize Cloudflare to read your GitHub or GitLab account if you have not already, then pick the repository.
The next screen asks for build settings:
- Production branch. Usually
main. Pushes to this branch build and deploy to production. - Framework preset. A dropdown of common frameworks (Astro, Next.js, Vite, Hugo, Eleventy, etc.). Each preset fills in the build command and output directory. Pick one if it matches; otherwise leave blank and fill in manually.
- Build command. What Cloudflare runs to build. For most static
generators:
npm run build,pnpm build,yarn build,hugo, etc. - Build output directory. Where the built files end up. Common
values:
dist,build,public,_site. - Root directory (advanced). If your project is not at the repo root (monorepo), point Cloudflare at the right subdirectory.
Click Save and Deploy. The first build takes 30 to 90 seconds.
When it finishes you get a URL like your-project.pages.dev that
serves your site immediately.
Per-branch previews
Every branch you push (not just main) gets its own preview deploy.
The URL pattern is:
https://<branch-slug>.<project>.pages.dev
Where <branch-slug> is the branch name with / replaced by -.
So feature/dark-mode becomes
feature-dark-mode.your-project.pages.dev. This is genuinely useful:
every PR has a live preview URL you can share with a reviewer or
the design person.
There is no per-branch configuration. Whatever the build command does,
it does for previews too. Use process.env.CF_PAGES_BRANCH inside the
build if you need to vary behavior (e.g., different analytics ID for
production vs. preview).
Custom domain
A pages.dev URL is fine for a side project but you usually want
yoursite.com or a subdomain.
In the Pages project settings, go to Custom domains → Set up a custom domain → enter the hostname. Cloudflare creates the DNS record for you if the domain is on the same Cloudflare account.
Behind the scenes this adds a proxied CNAME from your hostname to
your-project.pages.dev. Because the record is proxied (orange cloud),
Cloudflare:
- Issues a TLS certificate automatically (Let’s Encrypt under the hood, but you do not see that).
- Terminates HTTPS at the edge.
- Serves the static files from cache.
For an apex domain (yoursite.com, not www.yoursite.com), Cloudflare
uses CNAME flattening (see DNS lesson) to make the CNAME work on the
apex. You do not have to think about it.
Pages Functions
Pages also supports Functions, which are Workers that live inside
your Pages project. Drop a file at functions/api/hello.ts and that
file handles requests to /api/hello on your site. The runtime is
identical to standalone Workers (next lesson), but the deploy is tied
to your Pages project.
Functions are how you add dynamic behavior to an otherwise static site: form submissions, auth, API endpoints, edge-rendered pages.
Monorepo: root_dir and path_includes
A single Git repo can drive many Pages projects, each with their own build. Two settings make this work:
- Root directory. The subdirectory the build command runs in.
- Path includes. A list of paths whose changes trigger a rebuild for this project.
On too.foo there are around 30 apps in one monorepo. Each app has its
own Pages project with root_dir = apps/<slug> and path_includes
covering apps/<slug>/*, packages/**, pnpm-lock.yaml,
pnpm-workspace.yaml, package.json. A change to one app’s source
rebuilds only that app’s project. A change to a shared package
(packages/**) rebuilds every project that depends on it. A change
to a totally unrelated app rebuilds nothing.
The trap to avoid: if path_includes does not cover shared packages,
a change to a shared UI library will not rebuild apps that consume it,
and the design system drifts between subdomains. Always include the
shared paths.
Limits
- 500 builds per month on the free plan. Pro raises this to 5000.
- Up to 20,000 files per deploy. Bundle if you have more.
- 25 MB single-file maximum.
- Unlimited bandwidth. This is the headline feature.
- Concurrent builds: 1 on free, 5 on Pro.
These limits are generous enough that you usually only hit them when
something is misconfigured (a build looping, or a monorepo
accidentally including node_modules).
Pages is the easiest place to start on Cloudflare. Once your site is up, the next interesting move is running code at the edge: Workers.