How do I host a static website on Cloudflare? Put your HTML, CSS, JavaScript, images and other publishable files in a GitHub or GitLab repository, create a Pages project in Cloudflare, select the production branch, and set the correct build command and output directory. Cloudflare then deploys the site to a pages.dev address. A plain site needs no framework; its output directory simply needs a top-level index.html.
This guide covers Git deployments, Direct Upload and C3, framework builds, custom domains, redirects, headers, limits and the errors that most often prevent a successful launch. Cloudflare also notes that Workers now supports most Pages use cases and should be considered for new projects, but Pages remains the direct workflow for a static site.
Choose a Cloudflare Pages deployment method
Cloudflare documents three routes:
- Git integration: Connect GitHub or GitLab. Pushes to the selected production branch trigger builds and deployments, and new pull requests can receive preview deployments.
- Direct Upload: Upload an already-built directory manually or from your own CI process.
- C3 (Create Cloudflare project): Start from the command line when you want a Wrangler-based setup.
Decide before connecting a repository: Cloudflare documents that a Git-integrated project cannot later be converted to Direct Upload. Git integration supports GitHub and GitLab, including their hosted services; for another provider or a self-hosted instance, use Direct Upload from CI (such as GitHub Actions with Wrangler).
Prepare the files Cloudflare will publish
- Put the page visitors should see first in a file named
index.html. - Keep CSS, JavaScript, images, fonts and other assets in the site directory referenced by that HTML.
- Identify the directory that should become the public web root. Cloudflare uploads that directory’s contents, not its parent folder.
- If a generator is involved, confirm its generated output before deploying. The final output directory must contain
index.htmlat its top level (or the framework’s equivalent entry files).
For a plain static site, a minimal structure is:
site/
index.html
styles.css
app.js
images/
Open index.html locally and check that asset paths work. Relative paths such as ./styles.css are safer when the site may be served from a subpath during testing.
What’s actually slowing this PC down?
Pick the symptom - the matching free tool is one click away.
#1 Best Overall
Deploy with Git integration
- Push the site to GitHub or GitLab. For a basic example, use a production branch named
main. - In the Cloudflare dashboard, open Workers & Pages, choose Create application, select Pages, and import your repository.
- Authorize the Git provider, choose the repository and select the production branch.
- Set the build configuration. For plain HTML, leave the build command blank or enter the documented optional command
exit 0. Set the output directory to the directory containing the deploy-ready files (for example, the repository root orsite). - Click the deployment control and wait for the build log to report success. A command that exits non-zero marks the build failed; exit code zero tells Pages to upload the output.
- Open the generated
pages.devURL. Test the home page, a representative internal URL, CSS, JavaScript and images. Push a small change to verify that the branch trigger works; open a pull request to check its preview deployment.
In a monorepo, set the Pages project root directory to the application folder. Otherwise Pages may run the command in the repository root and upload the wrong directory.
Use the right build command and output directory
Cloudflare’s current framework presets include these examples:
| Site or workflow | Build command | Output directory or setting |
|---|---|---|
| Plain HTML | Blank or exit 0 |
Directory containing final site files |
| Vite | npm run build |
dist |
| Astro | npm run build |
dist |
| Hugo | hugo |
public |
| Next.js static export | npx next build |
out |
| Monorepo | Project-specific | Set the Pages root directory to the app folder |
Framework versions and defaults change. Verify the active framework’s output setting when a deployment succeeds but serves an empty or incorrect site. The authoritative build configuration is in Cloudflare’s build-configuration documentation.
Direct Upload and C3
Direct Upload
Use Direct Upload when your CI system already builds the site or your files are not in a supported Git provider. Build locally or in CI, then upload the resulting directory through the Pages project flow or Wrangler. Keep the output directory reproducible: it should contain only the files intended for visitors, including the top-level entry document.
Rank #2
C3
C3 creates a Cloudflare project from the command line and is useful when you prefer Wrangler-driven configuration. Follow the current prompts and deploy the generated output. The same rule applies regardless of method: the directory sent to Pages must be the finished site, not source files that still require a build.
Fix a 404 on the pages.dev address
Getting 404 errors on *.pages.dev? Check these items in order:
- Confirm that
index.htmlis at the top level of the configured output directory. - Inspect the deployment log to ensure the intended directory was uploaded and the build command exited with code zero.
- Check capitalization in filenames and links. A Linux-based deployment treats
Index.htmlandindex.htmlas different names. - For a framework, verify that the generator actually wrote files to the directory configured in Pages (
dist,publicorout, as applicable). - Redeploy after correcting the setting, then open the deployment’s own URL before testing a custom domain.
Add a custom domain
In the Pages project, open Custom domains and add the hostname. A subdomain normally follows the dashboard’s DNS instructions. An apex domain such as example.com has an additional requirement: the domain must be a zone in the same Cloudflare account and its nameservers must point to Cloudflare. A CNAME-only recipe is not sufficient for an apex domain under this requirement. See Cloudflare’s custom-domain documentation.
If the custom hostname should be the only public address, first add it, then create a Bulk Redirect from the project’s pages.dev hostname to that custom domain. Cloudflare documents this workflow in its redirect guide.
Outdated Drivers Are Slowing You Down
One free scan finds every outdated or missing driver and matches the right update for your exact hardware.Free scan · exact hardware matchPC Slower Than It Used to Be?
A free scan shows the junk files, broken settings and background clutter dragging Windows down - then fixes them in one click.Free scan · Windows 10 & 11Rank #3
Redirects and response headers
Static redirects
Place a plain-text file named _redirects in the asset directory so your build copies it into the final output. Each line defines a redirect. Cloudflare documents a limit of 2,000 static redirects and 100 dynamic redirects, with 2,100 combined. Redirect rules in this file do not control responses served by Pages Functions; move those rules into Function code or keep the affected paths outside Functions. Details are in the redirects documentation.
Headers
A plain-text _headers file can add, override or remove headers for static asset responses, and is not served as a public asset. It does not apply to Pages Functions responses; set headers in the Function response instead. Choose security-header values for your application rather than copying an example without review. See Cloudflare’s headers guide.
Limits to check before scaling
Cloudflare’s limits page was last updated September 5, 2026. On the Free plan it lists 500 builds per month, one concurrent build, 20,000 files per site, a 25 MiB maximum individual asset, and 100 custom domains per project. It also lists a 20-minute build timeout. Paid plans have different limits, including up to 100,000 files per site when the documented PAGES_WRANGLER_MAJOR_VERSION=4 project setting is used. These are service limits, not performance benchmarks, and can change; verify the live Pages limits page before planning capacity.
Performance, reliability and operating practices
- Keep generated output free of source maps, test fixtures and unused media when they are not needed in production.
- Compress large images and split oversized bundles before hitting the per-asset limit.
- Use pull-request previews to review links and layout before merging to production.
- Record the exact build command, root directory and output directory in project documentation so a replacement maintainer can reproduce deployments.
- When a build fails, read the first error in the log rather than only the final status; a missing dependency, wrong working directory or malformed command usually appears earlier.
Or skip the browser setup
If you need screenshots of the deployed site for documentation, visual checks or an AI workflow, ScreenshotNeo provides a one-request website screenshot API and MCP server. It removes cookie banners, newsletter popups and chat widgets before capture; bot checks, blank pages and failed loads are not billed. AI agents can use its MCP tools, including take_screenshot, get_page_info and capture_pdf.
Free tools Windows power users keep installed
One-click scans. No signup required.
Use the API documentation at screenshotneo.com/docs/. Replace the URL with your Pages address:
Rank #4
curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://your-project.pages.dev -o shot.webp
import requests
r = requests.get("https://api.screenshotneo.com/v1/shot", params={"access_key": "YOUR_API_KEY", "url": "https://your-project.pages.dev"}, timeout=90)
open("shot.webp", "wb").write(r.content)
const q = new URLSearchParams({ access_key: 'YOUR_API_KEY', url: 'https://your-project.pages.dev' });
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);
ScreenshotNeo’s Free plan includes 1,000 screenshots per month with no card; paid plans start at $5 for 3,000 shots. Create a free ScreenshotNeo account.
Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Common deployment failures and fixes
Build succeeds but the site is blank
The output directory is probably wrong or contains framework source instead of generated files. Inspect the build artifact and point Pages at the folder containing the entry document.
Assets return 404
Check case-sensitive paths, leading slashes and whether the asset was copied into the output directory. A framework may rewrite asset URLs during its build; use its documented base-path setting.
Git pushes do not deploy
Confirm that the push targets the configured production branch, the repository authorization is still valid and the project has not been paused by a failed configuration. Review the deployment list and build log.
Best Value
Custom apex domain will not activate
Verify that the domain is a zone in the same Cloudflare account and that its nameservers point to Cloudflare. For a subdomain, follow the DNS record instructions shown by the project.
Redirect or header has no effect
Ensure _redirects or _headers is in the final asset directory. If a Pages Function handles the request, configure the redirect or header in that Function instead.
Frequently Asked Questions
Can I host a static site on Cloudflare Pages without GitHub?
Yes. Use Direct Upload or C3. GitHub and GitLab are required only for the documented Git integration route.
Does Cloudflare Pages run server-side code?
Pages can serve static files and integrate with Pages Functions, but this guide covers a static deployment. Function responses follow different redirect and header rules.
Can I change a Pages project from Git integration to Direct Upload later?
Cloudflare documents that a Git-integrated project cannot be converted to Direct Upload; choose the deployment model before creating the project.
Quick Recap
Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.




