diff --git a/content/workers/platform/betas.md b/content/workers/platform/betas.md
index bcd5f5f29d6..fba0561d1be 100644
--- a/content/workers/platform/betas.md
+++ b/content/workers/platform/betas.md
@@ -18,6 +18,6 @@ These are the current alphas and betas relevant to the Cloudflare Workers platfo
| Green Compute | | | ✅ |[Blog](https://blog.cloudflare.com/earth-day-2022-green-compute-open-beta/) |
| Pub/Sub | | ✅ | |[Docs](/pub-sub) |
| Queues | | | ✅ |[Docs](/queues) |
-| TCP Workers | | ✅ | |[Blog](https://blog.cloudflare.com/introducing-socket-workers/) |
+| TCP Workers | | | ✅ |[Docs](/workers/runtime-apis/tcp-sockets) |
| Workers Analytics Engine | | | ✅ |[Docs](/analytics/analytics-engine/) |
| Workers Deployments | | | ✅ |[Docs](/workers/platform/deployments) |
diff --git a/content/workers/platform/limits.md b/content/workers/platform/limits.md
index 2a6db92fe3f..58ac3a26718 100644
--- a/content/workers/platform/limits.md
+++ b/content/workers/platform/limits.md
@@ -242,6 +242,7 @@ While handling a request, each Worker is allowed to have up to six connections o
- `put()`, `match()`, and `delete()` methods of [Cache objects](/workers/runtime-apis/cache/).
- `list()`, `get()`, `put()`, `delete()`, and `head()` methods of [R2](/r2/).
- `send()` and `sendBatch()`, methods of [Queues](/queues/).
+- Opening a TCP socket using the [`connect()`](/workers/runtime-apis/tcp-sockets/) API.
Once a Worker has six connections open, it can still attempt to open additional connections. However, these attempts are put in a pending queue — the connections will not be initiated until one of the currently open connections has closed. Since earlier connections can delay later ones, if a Worker tries to make many simultaneous subrequests, its later subrequests may appear to take longer to start.
diff --git a/content/workers/platform/protocols.md b/content/workers/platform/protocols.md
new file mode 100644
index 00000000000..09ec0ed5313
--- /dev/null
+++ b/content/workers/platform/protocols.md
@@ -0,0 +1,17 @@
+---
+pcx_content_type: concept
+title: Protocols
+---
+
+# Protocols
+
+Cloudflare Workers support the following protocols and interfaces:
+
+| Protocol | Inbound | Outbound |
+|---|---|---|
+| **HTTP / HTTPS** | Handle incoming HTTP requests using the [`fetch()` handler](/workers/runtime-apis/fetch-event/#syntax-module-worker/) | Make HTTP subrequests using the [`fetch()` API](/workers/runtime-apis/fetch/) |
+| **Direct TCP sockets** | Support for handling inbound TCP connections is [coming soon](https://blog.cloudflare.com/introducing-socket-workers/) | Create outbound TCP connections using the [`connect()` API](/workers/runtime-apis/tcp-sockets/) |
+| **WebSockets** | Accept incoming WebSocket connections using the [`WebSocket` API](/workers/runtime-apis/websockets/), or with [MQTT over WebSockets (Pub/Sub)](/pub-sub/learning/websockets-browsers/) | [MQTT over WebSockets (Pub/Sub)](/pub-sub/learning/websockets-browsers/) |
+| **MQTT** | Handle incoming messages to an MQTT broker with [Pub Sub](/pub-sub/learning/integrate-workers/) | Support for publishing MQTT messages to an MQTT topic is [coming soon](/pub-sub/learning/integrate-workers/) |
+| **HTTP/3 (QUIC)** | Accept inbound requests over [HTTP/3](https://www.cloudflare.com/learning/performance/what-is-http3/) by enabling it on your [zone](/fundamentals/get-started/concepts/accounts-and-zones/#zones) in the network tab of the [Cloudflare dashboard](https://dash.cloudflare.com/). | |
+| **SMTP** | Use [Email Workers](/email-routing/email-workers/) to process and forward email, without having to manage TCP connections to SMTP email servers | [Email Workers](/email-routing/email-workers/) |
\ No newline at end of file
diff --git a/content/workers/runtime-apis/tcp-sockets.md b/content/workers/runtime-apis/tcp-sockets.md
new file mode 100644
index 00000000000..00c02dc7664
--- /dev/null
+++ b/content/workers/runtime-apis/tcp-sockets.md
@@ -0,0 +1,161 @@
+---
+pcx_content_type: configuration
+title: TCP sockets
+---
+
+# TCP sockets
+
+The Workers runtime provides the `connect()` API for creating outbound [TCP connections](https://www.cloudflare.com/learning/ddos/glossary/tcp-ip/) from Workers.
+
+Many application-layer protocols are built on top of the Transmission Control Protocol (TCP). These application-layer protocols, including SSH, MQTT, SMTP, FTP, IRC, and most database wire protocols including MySQL, PostgreSQL, MongoDB, require an underlying TCP socket API in order to work.
+
+## `connect()`
+
+The `connect()` function returns a TCP socket, with both a [readable](/workers/runtime-apis/streams/readablestream/) and [writable](/workers/runtime-apis/streams/writablestream/) stream of data. This allows you to read and write data on an ongoing basis, as long as the connection remains open.
+
+`connect()` is provided as a [Runtime API](/workers/runtime-apis/), and is accessed by importing the `connect` function from `cloudflare:sockets`. This process is similar to how one imports built-in modules in Node.js. Refer to the following codeblock for an example of creating a TCP socket, writing to it, and returning the readable side of the socket as a response:
+
+```typescript
+import { connect } from 'cloudflare:sockets';
+
+export default {
+ async fetch(req: Request) {
+ 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);
+
+ return new Response(socket.readable, { headers: { "Content-Type": "text/plain" } });
+ } catch (error) {
+ return new Response("Socket connection failed: " + error, { status: 500 });
+ }
+ }
+};
+```
+
+{{}}
+
+- {{}}connect(address: {{}}SocketAddress{{}} | string, options?: {{}}optional{{}} {{}}SocketOptions{{}}){{}} : {{}}`Socket`{{}}
+ - `connect()` accepts either a URL string or [`SocketAddress`](/workers/runtime-apis/tcp-sockets/#socketaddress) to define the hostname and port number to connect to, and an optional configuration object, [`SocketOptions`](/workers/runtime-apis/tcp-sockets/#socketoptions). It returns an instance of a [`Socket`](/workers/runtime-apis/tcp-sockets/#socket).
+{{}}
+
+### `SocketAddress`
+
+{{}}
+
+- `hostname` {{}}string{{}}
+ - The hostname to connect to. Example: `cloudflare.com`.
+
+- `port` {{}}number{{}}
+ - The port number to connect to. Example: `5432`.
+
+{{}}
+
+### `SocketOptions`
+
+{{}}
+
+- `secureTransport` {{}}"off" | "on" | "starttls"{{}} — Defaults to `off`
+ - Specifies whether or not to use [TLS](https://www.cloudflare.com/learning/ssl/transport-layer-security-tls/) when creating the TCP socket.
+ - `off` — Do not use TLS.
+ - `on` — Use TLS.
+ - `starttls` — Do not use TLS initially, but allow the socket to be upgraded to use TLS by calling [`startTls()`](/workers/runtime-apis/tcp-sockets/#how-to-implement-the-starttls-pattern).
+
+- `allowHalfOpen` {{}}boolean{{}} — Defaults to `false`
+ - Defines whether the writable side of the TCP socket will automatically close on end-of-file (EOF). When set to `false`, the writable side of the TCP socket will automatically close on EOF. When set to `true`, the writable side of the TCP socket will remain open on EOF.
+ - This option is similar to that offered by the Node.js [`net` module](https://nodejs.org/api/net.html) and allows interoperability with code which utilizes it.
+
+{{}}
+
+### `Socket`
+
+{{}}
+
+- {{}}readable(){{}} : {{}}ReadableStream{{}}
+ - Returns the readable side of the TCP socket.
+
+- {{}}writeable(){{}} : {{}}WriteableStream{{}}
+ - Returns the writable side of the TCP socket.
+
+- `closed()` {{}}`Promise`{{}}
+ - This promise is resolved when the socket is closed and is rejected if the socket encounters an error.
+
+- `close()` {{}}`Promise`{{}}
+ - Closes the TCP socket. Both the readable and writable streams are forcibly closed.
+
+- {{}}startTls(){{}} : {{}}Socket{{}}
+ - Upgrades an insecure socket to a secure one that uses TLS, returning a new [Socket](/workers/runtime-apis/tcp-sockets#socket). Note that in order to call `startTls()`, you must set [`secureTransport`](/workers/runtime-apis/tcp-sockets/#socketoptions) to `starttls` when initially calling `connect()` to create the socket.
+
+{{}}
+
+## Opportunistic TLS (StartTLS)
+
+Many TCP-based systems, including databases and email servers, require that clients use opportunistic TLS (otherwise known as [StartTLS](https://en.wikipedia.org/wiki/Opportunistic_TLS)) when connecting. In this pattern, the client first creates an insecure TCP socket, without TLS, and then upgrades it to a secure TCP socket, that uses TLS. The `connect()` API simplifies this by providing a method, `startTls()`, which returns a new `Socket` instance that uses TLS:
+
+```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();
+```
+
+- `startTls()` can only be called if `secureTransport` is set to `starttls` when creating the initial TCP socket.
+- Once `startTls()` is called, the initial socket is closed and can no longer be read from or written to. In the example above, anytime after `startTls()` is called, you would use the newly created `secureSocket`. Any existing readers and writers based off the original socket will no longer work. You must create new readers and writers from the newly created `secureSocket`.
+- `startTls()` should only be called once on an existing socket.
+
+## Handle errors
+
+To handle errors when creating a new TCP socket, reading from a socket, or writing to a socket, wrap these calls inside `try..catch` blocks. The following example opens a connection to Google.com, initiates a HTTP request, and returns the response. If any of this fails and throws an exception, it returns a `500` response:
+
+```typescript
+import { connect } from 'cloudflare:sockets';
+const connectionUrl = { hostname: "google.com", port: 80 };
+export interface Env { }
+export default {
+ async fetch(req: Request, env: Env, ctx: ExecutionContext): Promise {
+ 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);
+
+ return new Response(socket.readable, { headers: { "Content-Type": "text/plain" } });
+ } catch (error) {
+ return new Response(`Socket connection failed: ${error}`, { status: 500 });
+ }
+ }
+};
+```
+
+## Close TCP connections
+
+You can close a TCP connection by calling `close()` on the socket. This will close both the readable and writeable sides of the socket.
+
+```typescript
+import { connect } from "cloudflare:sockets"
+
+const socket = connect({ hostname: "my-url.com", port: 70 });
+const reader = socket.readable.getReader();
+socket.close();
+
+// After close() is called, you can no longer read from the readable side of the socket
+const reader = socket.readable.getReader(); // This fails
+```
+
+## Considerations
+
+- When developing locally with [Wrangler](/workers/wrangler/), you must pass the [`--experimental-local`](/workers/wrangler/commands/#dev) flag, instead of the `--local` flag, to use `connect()`.
+- TCP sockets must be created within the [`fetch()` handler](/workers/get-started/guide/#3-write-code) of a Worker. TCP sockets cannot be created in global scope and shared across requests.
+- Each open TCP socket counts towards the maximum number of [open connections](/workers/platform/limits/#simultaneous-open-connections) that can be simultaneously open.
+- By default, Workers cannot create outbound TCP connections on port `25` to send email to SMTP mail servers. [Cloudflare Email Workers](/email-routing/email-workers/) provides APIs to process and forward email.
\ No newline at end of file