Standalone Workers
CreatedApr 4, 2026UpdatedApr 5, 2026Takeshi Takatsudo
Deploying independent Workers separate from Pages
When to Use
Standalone Workers are best for:
- Search workers — Dedicated search APIs with their own data and dependencies
- AI chat workers — LLM-powered endpoints with API key bindings
- Webhook handlers — Receiving callbacks from external services
- Proxy workers — Routing or transforming requests
Project Structure
A typical standalone Worker project:
packages/my-worker/
├── src/
│ └── index.ts
├── wrangler.toml
├── package.json
└── tsconfig.json
Worker Entry Point
// src/index.ts
export default {
async fetch(request: Request, env: Env): Promise<Response> {
const url = new URL(request.url);
if (url.pathname === "/api/search") {
return handleSearch(request, env);
}
return new Response("Not Found", { status: 404 });
},
};
ExecutionContext and Background Processing
The third argument to fetch is ExecutionContext, which provides waitUntil() for running async work after the response is sent:
export default {
async fetch(
request: Request,
env: Env,
ctx: ExecutionContext,
): Promise<Response> {
// Return response immediately
const response = buildResponse(request, env);
// Run non-critical work in the background
ctx.waitUntil(logAnalytics(request, env));
ctx.waitUntil(updateCache(request, env));
return response;
},
};
This is critical for:
- Webhook handlers — Slack, GitHub, etc. require responses within 3 seconds. Process the webhook payload after responding.
- Logging and analytics — Don’t block the user’s response for non-critical writes.
- Cache warming — Update caches after serving a response.
⚠️ waitUntil does not extend CPU time
ctx.waitUntil() keeps the Worker alive after the response is sent, but does not increase the CPU time limit. Long-running operations may still be terminated.
## Deployment
Deploy with `wrangler deploy` (not `wrangler pages deploy`):
```bash
npx wrangler@4 deploy
In CI, deploy from the worker’s directory:
- name: Deploy Worker
working-directory: packages/my-worker
run: pnpm run deploy
env:
CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }}
CLOUDFLARE_ACCOUNT_ID: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
Path-Triggered Deploys
For monorepos with multiple workers, trigger deploys only when the worker’s files change:
on:
push:
branches:
- main
paths:
- 'packages/my-worker/**'
workflow_dispatch: # Allow manual triggers
This avoids unnecessary deploys when other parts of the monorepo change.