On Runtime, a public TCP port costs nothing extra. Ports are included with a paid account, and you pay only for the sandbox (pricing checked 25 October 2026, network products). That suits anything that is not HTTP: Postgres, Redis, MQTT, the TCP side of a game server, or your own protocol. A 2 vCPU, 4 GiB sandbox that serves a port costs $0.03125 an hour while idle, and $0.08 an hour with both CPUs busy (pricing).
Open a port
Terminalruntime ports open <sandbox> 5432# 203.0.113.10:23456psql "postgres://app@203.0.113.10:23456/app?sslmode=require"TypeScriptimport { Runtime } from "withruntime";const runtime = new Runtime();const sbx = await runtime.sandboxes.create();const db = await runtime.ports.open({ sandboxId: sbx.id, port: 5432 });console.log(db.connect); // "203.0.113.10:23456"Pythonfrom withruntime import Runtimeruntime = Runtime()sbx = runtime.sandboxes.create()db = runtime.ports.open(sandbox_id=sbx.id, port=5432)print(db["connect"]) # "203.0.113.10:23456"The public port is chosen for you. Opening the same sandbox and port again
returns the same public port. So a retry never leaves two ports open. An MCP
agent uses runtime_ports with open, list and close.
Run the service so it keeps answering
Start the server with spawn. It keeps running after your call returns.
Anything an exec starts ends with its command, even when it runs as nohup … &:
Terminalruntime sandboxes exec <sandbox> -- sh -c 'sudo apt-get update && sudo apt-get install -y redis-server'runtime sandboxes spawn <sandbox> -- redis-server --protected-mode no --requirepass "$REDIS_PASSWORD"runtime ports open <sandbox> 6379Any server installed with apt-get, pip or npm can serve this way. Or bake
the server into a custom image, so every sandbox starts with it.
Limits
| Limit | Value |
|---|---|
| Price | Included with a paid account |
| Ports per sandbox | 5 |
| Ports per account | 20 |
| Opened per day | 50 |
| Open connections, all of a sandbox's ports | 256 |
| New connections a second | 50 |
| Connections from one client address | 32 |
| Protocol | TCP only; UDP is not carried |
| Bandwidth and daily bytes | The sandbox's outbound limits |
Mistakes and how Runtime handles them
- No password on the service. Anyone who knows the address can connect.
Runtime carries the bytes as they are. Use your service's own authentication
and TLS, as the
sslmode=requireabove does. - Expecting UDP. Only TCP is carried. QUIC and most game servers' own traffic will not arrive. A TCP protocol works unchanged.
- Reusing an address after closing it. A closed port rests for a day before anyone else can be given it. So a client still pointed at it never reaches someone else's service.
- A sandbox without credit. The response is
payment_required(402). Ports need a paid account and a paid sandbox. - Too many ports. Past the limits above, the response is
quota_exceeded(409: close one first) orrate_limited(429).no_capacity(503) means no public port is free just now (errors). - A paused sandbox. A connection wakes it. Its connections end when it stops, pauses or is deleted.
runtime ports ls lists open ports. runtime ports close <portId> closes one,
and ends its open connections before it returns. Every connection is logged
with the sandbox, the account and the client's address. The log does not
include the contents.
Public port, forward or tunnel?
| You want | Use |
|---|---|
| Clients anywhere to connect | A public TCP port (this page) |
| Only you, from your laptop | Port forwarding: no public address at all |
| Your own servers, privately | A WireGuard tunnel |
| A web app at your own name | A custom domain, with HTTPS |
A port forward is the safer choice for a database that only you use. It goes through Runtime's API with your key, and the sandbox opens nothing to the internet.
Related
- TCP ports in the networking guide.
- The sandbox environment: what is installed.
- Run Docker in a sandbox to serve a containerised database.
Facts on this page were checked on 26 October 2026.