switching from Cloudflare Pages

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.

  • _redirects beyond 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

  1. 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.
  2. 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.
  3. 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)
  4. STEP 04

    Deploy the build output

    Same output directory your Pages project builds. Add --spa if _redirects had 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/
  5. 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=mysite
    after
    - uses: one9x/pages-deploy@v1
      with:
        site: mysite
        dir: dist
        token: ${{ secrets.ONE9X_TOKEN }}
        deploy: ${{ github.ref == 'refs/heads/main' }}
        comment: true
  6. 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.
  7. STEP 07

    Delete the Pages project

    Once traffic has moved, so two builds are not racing to serve the same name, and remove _redirects, _headers and _routes.json from 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.