Back to Blog
Deploying Astro v6 to Cloudflare Workers
#cloudflare-workers #astro #deployment #wrangler #opentofu

Deploying Astro v6 to Cloudflare Workers

By Chris Smith
Published

Astro v6 released last month as I was building this site. I had already planned to deploy the site to Cloudflare Workers and upgraded from v5 as soon as I found out the development server is now able to work with Wrangler and run on workerd. This made debugging significantly easier since the dev environment was now similar to the deployed environment.

Today, I’ll walk you through my journey to full Wrangler integration, why OpenTofu fell short for Cloudflare Worker deployments, and what you need to know about Worker bindings and their unique behavior.

Choosing a Deployment Tool

Deploying the site to Cloudflare, I had to choose between two options, OpenTofu or Cloudflare’s Wrangler CLI.

I set out to use OpenTofu because I expected I would need to provision other items besides the worker, and it’s more flexible than a TOML config file for Wrangler. In theory, OpenTofu gives you dynamic environment variables and a clean separation of concerns. But in practice, I struggled to find a way to upload the final build with OpenTofu.

Dealing with Chunked Build Output

Astro’s build output is chunked across multiple files, making it difficult to upload with Terraform/OpenTofu as a single artifact. You’d need to handle individual file uploads or use a bundler that produces a single artifact. I did not want to modify or attempt to maintain a build system on top of the framework. Wrangler is already a required dependency and is able to handle this.

TOML Limitations

TOML files lack native support for shell variables like .env files. They also don’t play well with dynamic environments. This rigidity forced me to maintain multiple configuration blocks.

Wrangler’s Environment Configuration

Wrangler introduced environment setups like [env.dev] and [env.prod], but these still feel rigid compared to what OpenTofu could offer. The only way to provide dynamic variables or names is to use the Wrangler cli option flags. The flags will override settings in the config file. Here is an example:

# wrangler.toml
name = "www-kenogo-tech"

[vars]
LOG_LEVEL = "debug"

[env.dev]
name = "www-kenogo-tech-dev-main"

[env.dev.vars]
LOG_LEVEL = "info"

Running wrangler deploy --env dev --name feature-1 will deploy a worker with the name feature-1 and variable LOG_LEVEL="info".

Configuration Management

Developing locally with Astro v6, the adapter uses Wrangler and hosts your workers in a similar workerd environment. In the development build, it pulls from your wrangler.toml config. If you are deploying the worker with OpenTofu you would need to maintain a separate config. Maintaining the two configurations over time would drift, and add unnecessary complexity.

It was clear that I needed to commit to using Wrangler to make this deployment work. There was no point in trying to maintain two configurations for the worker.

The Switch to Wrangler

When I made the move to pure Wrangler for the worker deployment, I used a Taskfile to help configure the build. This helped with consistency for the dynamic variables passed to the Wrangler CLI. Let me show you the final setup.

The Wrangler Configuration

Here’s a shortened version what the wrangler.toml looks like after the migration:

# wrangler.toml
"$schema" = "./node_modules/wrangler/config-schema.json"
name = "www-kenogo-tech"
main = "@astrojs/cloudflare/entrypoints/server"
compatibility_date = "2026-03-10"

[assets]
directory = "./dist/client"
run_worker_first = false
html_handling = "drop-trailing-slash"
binding = "ASSETS"

[observability]
enabled = true
head_sampling_rate = 1

# Development environment
[env.dev]
name = "www-kenogo-tech-dev-main"

[env.dev.vars]
LOG_LEVEL = "debug"

# Production environment
[env.prod]
name = "www-kenogo-tech-prod-main"
workers_dev = false

[[env.prod.routes]]
custom_domain = true
pattern = "www.kenogo.tech"

[env.prod.vars]
ENV = "prod"
LOG_LEVEL = "info"

The Astro Configuration

With Astro v6 and the Cloudflare adapter, the setup is tightly coupled with Wrangler:

// astro.config.ts
import mdx from "@astrojs/mdx";
import sitemap from "@astrojs/sitemap";
import cloudflare from "@astrojs/cloudflare";
import tailwindcss from "@tailwindcss/vite";
import { defineConfig } from "astro/config";

export default defineConfig({
  site: "https://www.kenogo.tech",
  output: "static",
  build: {
    format: "file",
  },
  adapter: cloudflare({
    imageService: "compile",
  }),
  integrations: [mdx(), sitemap()],
  vite: {
    plugins: [tailwindcss()],
  },
});

Taskfile for Deploying

Here is a condensed version of the taskfile that shows how to build with Astro and give dynamic variables to wrangler.

# taskfile.yml
version: "3"
#...
tasks:
  #...
  build:
    env:
      # Needed to help select the correct environment in the wrangler.toml
      CLOUDFLARE_ENV:
        ref: .ENV
    desc: Build the application
    cmds:
      - deno run wrangler types
      - deno run astro build --mode $ENV

  # Astro bundled a copy of the wrangler.toml with the
  # environment variables set in the build.
  # So we don't need to pass the --env flag here.
  deploy:
    desc: Deploy the application
    cmds:
      - deno run wrangler deploy
        --name {{.main_worker_name}}
        --var LOG_SERVICE:{{.main_worker_name}}
        --secrets-file .env
        --message {{.current_commit}}

Conclusion

The journey from OpenTofu to full Wrangler wasn’t seamless, but it was the only path forward for me with Astro v6. I hope these key takeaways will help save you headaches down the road:

Key Takeaways

  1. Embrace Wrangler for Astro v6: Astro v6 is tightly coupled with Wrangler. Trying to use OpenTofu to deploy / upload the worker code will result in maintainability issues and possibly deployment issues.

  2. One Configuration: Although it’s possible to deploy the worker with IaC, you will still need a wrangler.toml for development. I generally avoid maintaining dual configurations (OpenTofu + Wrangler).

  3. Use Wrangler CLI flags for dynamic variables: The toml configuration file does not permit shell variables. Use cli options to override and set dynamic variables.

If you’re starting a new Astro project, consider using Wrangler from the start. If you’re migrating from OpenTofu and Astro v5, expect a few obstacles but embrace the simplicity of Astro+Wrangler’s unified approach.

Happy deploying!