Managing Workers with the API and IaC
Uploading and managing a Worker is easy with Wrangler, but sometimes you need to do it more programmatically or scalably. You might do this with IaC ("Infrastructure as Code") tools or by calling the Cloudflare API ↗ directly. Use cases for the API include build and deploy scripts, CI/CD pipelines, custom dev tools, or testing. We provide API SDK libraries for common languages that make interacting with the API easier, such as cloudflare-typescript ↗. For IaC, a common tool is HashiCorp's Terraform. You can use the Cloudflare Terraform Provider to create and manage Workers resources.
Here are examples of uploading a Worker script with common tools and languages. In particular, they highlight how to upload script content and format multipart upload metadata which is different with each approach.
Open a terminal or create a shell script to upload a Worker easily with curl. For this example, replace <account_id>
with your account id and <api_token>
with an API token (not Global API key). Reference the Upload Worker Module API docs here ↗.
curl https://api.cloudflare.com/client/v4/accounts/<account_id>/workers/scripts/my-hello-world-script \ -X PUT \ -H 'Authorization: Bearer <api_token>' \ -F 'metadata={ "main_module": "my-hello-world-script.mjs", "bindings": [ { "type": "plain_text", "name": "MESSAGE", "text": "Hello World!" } ], "compatibility_date": "2025-03-11" };type=application/json' \ -F 'my-hello-world-script.mjs=@-;filename=my-hello-world-script.mjs;type=application/javascript+module' <<EOFexport default { async fetch(request, env, ctx) { return new Response(env.MESSAGE, { status: 200 }); }};EOF
This example uses the cloudflare-typescript ↗ library which provides convenient access to the Cloudflare REST API from server-side JavaScript or TypeScript.
#!/usr/bin/env -S npm run tsn -T
/* * Generate an API token: https://developers.cloudflare.com/fundamentals/api/get-started/create-token/ * (Not Global API Key!) * * Find your account id: https://developers.cloudflare.com/fundamentals/setup/find-account-and-zone-ids/ * * Set these environment variables: * - CLOUDFLARE_API_TOKEN * - CLOUDFLARE_ACCOUNT_ID */
import Cloudflare from "cloudflare";
const client = new Cloudflare({ apiToken: process.env["CLOUDFLARE_API_TOKEN"] ?? "",});const accountID = process.env["CLOUDFLARE_ACCOUNT_ID"] ?? "";
async function main() { const scriptName = "my-hello-world-script"; const scriptFileName = `${scriptName}.mjs`; const scriptContent = ` export default { async fetch(request, env, ctx) { return new Response(env.MESSAGE, { status: 200 }); } }; `;
const script = await client.workers.scripts.update(scriptName, { account_id: accountID, /* * Add script content keyed by the filename */ // @ts-ignore [scriptFileName]: new File([scriptContent], scriptFileName, { type: "application/javascript+module", }), // @ts-ignore metadata: new File( [ JSON.stringify({ // https://developers.cloudflare.com/workers/configuration/multipart-upload-metadata/ bindings: [ { type: "plain_text", name: "MESSAGE", text: "Hello World!", }, ], main_module: scriptFileName, }), ], "metadata.json", { type: "application/json", }, ), });
console.log(script.id);}
main();
#!/usr/bin/env -S npm run tsn -T
/* * Generate an API token: https://developers.cloudflare.com/fundamentals/api/get-started/create-token/ * (Not Global API Key!) * * Find your account id: https://developers.cloudflare.com/fundamentals/setup/find-account-and-zone-ids/ * * Set these environment variables: * - CLOUDFLARE_API_TOKEN * - CLOUDFLARE_ACCOUNT_ID */
import Cloudflare from 'cloudflare';
const client = new Cloudflare({ apiToken: process.env['CLOUDFLARE_API_TOKEN'] ?? '',});const accountID = process.env['CLOUDFLARE_ACCOUNT_ID'] ?? '';
async function main() { const scriptName = 'my-hello-world-script'; const scriptFileName = `${scriptName}.mjs`; const scriptContent = ` export default { async fetch(request, env, ctx) { return new Response(env.MESSAGE, { status: 200 }); } }; `;
const script: Cloudflare.Workers.Scripts.ScriptUpdateResponse = await client.workers.scripts.update( scriptName, { account_id: accountID, /* * Add script content keyed by the filename */ // @ts-ignore [scriptFileName]: new File([scriptContent], scriptFileName, { type: 'application/javascript+module', }), // @ts-ignore metadata: new File( [ JSON.stringify({ // https://developers.cloudflare.com/workers/configuration/multipart-upload-metadata/ bindings: [ { type: 'plain_text', name: 'MESSAGE', text: 'Hello World!', }, ], main_module: scriptFileName, }), ], 'metadata.json', { type: 'application/json', }, ), }, );
console.log(script.id);}
main();
In this example, you need a local file named my-hello-world-script.mjs
with script content similar to the above examples. Replace account_id
with your own. Learn more about the Cloudflare Terraform Provider here.
terraform { required_providers { cloudflare = { source = "cloudflare/cloudflare" version = "~> 5" } }}
resource "cloudflare_workers_script" "my-hello-world-script" { account_id = "<replace_me>" script_name = "my-hello-world-script" main_module = "my-hello-world-script.mjs" content = trimspace(file("my-hello-world-script.mjs")) bindings = [{ name = "MESSAGE" type = "plain_text" text = "Hello World!" }]}
Was this helpful?
- Resources
- API
- New to Cloudflare?
- Products
- Sponsorships
- Open Source
- Support
- Help Center
- System Status
- Compliance
- GDPR
- Company
- cloudflare.com
- Our team
- Careers
- 2025 Cloudflare, Inc.
- Privacy Policy
- Terms of Use
- Report Security Issues
- Trademark