wrangler types command generates Service and DurableObjectNamespace types
Running wrangler types generates runtime types including the Service and DurableObjectNamespace types. Each of these accepts a single type parameter for the WorkerEntrypoint or DurableObject types respectively.
wrangler types generates client-side stub types automatically
wrangler types uses higher-order types to automatically generate client-side stub types, such as forcing all methods to be async.
wrangler types generates types for the env object
wrangler types generates types for the env object. You can pass in the path to the config files of the Worker or Durable Object being called so that the generated types include the type parameters for the Service and DurableObjectNamespace types.
Multiple config files to wrangler types command
To generate types for a client Worker with bindings to multiple services, pass multiple config file paths to wrangler types using the -c flag for each config file, for example: wrangler types -c ./client/wrangler.jsonc -c ../sum-worker/wrangler.jsonc -c ../counter/wrangler.jsonc
Basic delay with scheduler.wait() example
export default {
async fetch(request): Promise<Response> {
// Wait for 1 second
await scheduler.wait(1000);
return new Response("Delayed response");
},
} satisfies ExportedHandler;
This example shows how to pause execution for a specified duration using scheduler.wait().
scheduler.wait() delays execution with Promise
The scheduler.wait() method returns a Promise that resolves after a given number of milliseconds. It is an await-able alternative to setTimeout() that does not require a callback.
scheduler.wait() does not advance during CPU execution in production
Like other timers in Workers, scheduler.wait() does not advance during CPU execution when deployed to Cloudflare. This is a security measure to mitigate against Spectre attacks. In local development, timers advance regardless of whether I/O occurs.
scheduler.wait() syntax and parameters
scheduler.wait() has the signature: await scheduler.wait(delay) or await scheduler.wait(delay, options). The delay parameter (number, required) specifies the number of milliseconds to wait before the returned Promise resolves. The options parameter (object, optional) provides optional configuration. Within options, signal (AbortSignal, optional) is an AbortSignal that cancels the wait; when the signal is aborted, the returned Promise rejects with an AbortError.
scheduler.wait() return value
scheduler.wait() returns a Promise<void> that resolves after the delay milliseconds. If an AbortSignal is provided and aborted before the delay elapses, the Promise rejects with an AbortError.
Retry with exponential backoff using scheduler.wait() example
async function fetchWithRetry(url: string, maxAttempts = 3): Promise<Response> {
const baseBackoffMs = 100;
const maxBackoffMs = 10000;
for (let attempt = 0; attempt < maxAttempts; attempt++) {
try {
return await fetch(url);
} catch (err) {
if (attempt + 1 >= maxAttempts) {
throw err;
}
const backoffMs = Math.min(
maxBackoffMs,
baseBackoffMs * Math.random() * Math.pow(2, attempt),
);
await scheduler.wait(backoffMs);
}
}
throw new Error("unreachable");
}
export default {
async fetch(request): Promise<Response> {
const response = await fetchWithRetry("https://example.com/api");
return new Response(response.body, response);
},
} satisfies ExportedHandler;
This example demonstrates using scheduler.wait() to implement exponential backoff with jitter between retry attempts.
Cancel scheduler.wait() with AbortSignal example
export default {
async fetch(request): Promise<Response> {
const controller = new AbortController();
// Cancel the wait after 500ms
setTimeout(() => controller.abort(), 500);
try {
await scheduler.wait(5000, { signal: controller.signal });
return new Response("Wait completed");
} catch (err) {
if (err instanceof DOMException && err.name === "AbortError") {
return new Response("Wait was cancelled", { status: 408 });
}
throw err;
}
},
} satisfies ExportedHandler;
This example demonstrates using an AbortController to cancel a pending scheduler.wait() operation.
Streams API purpose and benefits
The Streams API is a web standard API that allows JavaScript to programmatically access and process streams of data. It enables you to avoid buffering large requests or responses in memory, allowing you to parse extremely large request or response bodies within a Worker's 128 MB memory limit. This is faster than buffering the entire payload into memory, as your Worker can start processing data incrementally and handle multi-gigabyte payloads or files within its memory limits.
Response streaming with ReadableStream
Workers can create a Response object using a ReadableStream as the body. Any data provided through the ReadableStream will be streamed to the client as it becomes available. Workers do not need to prepare an entire response body before returning a Response; the response status line and headers can be sent first while the body streams afterward.
Simple streaming response example
This Module Worker example shows how to stream a response by fetching from an origin server and returning the response body as-is:
```js
export default {
async fetch(request, env, ctx) {
// Fetch from origin server.
const response = await fetch(request);
// ... and deliver our Response while that's running.
return new Response(response.body, response);
},
};
```
Transform stream with pipeTo example
This Module Worker example demonstrates using TransformStream and ReadableStream.pipeTo() to modify the response body as it is being streamed:
```js
export default {
async fetch(request, env, ctx) {
// Fetch from origin server.
const response = await fetch(request);
const { readable, writable } = new TransformStream({
transform(chunk, controller) {
controller.enqueue(modifyChunkSomehow(chunk));
},
});
// Start pumping the body. NOTE: No await!
response.body.pipeTo(writable);
// ... and deliver our Response while that's running.
return new Response(readable, response);
},
};
```
The response.body.pipeTo(writable) call is not awaited so it does not block the forward progress of the function. It continues to run asynchronously until the response is complete or the client disconnects.
TransformStream and pipeTo for response modification
A TransformStream and the ReadableStream.pipeTo() method can be used to modify the response body as it is being streamed. The pipeTo() call should not be awaited, allowing it to run asynchronously in the background while the response is returned to the client.
Python Worker streaming response example
This Python Worker example demonstrates streaming a response body to the client:
```python
from workers import WorkerEntrypoint, Response, fetch
class Default(WorkerEntrypoint):
async def fetch(self, request):
# Fetch from origin server.
response = await fetch(request)
# Stream the response body to the client.
return Response(response.body, headers=response.headers)
```
Python Worker custom ReadableStream example
This Python Worker example demonstrates creating a custom ReadableStream that enqueues chunks:
```python
from workers import WorkerEntrypoint, Response
from js import ReadableStream, TextEncoder
from pyodide.ffi import create_proxy, to_js
import asyncio
class Default(WorkerEntrypoint):
async def fetch(self, request):
enc = TextEncoder.new()
async def start(controller):
for i in range(5):
controller.enqueue(enc.encode(f"chunk {i}\n"))
await asyncio.sleep(0.1)
controller.close()
stream = ReadableStream.new(
to_js({"start": create_proxy(start)})
)
return Response(stream, headers={"Content-Type": "text/plain"})
```
Asynchronous execution after response return
The runtime can continue running a function after a response is returned to the client. This enables scenarios where you use pipeTo() without awaiting it, allowing the stream pump to continue asynchronously until the response is complete or the client disconnects.
Streams API availability context
The Streams API is only available inside of the Request context, inside the fetch event listener callback.
Default streaming behavior in Cloudflare Workers
By default, Cloudflare Workers is capable of streaming responses using the Streams APIs. To maintain the streaming behavior, you should only modify the response body using the methods in the Streams APIs. If your Worker only forwards subrequest responses to the client verbatim without reading their body text, then its body handling is already optimal and you do not have to use these APIs.
TCP socket error: Connections to port 25 are prohibited
This error occurs when the socket is connecting to an address on port 25, typically used for SMTP mail servers. Workers cannot create outbound connections on port 25. Consider using Cloudflare Email Workers instead.
TCP sockets connect() import location
The `connect()` function is imported from `cloudflare:sockets`. This is the runtime API for creating outbound TCP connections from Workers, similar to how built-in modules are imported in Node.js.
connect() function signature and return value
The `connect()` function accepts either a URL string or a SocketAddress object to define hostname and port, and an optional SocketOptions configuration object. It returns a Socket instance with both readable and writable streams.
SocketAddress interface
SocketAddress has two required fields: hostname (string, example: cloudflare.com) and port (number, example: 5432). These define the endpoint to connect to.
SocketOptions secureTransport parameter
The secureTransport option accepts three values with default 'off': 'off' (do not use TLS), 'on' (use TLS), or 'starttls' (do not use TLS initially, but allow upgrade via startTls() method). This controls whether TLS encryption is used for the TCP socket.
SocketOptions allowHalfOpen parameter
The allowHalfOpen option is a boolean that defaults to false. When false, the writable side of the TCP socket automatically closes on EOF. When true, the writable side remains open on EOF. This is similar to the Node.js net module option for interoperability.
SocketInfo interface
SocketInfo has two optional string fields: remoteAddress (the address of the remote peer the socket is connected to, may not always be set) and localAddress (the address of the local network endpoint for this socket, may not always be set).
Socket readable property
The readable property on a Socket returns a ReadableStream for reading data from the TCP socket.
Socket writable property
The writable property on a Socket returns a WritableStream for writing data to the TCP socket. The WritableStream only accepts chunks of Uint8Array or its views.
Socket opened promise
The opened property is a Promise<SocketInfo> that resolves when the socket connection is established and rejects if the socket encounters an error.
Socket closed promise
The closed property is a Promise<void> that resolves when the socket is closed and rejects if the socket encounters an error.
Socket close() method
The close() method returns Promise<void> and closes the TCP socket by forcibly closing both the readable and writable streams.
Socket startTls() method
The startTls() method upgrades an insecure socket to a secure one using TLS, returning a new Socket instance. It can only be called if secureTransport was set to 'starttls' when initially calling connect().
startTls() behavior with existing readers and writers
Once startTls() is called, the initial socket is closed and can no longer be read from or written to. Any existing readers and writers based on the original socket will no longer work. New readers and writers must be created from the newly created secure socket.
startTls() call limit
startTls() should only be called once on an existing socket.
TCP socket basic example with gopher
Example showing how to create a TCP socket, write data, and return the readable side as a response:
```typescript
import { connect } from 'cloudflare:sockets';
export default {
async fetch(req): Promise<Response> {
const gopherAddr = { hostname: "gopher.floodgap.com", port: 70 };
const url = new URL(req.url);
try {
const socket = connect(gopherAddr);
const writer = socket.writable.getWriter()
const encoder = new TextEncoder();
const encoded = encoder.encode(url.pathname + "\r\n");
await writer.write(encoded);
await writer.close();
return new Response(socket.readable, { headers: { "Content-Type": "text/plain" } });
} catch (error) {
return new Response("Socket connection failed: " + error, { status: 500 });
}
}
} satisfies ExportedHandler;
```
TCP socket opportunistic TLS (StartTLS) example
Example showing how to create an insecure TCP socket and upgrade it to use TLS via startTls():
```typescript
import { connect } from "cloudflare:sockets"
const address = {
hostname: "example-postgres-db.com",
port: 5432
};
const socket = connect(address, { secureTransport: "starttls" });
const secureSocket = socket.startTls();
```
TCP socket error handling example with HTTP request
Example showing how to handle errors when creating a TCP socket, initiating an HTTP request, and returning the response:
```typescript
import { connect } from 'cloudflare:sockets';
const connectionUrl = { hostname: "google.com", port: 80 };
export interface Env { }
export default {
async fetch(req, env, ctx): Promise<Response> {
try {
const socket = connect(connectionUrl);
const writer = socket.writable.getWriter();
const encoder = new TextEncoder();
const encoded = encoder.encode("GET / HTTP/1.0\r\n\r\n");
await writer.write(encoded);
await writer.close();
return new Response(socket.readable, { headers: { "Content-Type": "text/plain" } });
} catch (error) {
return new Response(`Socket connection failed: ${error}`, { status: 500 });
}
}
} satisfies ExportedHandler<Env>;
```
TCP sockets cannot be created in global scope
TCP sockets cannot be created in global scope and shared across requests. They must always be created within a handler such as fetch(), scheduled(), queue(), or alarm().
TCP socket connection limit
Each open TCP socket counts towards the maximum number of open connections that can be simultaneously open, subject to the simultaneous open connections platform limit.
TCP socket in Durable Objects keeps object alive
When created from within a Durable Object, an open TCP socket keeps the Durable Object in memory and causes it to incur duration charges for up to 15 minutes per connection. After 15 minutes, the socket stops keeping the Durable Object alive, the socket itself continues operating, and standard eviction rules resume.
TCP socket blocked addresses and ports
Outbound TCP sockets to Cloudflare IP ranges are blocked. By default, Workers cannot create outbound TCP connections on port 25 to send email to SMTP mail servers. For email handling, use Cloudflare Email Workers instead.
TCP sockets sourced from non-Cloudflare IP range
TCP Workers outbound connections are sourced from a prefix that is not part of the Cloudflare IP ranges list.
TCP socket error: proxy request failed, cannot connect to the specified address
This error occurs when the socket is connecting to a disallowed address such as Cloudflare IPs, localhost, or private network IPs. To make HTTP requests to addresses on port 80 or 443, use the fetch() API instead.
TCP socket error: TCP Loop detected
This error occurs when the socket is connecting back to the Worker that initiated the outbound connection, meaning the Worker is connecting back to itself. This is currently not supported.
Hyperdrive recommended for PostgreSQL connections
When connecting to a PostgreSQL database, Hyperdrive should be used instead of the TCP connect() API, as Hyperdrive provides the connect() API with built-in connection pooling and query caching.
TCP socket use cases: application-layer protocols
Many application-layer protocols are built on top of TCP. These include SSH, MQTT, SMTP, FTP, IRC, and most database wire protocols including MySQL, PostgreSQL, and MongoDB. The TCP connect() API is required to work with these protocols.
Ed25519 and X25519 algorithms from Secure Curves API
Ed25519 and X25519 algorithms are supported as specified in the Secure Curves API. They provide modern elliptic curve cryptography support in Workers.
NODE-ED25519 legacy EdDSA algorithm
NODE-ED25519 is a legacy non-standard EdDSA algorithm supported for the Ed25519 curve in addition to the Secure Curves version. When using NODE-ED25519: use NODE-ED25519 as the algorithm and namedCurve parameters. Unlike Node.js, Cloudflare does not support raw import of private keys. The algorithm implementation may change over time, though Cloudflare will strive to maintain backward compatibility and compatibility with Node.js behavior. Any notable compatibility notes will be communicated in release notes and documentation.
MD5 algorithm support and limitations
MD5 is not part of the WebCrypto standard but is supported in Cloudflare Workers for interacting with legacy systems that require MD5. MD5 is considered a weak algorithm and should not be relied upon for security.
DigestStream example with SHA-256
Example code showing DigestStream usage: Create a SHA-256 digest stream with new crypto.DigestStream('SHA-256'). Pipe a body stream into it using bodyTwo.pipeTo(digestStream). Await digestStream.digest to get the final ArrayBuffer result. Convert to hex string using: [...new Uint8Array(digest)].map(b => b.toString(16).padStart(2, '0')).join(''). This example demonstrates computing a SHA-256 hash of a response body and setting it as a header.
generateKey example for AES-GCM
Example code for generating an AES-GCM key: const keyPair = await crypto.subtle.generateKey({name: 'AES-GCM', length: 256}, true, ['encrypt', 'decrypt']); This generates a symmetric 256-bit AES-GCM key that can be used for both encryption and decryption operations.
Web Crypto API differences from Node.js Crypto API
The Web Crypto API differs significantly from the Node.js Crypto API. If working with code that relies on the Node.js Crypto API, you can use it by enabling the nodejs_compat compatibility flag.
crypto.DigestStream constructor and usage
crypto.DigestStream(algorithm) is a non-standard extension that creates a WritableStream for generating hash digests from streaming data. The DigestStream does not retain written data but generates a hash digest automatically when the data flow ends. The algorithm parameter describes the algorithm to use in an algorithm-specific format. DigestStream has a digest property that is awaitable and returns the final hash digest as an ArrayBuffer.
crypto.getRandomValues method
crypto.getRandomValues(buffer) fills the passed ArrayBufferView with cryptographically sound random values and returns the buffer. The buffer parameter must be one of: Int8Array, Uint8Array, Uint8ClampedArray, Int16Array, Uint16Array, Int32Array, Uint32Array, BigInt64Array, or BigUint64Array.
Web Crypto API overview and access
The Web Crypto API provides low-level functions for common cryptographic tasks. The Workers runtime implements the full surface of the Web Crypto API but with differences in supported algorithms compared to browsers. The API is implemented through the SubtleCrypto interface, accessible via the global crypto.subtle binding. Cryptographic operations using the Web Crypto API are significantly faster than performing them purely in JavaScript.
crypto.subtle.verify method
crypto.subtle.verify(algorithm, key, signature, data) returns a Promise<boolean> indicating if the signature matches the text, algorithm, and key. The algorithm parameter is a string or object describing the algorithm in algorithm-specific format. The key parameter is a CryptoKey. The signature parameter is an ArrayBuffer. The data parameter is an ArrayBuffer.
crypto.subtle.digest method
crypto.subtle.digest(algorithm, data) returns a Promise<ArrayBuffer> that fulfills with a digest generated from the algorithm and text. The algorithm parameter is a string or object describing the algorithm and required parameters in algorithm-specific format. The data parameter is an ArrayBuffer.
crypto.subtle.generateKey method
crypto.subtle.generateKey(algorithm, extractable, keyUsages) returns a Promise<CryptoKey> for symmetrical algorithms or Promise<CryptoKeyPair> for asymmetrical algorithms. The algorithm parameter is an object describing the algorithm and required parameters in algorithm-specific format. The extractable parameter is a boolean. The keyUsages parameter is an array of strings indicating possible usages of the new key.