---
title: Workers Changelog
image: https://developers.cloudflare.com/cf-twitter-card.png
---

> Documentation Index  
> Fetch the complete documentation index at: https://developers.cloudflare.com/changelog/llms.txt  
> Use this file to discover all available pages before exploring further. 

[Skip to content](#%5Ftop) 

# Changelog

New updates and improvements at Cloudflare.

[ Subscribe to RSS ](https://developers.cloudflare.com/changelog/rss/index.xml) [ View RSS feeds ](https://developers.cloudflare.com/fundamentals/new-features/available-rss-feeds/) 

Workers

![hero image](https://developers.cloudflare.com/_astro/hero.CVYJHPAd_26AMqX.svg) 

Jan 31, 2025
1. ### [Transform HTML quickly with streaming content](https://developers.cloudflare.com/changelog/post/2025-01-31-html-rewriter-streaming/)  
[ Workers ](https://developers.cloudflare.com/workers/)  
You can now transform HTML elements with streamed content using [HTMLRewriter](https://developers.cloudflare.com/workers/runtime-apis/html-rewriter).  
Methods like `replace`, `append`, and `prepend` now accept [Response](https://developers.cloudflare.com/workers/runtime-apis/response/) and [ReadableStream](https://developers.cloudflare.com/workers/runtime-apis/streams/readablestream/)values as [Content](https://developers.cloudflare.com/workers/runtime-apis/html-rewriter/#global-types).  
This can be helpful in a variety of situations. For instance, you may have a Worker in front of an origin, and want to replace an element with content from a different source. Prior to this change, you would have to load all of the content from the upstream URL and convert it into a string before replacing the element. This slowed down overall response times.  
Now, you can pass the `Response` object directly into the `replace` method, and HTMLRewriter will immediately start replacing the content as it is streamed in. This makes responses faster.

  * [  JavaScript ](#tab-panel-3131)
  * [  TypeScript ](#tab-panel-3132)

**index.js**  
```js  
class ElementRewriter {  
  async element(element) {  
    // able to replace elements while streaming content  
    // the fetched body is not buffered into memory as part  
    // of the replace  
    let res = await fetch("https://upstream-content-provider.example");  
    element.replace(res);  
  }  
}  
export default {  
  async fetch(request, env, ctx) {  
    let response = await fetch("https://site-to-replace.com");  
    return new HTMLRewriter()  
      .on("[data-to-replace]", new ElementRewriter())  
      .transform(response);  
  },  
};  
```

**index.ts**  
```ts  
class ElementRewriter {  
  async element(element: any) {  
    // able to replace elements while streaming content  
    // the fetched body is not buffered into memory as part  
    // of the replace  
    let res = await fetch('https://upstream-content-provider.example');  
    element.replace(res);  
  }  
}  
export default {  
  async fetch(request, env, ctx): Promise<Response> {  
    let response = await fetch('https://site-to-replace.com');  
    return new HTMLRewriter().on('[data-to-replace]', new ElementRewriter()).transform(response);  
  },  
} satisfies ExportedHandler<Env>;  
```  
For more information, see the [HTMLRewriter documentation](https://developers.cloudflare.com/workers/runtime-apis/html-rewriter).

Jan 30, 2025
1. ### [Increased Browser Rendering limits!](https://developers.cloudflare.com/changelog/post/2025-01-30-browser-rendering-more-instances/)  
[ Workers ](https://developers.cloudflare.com/workers/)[ Browser Run ](https://developers.cloudflare.com/browser-run/)  
[Browser Rendering](https://developers.cloudflare.com/browser-run/) now supports 10 concurrent browser instances per account _and_ 10 new instances per minute, up from the previous limits of 2.  
This allows you to launch more browser tasks from [Cloudflare Workers](https://developers.cloudflare.com/workers).  
To manage concurrent browser sessions, you can use [Queues](https://developers.cloudflare.com/queues/) or [Workflows](https://developers.cloudflare.com/workflows/):

  * [  JavaScript ](#tab-panel-3139)
  * [  TypeScript ](#tab-panel-3140)

**index.js**  
```js  
export default {  
  async queue(batch, env) {  
    for (const message of batch.messages) {  
      const browser = await puppeteer.launch(env.BROWSER);  
      const page = await browser.newPage();  
      try {  
        await page.goto(message.url, {  
          waitUntil: message.waitUntil,  
        });  
        // Process page...  
      } finally {  
        await browser.close();  
      }  
    }  
  },  
};  
```

**index.ts**  
```ts  
interface QueueMessage {  
  url: string;  
  waitUntil: number;  
}  
export interface Env {  
  BROWSER_QUEUE: Queue<QueueMessage>;  
  BROWSER: Fetcher;  
}  
export default {  
  async queue(batch: MessageBatch<QueueMessage>, env: Env): Promise<void> {  
    for (const message of batch.messages) {  
      const browser = await puppeteer.launch(env.BROWSER);  
      const page = await browser.newPage();  
      try {  
        await page.goto(message.url, {  
          waitUntil: message.waitUntil,  
        });  
        // Process page...  
      } finally {  
        await browser.close();  
      }  
    }  
  },  
};  
```

Jan 28, 2025
1. ### [Support for Node.js DNS, Net, and Timer APIs in Workers](https://developers.cloudflare.com/changelog/post/2025-01-28-nodejs-compat-improvements/)  
[ Workers ](https://developers.cloudflare.com/workers/)  
When using a Worker with the [nodejs\_compat](https://developers.cloudflare.com/workers/runtime-apis/nodejs/) compatibility flag enabled, you can now use the following Node.js APIs:

  * [node:net](https://developers.cloudflare.com/workers/runtime-apis/nodejs/net/)
  * [node:dns](https://developers.cloudflare.com/workers/runtime-apis/nodejs/dns/)
  * [node:timers](https://developers.cloudflare.com/workers/runtime-apis/nodejs/timers/)  
#### node:net  
You can use [node:net ↗](https://nodejs.org/api/net.html) to create a direct connection to servers via a TCP sockets with [net.Socket ↗](https://nodejs.org/api/net.html#class-netsocket).

  * [  JavaScript ](#tab-panel-3137)
  * [  TypeScript ](#tab-panel-3138)

**index.js**  
```js  
import net from "node:net";  
const exampleIP = "127.0.0.1";  
export default {  
  async fetch(req) {  
    const socket = new net.Socket();  
    socket.connect(4000, exampleIP, function () {  
      console.log("Connected");  
    });  
    socket.write("Hello, Server!");  
    socket.end();  
    return new Response("Wrote to server", { status: 200 });  
  },  
};  
```

**index.ts**  
```ts  
import net from "node:net";  
const exampleIP = "127.0.0.1";  
export default {  
  async fetch(req): Promise<Response> {  
    const socket = new net.Socket();  
    socket.connect(4000, exampleIP, function () {  
      console.log("Connected");  
    });  
    socket.write("Hello, Server!");  
    socket.end();  
    return new Response("Wrote to server", { status: 200 });  
  },  
} satisfies ExportedHandler;  
```  
Additionally, you can now use other APIs including [net.BlockList ↗](https://nodejs.org/api/net.html#class-netblocklist) and [net.SocketAddress ↗](https://nodejs.org/api/net.html#class-netsocketaddress).  
Note that [net.Server ↗](https://nodejs.org/api/net.html#class-netserver) is not supported.  
#### node:dns  
You can use [node:dns ↗](https://nodejs.org/api/dns.html) for name resolution via [DNS over HTTPS](https://developers.cloudflare.com/1.1.1.1/encryption/dns-over-https/) using [Cloudflare DNS ↗](https://www.cloudflare.com/application-services/products/dns/) at 1.1.1.1.

  * [  JavaScript ](#tab-panel-3129)
  * [  TypeScript ](#tab-panel-3130)

**index.js**  
```js  
import dns from "node:dns";  
let response = await dns.promises.resolve4("cloudflare.com", "NS");  
```

**index.ts**  
```ts  
import dns from 'node:dns';  
let response = await dns.promises.resolve4('cloudflare.com', 'NS');  
```  
All `node:dns` functions are available, except `lookup`, `lookupService`, and `resolve` which throw "Not implemented" errors when called.  
#### node:timers  
You can use [node:timers ↗](https://nodejs.org/api/timers.html) to schedule functions to be called at some future period of time.  
This includes [setTimeout ↗](https://nodejs.org/api/timers.html#settimeoutcallback-delay-args) for calling a function after a delay, [setInterval ↗](https://nodejs.org/api/timers.html#setintervalcallback-delay-args) for calling a function repeatedly, and [setImmediate ↗](https://nodejs.org/api/timers.html#setimmediatecallback-args) for calling a function in the next iteration of the event loop.

  * [  JavaScript ](#tab-panel-3133)
  * [  TypeScript ](#tab-panel-3134)

**index.js**  
```js  
import timers from "node:timers";  
console.log("first");  
timers.setTimeout(() => {  
  console.log("last");  
}, 10);  
timers.setTimeout(() => {  
  console.log("next");  
});  
```

**index.ts**  
```ts  
import timers from "node:timers";  
console.log("first");  
timers.setTimeout(() => {  
  console.log("last");  
}, 10);  
timers.setTimeout(() => {  
  console.log("next");  
});  
```

Dec 29, 2024
1. ### [Faster Workers Builds with Build Caching and Watch Paths](https://developers.cloudflare.com/changelog/post/2024-12-29-faster-builds/)  
[ Workers ](https://developers.cloudflare.com/workers/)  
![Build caching settings](https://developers.cloudflare.com/_astro/workers-build-caching.DWEh3Tj1_Z1HXvDQ.webp)![Build watch path settings](https://developers.cloudflare.com/_astro/workers-build-watch-paths.ClqD-iNq_ZUCGHo.webp)  
[**Workers Builds**](https://developers.cloudflare.com/workers/ci-cd/builds/), the integrated CI/CD system for Workers (currently in beta), now lets you cache artifacts across builds, speeding up build jobs by eliminating repeated work, such as downloading dependencies at the start of each build.

  * **[Build Caching](https://developers.cloudflare.com/workers/ci-cd/builds/build-caching/)**: Cache dependencies and build outputs between builds with a shared project-wide cache, ensuring faster builds for the entire team.
  * **[Build Watch Paths](https://developers.cloudflare.com/workers/ci-cd/builds/build-watch-paths/)**: Define paths to include or exclude from the build process, ideal for [monorepos](https://developers.cloudflare.com/workers/ci-cd/builds/advanced-setups/#monorepos) to target only the files that need to be rebuilt per Workers project.  
To get started, select your Worker on the [Cloudflare dashboard ↗](https://dash.cloudflare.com) then go to **Settings** \> **Builds**, and connect a GitHub or GitLab repository. Once connected, you'll see options to configure Build Caching and Build Watch Paths.

Nov 11, 2024
1. ### [Bypass caching for subrequests made from Cloudflare Workers, with Request.cache](https://developers.cloudflare.com/changelog/post/2024-11-11-cache-no-store/)  
[ Workers ](https://developers.cloudflare.com/workers/)  
You can now use the [cache](https://developers.cloudflare.com/workers/runtime-apis/request/#options) property of the [Request](https://developers.cloudflare.com/workers/runtime-apis/request/) interface to bypass [Cloudflare's cache](https://developers.cloudflare.com/workers/reference/how-the-cache-works/) when making subrequests from [Cloudflare Workers](https://developers.cloudflare.com/workers), by setting its value to `no-store`.

  * [  JavaScript ](#tab-panel-3135)
  * [  TypeScript ](#tab-panel-3136)

**index.js**  
```js  
export default {  
  async fetch(req, env, ctx) {  
    const request = new Request("https://cloudflare.com", {  
      cache: "no-store",  
    });  
    const response = await fetch(request);  
    return response;  
  },  
};  
```

**index.ts**  
```ts  
export default {  
  async fetch(req, env, ctx): Promise<Response> {  
    const request = new Request("https://cloudflare.com", { cache: 'no-store'});  
    const response = await fetch(request);  
    return response;  
  }  
} satisfies ExportedHandler<Environment>  
```  
When you set the value to `no-store` on a subrequest made from a Worker, the Cloudflare Workers runtime will not check whether a match exists in the cache, and not add the response to the cache, even if the response includes directives in the `Cache-Control` HTTP header that otherwise indicate that the response is cacheable.  
This increases compatibility with NPM packages and JavaScript frameworks that rely on setting the [cache](https://developers.cloudflare.com/workers/runtime-apis/request/#options) property, which is a cross-platform standard part of the [Request](https://developers.cloudflare.com/workers/runtime-apis/request/) interface. Previously, if you set the `cache` property on `Request`, the Workers runtime threw an exception.  
If you've tried to use `@planetscale/database`, `redis-js`, `stytch-node`, `supabase`, `axiom-js` or have seen the error message `The cache field on RequestInitializerDict is not implemented in fetch` — you should try again, making sure that the [Compatibility Date](https://developers.cloudflare.com/workers/configuration/compatibility-dates/) of your Worker is set to on or after `2024-11-11`, or the [cache\_option\_enabled compatibility flag](https://developers.cloudflare.com/workers/configuration/compatibility-flags/#enable-cache-no-store-http-standard-api) is enabled for your Worker.

  * Learn [how the Cache works with Cloudflare Workers](https://developers.cloudflare.com/workers/reference/how-the-cache-works/)
  * Enable [Node.js compatibility](https://developers.cloudflare.com/workers/runtime-apis/nodejs/) for your Cloudflare Worker
  * Explore [Runtime APIs](https://developers.cloudflare.com/workers/runtime-apis/) and [Bindings](https://developers.cloudflare.com/workers/runtime-apis/bindings/) available in Cloudflare Workers

Oct 24, 2024
1. ### [Workflows is now in open beta](https://developers.cloudflare.com/changelog/post/2024-10-24-workflows-beta/)  
[ Workers ](https://developers.cloudflare.com/workers/)[ Workflows ](https://developers.cloudflare.com/workflows/)  
Workflows is now in open beta, and available to any developer a free or paid Workers plan.  
Workflows allow you to build multi-step applications that can automatically retry, persist state and run for minutes, hours, days, or weeks. Workflows introduces a programming model that makes it easier to build reliable, long-running tasks, observe as they progress, and programmatically trigger instances based on events across your services.  
#### Get started  
You can get started with Workflows by [following our get started guide](https://developers.cloudflare.com/workflows/get-started/guide/) and/or using `npm create cloudflare` to pull down the starter project:  
```sh  
npm create cloudflare@latest workflows-starter -- --template "cloudflare/workflows-starter"  
```  
You can open the `src/index.ts` file, extend it, and use `wrangler deploy` to deploy your first Workflow. From there, you can:

  * Learn the [Workflows API](https://developers.cloudflare.com/workflows/build/workers-api/)
  * [Trigger Workflows](https://developers.cloudflare.com/workflows/build/trigger-workflows/) via your Workers apps.
  * Understand the [Rules of Workflows](https://developers.cloudflare.com/workflows/build/rules-of-workflows/) and how to adopt best practices

```json
{"@context":"https://schema.org","@type":"BlogPosting","@id":"https://developers.cloudflare.com/changelog/product/workers/9/#page","headline":"Workers Changelog | Cloudflare Docs","url":"https://developers.cloudflare.com/changelog/product/workers/9/","inLanguage":"en","image":"https://developers.cloudflare.com/cf-twitter-card.png","publisher":{"@type":"Organization","name":"Cloudflare","url":"https://www.cloudflare.com/"},"isPartOf":{"@type":"WebSite","@id":"https://developers.cloudflare.com/#website","name":"Cloudflare Docs","url":"https://developers.cloudflare.com/"}}
```
