This is documentation for the next version of Grafana k6 documentation. For the latest stable release, go to the latest version.
k6/x/tcp
Note
This module is implemented as an official extension and is not part of k6 by default. However, k6’s automatic extension resolution makes it available seamlessly when you import it in your script. Refer to the extensions documentation for available extensions and details.
The k6/x/tcp module adds first-class support for raw TCP socket communication to your performance testing scripts. With this extension, you can establish TCP connections and send and receive data directly from your k6 tests.
If you’ve used Node.js’s net.Socket, the API will feel familiar, with event-driven programming, Promise-based operations, and comprehensive lifecycle management.
Key features
- Event-driven architecture with support for socket lifecycle events (
connect,data,close,error,timeout) - Promise-based
connect()andwrite()methods for use withasync/await - TLS/SSL support using standard k6 TLS configuration
- Binary data handling: send and receive strings and
ArrayBuffer - Automatic metrics collection for all socket operations
- Optional custom tags for filtering and grouping metrics
Use cases
- Load testing TCP-based services and custom binary protocols
- Testing raw network protocol implementations under high concurrency
- Validating server behavior and connection handling under load
- Performance testing services that don’t use HTTP
API
Metrics
The extension automatically generates metrics for TCP socket operations:
You can pass custom tags in the Socket constructor, connection options, or write options to attach additional metadata to each metric.
Event-driven architecture
Unlike HTTP-based tests, TCP tests use an asynchronous event loop. Each VU creates a Socket, registers event handlers, and connects to a server. The VU remains active until socket.destroy() is called or the connection is closed.
Register handlers with socket.on() before calling socket.connect(). The connect handler fires when the connection is established; the data handler fires each time data is received; the close handler fires when the connection is fully closed.
Examples
Basic usage
import { Socket } from "k6/x/tcp"
export default async function () {
const socket = new Socket()
const closed = new Promise((resolve) => {
socket.on("close", () => {
console.log("Connection closed")
resolve()
})
})
socket.on("error", (err) => {
console.error("Error:", err)
})
const host = __ENV.TCP_HOST || "localhost"
const port = __ENV.TCP_PORT || "8080"
await socket.connect(port, host)
console.log("Connected")
socket.destroy()
await closed
}TLS connection
import { Socket } from "k6/x/tcp"
export default async function () {
const socket = new Socket()
const closed = new Promise((resolve) => {
socket.on("close", resolve)
})
socket.on("data", (data) => {
const response = String.fromCharCode.apply(null, new Uint8Array(data))
console.log("Received:", response.substring(0, 100))
socket.destroy()
})
socket.on("error", (err) => {
console.error("Error:", err)
})
const host = __ENV.TLS_HOST || "example.com"
await socket.connect({ port: 443, host, tls: true })
await socket.write(`GET / HTTP/1.1\r\nHost: ${host}\r\nConnection: close\r\n\r\n`)
await closed
}
