Start a Project
All guides

Dev Stack

Deploy Astro to Cloudflare Workers from South Africa.

If you host a .co.za site on Afrihost, Xneelo or WebAfrica shared hosting, you already know the pain — TTFB north of 600ms from a Johannesburg visitor, and PHP stack tax on every request. Moving an Astro build onto Cloudflare Workers lands your site on the JNB and CPT points of presence, so a fibre user in Sandton or Claremont sees first-byte in under 40ms. This guide documents the exact wrangler.jsonc pattern we run on ecomsolve.co.za and a dozen client builds, including the custom domain binding that lets you keep your .za domain registered with Afrihost or domains.co.za while serving from Cloudflare. No SSR adapter, no origin server, no surprise renewal invoices in dollars.

Updated 15 April 2026 · 9 min read · Cloudflare Workers · Joshua Kaplan

Prerequisites

  • Node 20+ and npm installed locally
  • A Cloudflare account (free plan is fine — 100k requests/day)
  • Your .co.za domain added to Cloudflare as a zone (nameservers pointed from Afrihost/Xneelo/domains.co.za)
  • An existing Astro project or a willingness to scaffold one

Step 1. Scaffold Astro with static output

Cloudflare Workers serves static assets directly — no SSR adapter needed for a brochure site or content build. Keep output: 'static' in astro.config.mjs and set site to your production .co.za URL so @astrojs/sitemap emits absolute URLs.

astro.config.mjs
import { defineConfig } from 'astro/config';
import sitemap from '@astrojs/sitemap';

export default defineConfig({
  site: 'https://ecomsolve.co.za',
  output: 'static',
  integrations: [sitemap()],
  build: { assets: '_astro' },
});

Step 2. Install Wrangler and log in

Wrangler is the Cloudflare CLI. You are not writing a Worker script — you are using the static assets binding, which is the cheaper and faster path for Astro static output.

npm install --save-dev wrangler
npx wrangler login

Step 3. Write wrangler.jsonc with the assets binding

Point assets.directory at ./dist (Astro's default output). Routes use custom_domain: true so Cloudflare provisions the cert and binds both apex and www. Compatibility date should be recent; nodejs_compat is cheap insurance if you later add a Worker function.

wrangler.jsonc
{
  "$schema": "node_modules/wrangler/config-schema.json",
  "name": "your-site",
  "compatibility_date": "2026-02-18",
  "compatibility_flags": ["nodejs_compat"],
  "assets": { "directory": "./dist" },
  "routes": [
    { "pattern": "yoursite.co.za", "custom_domain": true },
    { "pattern": "www.yoursite.co.za", "custom_domain": true }
  ],
  "observability": { "enabled": true }
}

Step 4. Add a _headers file for security and caching

Cloudflare reads public/_headers from the asset directory. Set a long cache on the hashed /_astro/* bundle (Astro fingerprints filenames) and sensible security headers for the root.

public/_headers
/*
  X-Content-Type-Options: nosniff
  X-Frame-Options: DENY
  Referrer-Policy: strict-origin-when-cross-origin
  Permissions-Policy: camera=(), microphone=(), geolocation=()

/_astro/*
  Cache-Control: public, max-age=31536000, immutable

/fonts/*
  Cache-Control: public, max-age=31536000, immutable

Step 5. Add deploy scripts to package.json

One script, one deploy. Build runs Astro, wrangler deploy pushes the dist directory to the Workers platform and attaches the custom domains on first run.

package.json
{
  "scripts": {
    "dev": "astro dev",
    "build": "astro build",
    "deploy": "astro build && wrangler deploy",
    "preview": "wrangler dev"
  }
}

Step 6. Point your .co.za domain at Cloudflare

In your registrar (Afrihost, Xneelo, domains.co.za), change nameservers to the two Cloudflare NS records shown in the dashboard. Propagation over SA DNS resolvers usually settles within 30–60 minutes. Once the zone is Active, the custom_domain routes in wrangler.jsonc will attach automatically on the next deploy.

Step 7. Run the first deploy

wrangler deploy uploads your dist directory as static assets. First deploy takes 30–60 seconds; subsequent deploys are faster because only changed files are re-uploaded. Cloudflare auto-provisions an Edge TLS cert for both hostnames.

npm run deploy
# → Deployed your-site triggers (1.2 sec)
#   https://yoursite.co.za
#   https://www.yoursite.co.za

Step 8. Verify from a Johannesburg or Cape Town connection

Use curl -w "%{time_starttransfer}" from a Rain, Vumatel or Afrihost Pure Fibre line. You should see TTFB under 50ms. If you see 150ms+, check that the request actually hit the JNB or CPT colo (look at the cf-ray header — the last three chars are the airport code, e.g. JNB or CPT).

SA gotchas

  • Do not install an SSR adapter unless you need it — static output ships smaller and hits the edge cache on every request. SSR on Workers pulls you into the 1MB script size limit and costs you the free plan's unlimited static requests.
  • Astro fingerprints fonts under /_astro/*.woff2. If you preload with a hardcoded filename, it will break on the next build. Either use link preload generation from @fontsource-variable or skip preload and rely on the _headers long cache.
  • The free plan caps requests at 100k/day across Workers (not static asset requests — those are unlimited). A brochure site will never hit this; a high-traffic app or exposed API will. The Paid plan is USD $5/month, billed monthly in dollars — budget for ZAR exchange rate swings.
  • Custom domains need the zone to be Active in Cloudflare before wrangler deploy can bind routes. If you deploy while the zone is still Pending, you get a confusing "route not found" error. Wait for nameserver propagation first.
  • Observability is off by default on older compatibility dates. Add observability.enabled = true in wrangler.jsonc so you get request logs in the dashboard — essential when a POPIA cookie banner vendor starts throwing CORS errors from a Johannesburg IP.

Frequently asked questions

Is Cloudflare Workers cheaper than Afrihost for a small Astro site?

Yes. The free plan covers most brochure and marketing sites entirely. Afrihost shared hosting starts around R99/month; Cloudflare Workers free gets you the same static site with faster TTFB from SA visitors and global failover. You pay only for Workers script invocations, not static asset hits.

Can I keep my .co.za domain registered with my current registrar?

Yes. Registration and DNS are separate. Keep the domain at Afrihost, Xneelo or domains.co.za, and just change the nameservers to Cloudflare. You pay zero to Cloudflare for DNS.

Do I need Cloudflare Pages instead of Workers?

Pages is being folded into Workers. New projects should use the Workers static assets binding (this guide). Pages still works, but the Workers path gives you Durable Objects, KV and D1 on the same deployment if you ever need dynamic bits.

How do Cloudflare PoPs in South Africa affect latency?

Cloudflare operates edge locations in Johannesburg and Cape Town, peering with local ISPs including Afrihost, MTN and Openserve. A request from a Johannesburg fibre line usually terminates at the JNB PoP in under 15ms — the static asset is served from local cache without crossing the Atlantic. Compare this with a London-hosted origin, where the round trip adds 150–200ms.