Automatically deploy pull request previews to Cloudflare Workers - just like Cloudflare Pages does for static sites!
Cloudflare Pages automatically creates preview deployments for every pull request, but this feature doesn't exist for Cloudflare Workers. This action fills that gap by automatically deploying your Workers to unique preview URLs for each PR.
- β¨ Automatic PR preview deployments
- π§Ή Automatic cleanup when PR is closed or merged
- π¬ Comments preview URL directly on your PR
- π¨ Fully customizable build process
- π¦ Supports npm, pnpm, and yarn
- π§ Works with any framework (Astro, Next.js, Remix, etc.)
- π― Simple setup with sensible defaults
- Go to Cloudflare Dashboard
- Click "Create Token"
- Use the "Edit Cloudflare Workers" template
- Or create a custom token with these permissions:
- Account > Cloudflare Workers Scripts > Edit
- Account > Account Settings > Read
- Copy your token
- Go to Cloudflare Dashboard
- Select your domain/account
- Scroll down on the right sidebar - you'll see "Account ID"
- Copy your Account ID
- Go to your repository settings
- Navigate to
Secrets and variables>Actions - Add these secrets:
CF_API_TOKEN- Your Cloudflare API TokenCF_ACCOUNT_ID- Your Cloudflare Account ID
Create .github/workflows/preview.yml:
name: Deploy PR Preview
on:
pull_request:
types: [opened, synchronize, reopened, closed]
permissions:
contents: read
pull-requests: write
deployments: write
jobs:
preview:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
# Deploy preview on PR open/update
- name: Deploy Preview
if: github.event.action != 'closed'
uses: mertselimb/cloudflare-workers-pr-preview@v1.0.1
with:
cloudflare-api-token: ${{ secrets.CF_API_TOKEN }}
cloudflare-account-id: ${{ secrets.CF_ACCOUNT_ID }}
# Cleanup preview on PR close/merge
- name: Cleanup Preview
if: github.event.action == 'closed'
uses: mertselimb/cloudflare-workers-pr-preview@v1.0.1
with:
cloudflare-api-token: ${{ secrets.CF_API_TOKEN }}
cloudflare-account-id: ${{ secrets.CF_ACCOUNT_ID }}
mode: cleanupThat's it! π
What happens:
- When a PR is opened or updated β Deploys preview to Cloudflare Workers
- When a PR is closed or merged β Automatically deletes the worker deployment
Example workflow: See
workflow-example.ymlfor a complete working example.
- uses: mertselimb/cloudflare-workers-pr-preview@v1.0.1
with:
cloudflare-api-token: ${{ secrets.CF_API_TOKEN }}
cloudflare-account-id: ${{ secrets.CF_ACCOUNT_ID }}- uses: mertselimb/cloudflare-workers-pr-preview@v1.0.1
with:
cloudflare-api-token: ${{ secrets.CF_API_TOKEN }}
cloudflare-account-id: ${{ secrets.CF_ACCOUNT_ID }}
build-command: npm run build:production
install-command: npm ci- uses: mertselimb/cloudflare-workers-pr-preview@v1.0.1
with:
cloudflare-api-token: ${{ secrets.CF_API_TOKEN }}
cloudflare-account-id: ${{ secrets.CF_ACCOUNT_ID }}
package-manager: pnpm
install-command: pnpm install --frozen-lockfile- uses: mertselimb/cloudflare-workers-pr-preview@v1.0.1
with:
cloudflare-api-token: ${{ secrets.CF_API_TOKEN }}
cloudflare-account-id: ${{ secrets.CF_ACCOUNT_ID }}
working-directory: ./apps/web
build-command: pnpm build- uses: mertselimb/cloudflare-workers-pr-preview@v1.0.1
with:
cloudflare-api-token: ${{ secrets.CF_API_TOKEN }}
cloudflare-account-id: ${{ secrets.CF_ACCOUNT_ID }}
subdomain: myapp
# Preview URL will be: https://myapp-pr-123.yourname.workers.dev- uses: mertselimb/cloudflare-workers-pr-preview@v1.0.1
with:
cloudflare-api-token: ${{ secrets.CF_API_TOKEN }}
cloudflare-account-id: ${{ secrets.CF_ACCOUNT_ID }}
comment-on-pr: false| Input | Description | Required | Default |
|---|---|---|---|
cloudflare-api-token |
Cloudflare API Token with Workers permissions | β Yes | - |
cloudflare-account-id |
Cloudflare Account ID | β Yes | - |
mode |
Action mode: deploy or cleanup |
No | deploy |
build-command |
Command to build your project | No | npm run build |
install-command |
Command to install dependencies | No | npm install |
node-version |
Node.js version to use | No | 18 |
working-directory |
Working directory for the project | No | . |
subdomain |
Custom subdomain prefix | No | Repository name |
comment-on-pr |
Whether to comment preview URL on PR | No | true |
package-manager |
Package manager (npm, pnpm, yarn) | No | npm |
wrangler-version |
Specific Wrangler version to use | No | Latest |
| Output | Description |
|---|---|
preview-url |
The deployed preview URL |
deployment-id |
The deployment ID |
- uses: mertselimb/cloudflare-workers-pr-preview@v1.0.1
id: preview
with:
cloudflare-api-token: ${{ secrets.CF_API_TOKEN }}
cloudflare-account-id: ${{ secrets.CF_ACCOUNT_ID }}
- name: Run E2E tests
run: npm run test:e2e
env:
PREVIEW_URL: ${{ steps.preview.outputs.preview-url }}Here's a full-featured example with testing and automatic cleanup:
name: PR Preview & Tests
on:
pull_request:
types: [opened, synchronize, reopened, closed]
permissions:
contents: read
pull-requests: write
deployments: write
jobs:
deploy-and-test:
if: github.event.action != 'closed'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: mertselimb/cloudflare-workers-pr-preview@v1.0.1
id: preview
with:
cloudflare-api-token: ${{ secrets.CF_API_TOKEN }}
cloudflare-account-id: ${{ secrets.CF_ACCOUNT_ID }}
build-command: npm run build
package-manager: npm
- name: Run E2E tests against preview
run: npm run test:e2e
env:
BASE_URL: ${{ steps.preview.outputs.preview-url }}
- name: Run Lighthouse
uses: treosh/lighthouse-ci-action@v1.0.1
with:
urls: ${{ steps.preview.outputs.preview-url }}
uploadArtifacts: true
cleanup:
if: github.event.action == 'closed'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: mertselimb/cloudflare-workers-pr-preview@v1.0.1
with:
cloudflare-api-token: ${{ secrets.CF_API_TOKEN }}
cloudflare-account-id: ${{ secrets.CF_ACCOUNT_ID }}
mode: cleanup- Checkout: Gets your code
- Setup Node.js: Installs specified Node version
- Install Dependencies: Runs your install command
- Build: Runs your build command
- Deploy: Deploys to Cloudflare Workers with name
{repo}-pr-{number} - Comment: Posts preview URL to your PR
- Checkout: Gets your code
- Delete Worker: Removes the worker deployment from Cloudflare
- Comment: Updates PR comment with cleanup notification
The preview URL follows this pattern:
https://{subdomain}-pr-{pr-number}.{github-username}.workers.dev
For example:
- Repository:
johndoe/my-app - PR Number: 42
- Preview URL:
https://my-app-pr-42.johndoe.workers.dev
- uses: mertselimb/cloudflare-workers-pr-preview@v1.0.1
with:
cloudflare-api-token: ${{ secrets.CF_API_TOKEN }}
cloudflare-account-id: ${{ secrets.CF_ACCOUNT_ID }}
build-command: npm run build- uses: mertselimb/cloudflare-workers-pr-preview@v1.0.1
with:
cloudflare-api-token: ${{ secrets.CF_API_TOKEN }}
cloudflare-account-id: ${{ secrets.CF_ACCOUNT_ID }}
build-command: npm run build- uses: mertselimb/cloudflare-workers-pr-preview@v1.0.1
with:
cloudflare-api-token: ${{ secrets.CF_API_TOKEN }}
cloudflare-account-id: ${{ secrets.CF_ACCOUNT_ID }}
build-command: npm run buildMake sure your workflow has these permissions:
permissions:
contents: read
pull-requests: write
deployments: writeVerify your token has the correct permissions:
- Account > Cloudflare Workers Scripts > Edit
- Account > Account Settings > Read
Check that:
- Your
build-commandis correct - All dependencies are in
package.json - You have a valid
wrangler.tomlin your project root
Make sure you have a wrangler.toml file in your working directory:
name = "my-worker"
main = "dist/index.js"
compatibility_date = "2024-01-01"Contributions are welcome! Please feel free to submit a Pull Request.
MIT License - see LICENSE file for details.
Created by @mertselimb
Inspired by Cloudflare Pages automatic PR previews.
β If this action helped you, consider giving it a star!