Two production features for Pages
Cloudflare Pages has added deployment rollbacks and a public API. Rollbacks let a production site return to a known-good build without waiting on a new build, while the API opens up automation and integration with existing development workflows.
These follow the general availability announcement of Pages and previously requested additions such as URL redirects, web analytics, and Access integration.
Rolling back production
Restoring a previous working deployment now takes a single click, which is useful for quickly undoing a deployment while troubleshooting. The earlier workflow required pushing another deployment and waiting for the build to finish before production updated; a rollback instead restores a working version in moments.
The control is the "Rollback to this deployment" button, available either in the deployments list menu or on an individual deployment page.

API access
The Pages API exposes endpoints for building automations and fitting Pages into a development workflow. Once you copy your "Global API Key" from the Cloudflare API Tokens page, you authenticate and issue requests using your email and auth key in the request headers. The API documentation covers the full set of object types and endpoints.
A request fetching all projects on an account:
Request (example)
curl -X GET "https://api.cloudflare.com/client/v4/accounts/{account_id}/pages/projects" \
-H "X-Auth-Email: {email}" \
-H "X-Auth-Key: {auth_key}"
Response (example)
{
"success": true,
"errors": [],
"messages": [],
"result": {
"name": "NextJS Blog",
"id": "7b162ea7-7367-4d67-bcde-1160995d5",
"created_on": "2017-01-01T00:00:00Z",
"subdomain": "helloworld.pages.dev",
"domains": [
"customdomain.com",
"customdomain.org"
],
"source": {
"type": "github",
"config": {
"owner": "cloudflare",
"repo_name": "ninjakittens",
"production_branch": "main",
"pr_comments_enabled": true,
"deployments_enabled": true
}
},
"build_config": {
"build_command": "npm run build",
"destination_dir": "build",
"root_dir": "/",
"web_analytics_tag": "cee1c73f6e4743d0b5e6bb1a0bcaabcc",
"web_analytics_token": "021e1057c18547eca7b79f2516f06o7x"
},
"deployment_configs": {
"preview": {
"env_vars": {
"BUILD_VERSION": {
"value": "3.3"
}
}
},
"production": {
"env_vars": {
"BUILD_VERSION": {
"value": "3.3"
}
}
}
},
"latest_deployment": {
"id": "f64788e9-fccd-4d4a-a28a-cb84f88f6",
"short_id": "f64788e9",
"project_id": "7b162ea7-7367-4d67-bcde-1160995d5",
"project_name": "ninjakittens",
"environment": "preview",
"url": "https://f64788e9.ninjakittens.pages.dev",
"created_on": "2021-03-09T00:55:03.923456Z",
"modified_on": "2021-03-09T00:58:59.045655",
"aliases": [
"https://branchname.projectname.pages.dev"
],
"latest_stage": {
"name": "deploy",
"started_on": "2021-03-09T00:55:03.923456Z",
"ended_on": "2021-03-09T00:58:59.045655",
"status": "success"
},
"env_vars": {
"BUILD_VERSION": {
"value": "3.3"
},
"ENV": {
"value": "STAGING"
}
},
"deployment_trigger": {
"type": "ad_hoc",
"metadata": {
"branch": "main",
"commit_hash": "ad9ccd918a81025731e10e40267e11273a263421",
"commit_message": "Update index.html"
}
},
"stages": [
{
"name": "queued",
"started_on": "2021-06-03T15:38:15.608194Z",
"ended_on": "2021-06-03T15:39:03.134378Z",
"status": "active"
},
{
"name": "initialize",
"started_on": null,
"ended_on": null,
"status": "idle"
},
{
"name": "clone_repo",
"started_on": null,
"ended_on": null,
"status": "idle"
},
{
"name": "build",
"started_on": null,
"ended_on": null,
"status": "idle"
},
{
"name": "deploy",
"started_on": null,
"ended_on": null,
"status": "idle"
}
],
"build_config": {
"build_command": "npm run build",
"destination_dir": "build",
"root_dir": "/",
"web_analytics_tag": "cee1c73f6e4743d0b5e6bb1a0bcaabcc",
"web_analytics_token": "021e1057c18547eca7b79f2516f06o7x"
},
"source": {
"type": "github",
"config": {
"owner": "cloudflare",
"repo_name": "ninjakittens",
"production_branch": "main",
"pr_comments_enabled": true,
"deployments_enabled": true
}
}
},
"canonical_deployment": {
"id": "f64788e9-fccd-4d4a-a28a-cb84f88f6",
"short_id": "f64788e9",
"project_id": "7b162ea7-7367-4d67-bcde-1160995d5",
"project_name": "ninjakittens",
"environment": "preview",
"url": "https://f64788e9.ninjakittens.pages.dev",
"created_on": "2021-03-09T00:55:03.923456Z",
"modified_on": "2021-03-09T00:58:59.045655",
"aliases": [
"https://branchname.projectname.pages.dev"
],
"latest_stage": {
"name": "deploy",
"started_on": "2021-03-09T00:55:03.923456Z",
"ended_on": "2021-03-09T00:58:59.045655",
"status": "success"
},
"env_vars": {
"BUILD_VERSION": {
"value": "3.3"
},
"ENV": {
"value": "STAGING"
}
},
"deployment_trigger": {
"type": "ad_hoc",
"metadata": {
"branch": "main",
"commit_hash": "ad9ccd918a81025731e10e40267e11273a263421",
"commit_message": "Update index.html"
}
},
"stages": [
{
"name": "queued",
"started_on": "2021-06-03T15:38:15.608194Z",
"ended_on": "2021-06-03T15:39:03.134378Z",
"status": "active"
},
{
"name": "initialize",
"started_on": null,
"ended_on": null,
"status": "idle"
},
{
"name": "clone_repo",
"started_on": null,
"ended_on": null,
"status": "idle"
},
{
"name": "build",
"started_on": null,
"ended_on": null,
"status": "idle"
},
{
"name": "deploy",
"started_on": null,
"ended_on": null,
"status": "idle"
}
],
"build_config": {
"build_command": "npm run build",
"destination_dir": "build",
"root_dir": "/",
"web_analytics_tag": "cee1c73f6e4743d0b5e6bb1a0bcaabcc",
"web_analytics_token": "021e1057c18547eca7b79f2516f06o7x"
},
"source": {
"type": "github",
"config": {
"owner": "cloudflare",
"repo_name": "ninjakittens",
"production_branch": "main",
"pr_comments_enabled": true,
"deployments_enabled": true
}
}
}
},
"result_info": {
"page": 1,
"per_page": 100,
"count": 1,
"total_count": 1
}
}
And a request that rolls back to a previous deployment:
Request (example)
curl -X POST "https://api.cloudflare.com/client/v4/accounts/{account_id}/pages/projects/{project_name}/deployments/{deployment_id}/rollback" \
-H "X-Auth-Email: {email}" \
-H "X-Auth-Key: {auth_key"
Response (example)
{
"success": true,
"errors": [],
"messages": [],
"result": {
"id": "f64788e9-fccd-4d4a-a28a-cb84f88f6",
"short_id": "f64788e9",
"project_id": "7b162ea7-7367-4d67-bcde-1160995d5",
"project_name": "ninjakittens",
"environment": "preview",
"url": "https://f64788e9.ninjakittens.pages.dev",
"created_on": "2021-03-09T00:55:03.923456Z",
"modified_on": "2021-03-09T00:58:59.045655",
"aliases": [
"https://branchname.projectname.pages.dev"
],
"latest_stage": {
"name": "deploy",
"started_on": "2021-03-09T00:55:03.923456Z",
"ended_on": "2021-03-09T00:58:59.045655",
"status": "success"
},
"env_vars": {
"BUILD_VERSION": {
"value": "3.3"
},
"ENV": {
"value": "STAGING"
}
},
"deployment_trigger": {
"type": "ad_hoc",
"metadata": {
"branch": "main",
"commit_hash": "ad9ccd918a81025731e10e40267e11273a263421",
"commit_message": "Update index.html"
}
},
"stages": [
{
"name": "queued",
"started_on": "2021-06-03T15:38:15.608194Z",
"ended_on": "2021-06-03T15:39:03.134378Z",
"status": "active"
},
{
"name": "initialize",
"started_on": null,
"ended_on": null,
"status": "idle"
},
{
"name": "clone_repo",
"started_on": null,
"ended_on": null,
"status": "idle"
},
{
"name": "build",
"started_on": null,
"ended_on": null,
"status": "idle"
},
{
"name": "deploy",
"started_on": null,
"ended_on": null,
"status": "idle"
}
],
"build_config": {
"build_command": "npm run build",
"destination_dir": "build",
"root_dir": "/",
"web_analytics_tag": "cee1c73f6e4743d0b5e6bb1a0bcaabcc",
"web_analytics_token": "021e1057c18547eca7b79f2516f06o7x"
},
"source": {
"type": "github",
"config": {
"owner": "cloudflare",
"repo_name": "ninjakittens",
"production_branch": "main",
"pr_comments_enabled": true,
"deployments_enabled": true
}
}
}
}
To try it against one of your own projects, substitute {account_id}, {deployment_id}, {email} and {auth_key}. The account_id appears in the URL address bar when you navigate the Cloudflare Dashboard — for example, 41643ed677c7c7gba4x463c4zdb9563c.
Pages API on Workers
Combining the API with Cloudflare Workers is one way to automate common tasks. Three examples:
- Triggering a new build every hour. A CMS that compiles static output from live sources can stay fresh if builds are triggered periodically through the API.
- Deleting old deployments. Pages serves every project deployment on a preview link; deployments can be deleted after a month so they are no longer public online.
- Sharing project information. Deployment status and preview links can be served as HTML from a Worker, so teammates can see them without sharing Cloudflare accounts.
Code snippets for all three are available in the Pages API documentation.
Hourly build trigger, step by step
Create a Worker at workers.new; newcomers can follow the getting started guide. You need an existing Pages project to follow along.
const endpoint = "https://api.cloudflare.com/client/v4/accounts/{account_id}/pages/projects/{project_name}/deployments";
const email = "{your_email}";
addEventListener("scheduled", (event) => {
event.waitUntil(handleScheduled(event.scheduledTime));
});
async function handleScheduled(request) {
const init = {
method: "POST",
headers: {
"content-type": "application/json;charset=UTF-8",
"X-Auth-Email": email,
"X-Auth-Key": API_KEY,
//We recommend you store API keys as secrets using the Workers dashboard or using Wrangler as documented here https://developers.cloudflare.com/workers/cli-wrangler/commands#secret
},
};
const response = await fetch(endpoint, init);
return new Response(200);
}
Paste the template into the Worker, then customize the values such as {account_id}, {project_name}, {auth_key}, and {your_email}. The script issues a POST request to the deployments endpoint to trigger a build.
To finish configuring it, use the back arrow near the top left of the window, open the settings tab, and set an environment variable API_KEY to your Cloudflare Global key. Click "Encrypt", then "Save".
Return to the code editor via "Quick edit" to test. In the "Schedule" tab, next to the "HTTP" and "Preview" tabs, "Trigger scheduled event" makes a request and a new queued build should appear in the Pages dashboard for the project. "Save and Deploy" publishes the work, and the back arrow returns to the Worker settings page.
The last step is periodic execution: on the "Triggers" tab, click "Add Cron Trigger".

Enter 0 * * * * to run the build every hour.

Saving the trigger completes the automation, and the Pages API then starts a new build each hour.
What's next
Rollbacks are live now, and the API is expected to gain capabilities such as support for prebuilt deployments.
Feedback is welcome on the Workers Discord, which has a dedicated #pages-help channel.



