A Cloudflare Pages alternative that is one product, not a platform
Static hosting as the whole thing, rather than a tab inside an account that also does DNS, security, tunnels and workers.
Cloudflare Pages sits on one of the best networks on earth with a famously generous free tier, and if you are already running your DNS and security there, keeping the site in the same account is the sensible choice. This page is not going to argue that our network is bigger than Cloudflare’s.
What it is for is the person whose static site somehow became an infrastructure account: a dashboard with dozens of products in it, a deploy path that assumes Git or Wrangler, and a mental model where hosting a folder is one feature among many. One9x Pages does one thing. Everything in the product is the deploy of a folder, the release it becomes, and the domain it serves on.
Where the two actually differ
Structural differences only — what each product fundamentally is. No plan names and no prices for Cloudflare Pages, because those change without telling us and a stale number here would mislead exactly the person who came to check one.
Surface area
One9x Pages
One product. Sites, releases, domains — and a published roadmap.
Cloudflare Pages
One product inside a large platform account.
Getting a folder online
One9x Pages
Drag it onto the dashboard, or one CLI command. No account setup between you and a URL.
Cloudflare Pages
Git connection or Wrangler, inside the platform account model.
Push-to-deploy
One9x Pages
A GitHub Action you add to the repo — PR previews and publish-on-merge, with the build in your own CI.
Cloudflare Pages
Built in, from the connected repository.
Rollback
One9x Pages
Any kept release, instantly, by pointer flip. Nothing to purge.
Cloudflare Pages
Roll back to a previous deployment from the dashboard.
Caching
One9x Pages
Content-addressed, so there is no purge button — a changed file is a new URL.
Cloudflare Pages
Platform caching, with purge controls to understand.
Support
One9x Pages
Email support on every plan including free; priority on Pro and up.
Cloudflare Pages
Community support at the free tier.
Price shape
One9x Pages
A flat monthly figure. No metered dimension anywhere.
Cloudflare Pages
Free tier plus usage-priced platform services around it.
When to stay on Cloudflare Pages
Three cases where moving would cost you something we cannot give back. If one of them is yours, this is the wrong product and you should not have to read to the bottom of a sales page to find that out.
- You need Workers, D1, R2, KV, or Access in front of the site. Those are Cloudflare products and there is no equivalent here.
- Your DNS, WAF and certificates already live in Cloudflare and you want one place to hold them. Splitting a domain across two providers is real overhead.
- You serve a very large amount of traffic from a free tier. Cloudflare’s free bandwidth is not something we are going to undercut.
Moving a site from Cloudflare Pages
What your configuration maps to, what has no equivalent at all, and the order to do it in. The middle one is the part that decides whether this is an afternoon.
What maps to what
| On Cloudflare Pages | Here |
|---|---|
| Build output directory | The directory you hand to the deploy. |
| Build command, run by Cloudflare | Runs in your own CI — the GitHub Action. |
_redirects with /* /index.html 200 | --spa. |
A 404.html | --error 404:/404.html. |
| Preview deployments per branch or PR | The Action stages a release per PR and comments the URL. |
| Rolling back to a previous deployment | one9x pages deploy --to v6, or the dashboard. |
| Build environment variables | Repository secrets in your CI. |
| Cache purge after a deploy | Nothing to purge — a changed file is a different hash at a different URL. |
What has no equivalent
Handle these before you move DNS, not after. Pages serves files: it has an SPA fallback, custom error pages and an exclude list, and it has no redirect table and no custom response headers.
-
_redirectsbeyond the SPA line, and_headers. Cloudflare Pages supports both properly; we support neither. This is the most likely thing to break on this particular move, so read your files before you start. -
functions/and_routes.json. Pages Functions are Workers. There is no runtime here for them to become. - Everything else in the account. Access policies, Workers bindings, D1, R2, KV. If the site depends on any of them, it is not a static site being hosted — it is an application, and it should stay.
The order to do it in
-
STEP 01
Read _redirects and _headers line by line
Start here, because this is the step that decides whether the move works at all. Cloudflare Pages supports both files properly and we support neither — only the catch-all SPA line has an equivalent. Anything else needs somewhere to go before you continue. -
STEP 02
Check for functions/ and _routes.json
Pages Functions are Workers. There is no runtime here for them to become, so if either is doing real work, the site is an application rather than a static site and it belongs where the runtime is. -
STEP 03
Create the site and a CI token
A site has to exist before anything can deploy to it — the action will not create one, so a typo fails instead of quietly publishing to a new address. Do both from the dashboard if you prefer.once$ one9x pages create mysite ✓ created mysite → https://mysite.one9x.app/ $ one9x tokens create "github actions" one9x_tok_7Kd… (shown once) -
STEP 04
Deploy the build output
Same output directory your Pages project builds. Add--spaif_redirectshad the catch-all line. Nothing on your live site moves — this stages.first deploy$ one9x pages release ./dist --site mysite --spa ✓ v1 staged → https://v1--mysite.one9x.app/ -
STEP 05
Swap the deploy step in CI
If your Pages project builds from the Git integration, you are writing your first workflow and GitHub Actions has it in full. If you already deploy with Wrangler from Actions, it is the same workflow with one step swapped.before- uses: cloudflare/wrangler-action@v3 with: apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }} accountId: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }} command: pages deploy dist --project-name=mysiteafter- uses: one9x/pages-deploy@v1 with: site: mysite dir: dist token: ${{ secrets.ONE9X_TOKEN }} deploy: ${{ github.ref == 'refs/heads/main' }} comment: true -
STEP 06
Repoint the domain — DNS-only, not proxied
If you keep Cloudflare for DNS, set the record to DNS-only (grey cloud) rather than proxied. Proxied, the certificate challenge cannot reach us and issuance silently never completes. Lower the TTL a day ahead as usual. -
STEP 07
Delete the Pages project
Once traffic has moved, so two builds are not racing to serve the same name, and remove_redirects,_headersand_routes.jsonfrom the repo in the same commit.
Your live site on Cloudflare Pages keeps serving throughout — nothing here touches it until you move DNS, and the free plan is enough to do the whole rehearsal first.
Try it with one site
The free plan takes three sites, no card, and does not expire. Deploy the folder you already have and see what it looks like before anything moves.
also compared