cloudflare
references/containers/api.md
.md 188 lines
Content
## Container Class API
```typescript
import { Container } from "@cloudflare/containers";
export class MyContainer extends Container {
defaultPort = 8080;
requiredPorts = [8080];
sleepAfter = "30m";
enableInternet = true;
pingEndpoint = "/health";
envVars = {};
entrypoint = [];
onStart() { /* container started */ }
onStop() { /* container stopping */ }
onError(error: Error) { /* container error */ }
onActivityExpired(): boolean { /* timeout, return true to stay alive */ }
async alarm() { /* scheduled task */ }
}
```
## Routing
**getByName(id)** - Named instance for session affinity, per-user state
**getRandom()** - Random instance for load balancing stateless services
```typescript
const container = env.MY_CONTAINER.getByName("user-123");
const container = env.MY_CONTAINER.getRandom();
```
## Startup Methods
### start() - Basic start (8s timeout)
```typescript
await container.start();
await container.start({ envVars: { KEY: "value" } });
```
Returns when **process starts**, NOT when ports ready. Use for fire-and-forget.
### startAndWaitForPorts() - Recommended (20s timeout)
```typescript
await container.startAndWaitForPorts(); // Uses requiredPorts
await container.startAndWaitForPorts({ ports: [8080, 9090] });
await container.startAndWaitForPorts({
ports: [8080],
startOptions: { envVars: { KEY: "value" } }
});
```
Returns when **ports listening**. Use before HTTP/TCP requests.
**Port resolution:** explicit ports → requiredPorts → defaultPort → port 33
### waitForPort() - Wait for specific port
```typescript
await container.waitForPort(8080);
await container.waitForPort(8080, { timeout: 30000 });
```
## Communication
### fetch() - HTTP with WebSocket support
```typescript
// ✅ Supports WebSocket upgrades
const response = await container.fetch(request);
const response = await container.fetch("http://container/api", {
method: "POST",
body: JSON.stringify({ data: "value" })
});
```
**Use for:** All HTTP, especially WebSocket.
### containerFetch() - HTTP only (no WebSocket)
```typescript
// ❌ No WebSocket support
const response = await container.containerFetch(request);
```
**⚠️ Critical:** Use `fetch()` for WebSocket, not `containerFetch()`.
### TCP Connections
```typescript
const port = this.ctx.container.getTcpPort(8080);
const conn = port.connect();
await conn.opened;
if (request.body) await request.body.pipeTo(conn.writable);
return new Response(conn.readable);
```
### switchPort() - Change default port
```typescript
this.switchPort(8081); // Subsequent fetch() uses this port
```
## Lifecycle Hooks
### onStart()
Called when container process starts (ports may not be ready). Runs in `blockConcurrencyWhile` - no concurrent requests.
```typescript
onStart() {
console.log("Container starting");
}
```
### onStop()
Called when SIGTERM received. 15 minutes until SIGKILL. Use for graceful shutdown.
```typescript
onStop() {
// Save state, close connections, flush logs
}
```
### onError()
Called when container crashes or fails to start.
```typescript
onError(error: Error) {
console.error("Container error:", error);
}
```
### onActivityExpired()
Called when `sleepAfter` timeout reached. Return `true` to stay alive, `false` to stop.
```typescript
onActivityExpired(): boolean {
if (this.hasActiveConnections()) return true; // Keep alive
return false; // OK to stop
}
```
## Scheduling
```typescript
export class ScheduledContainer extends Container {
async fetch(request: Request) {
await this.schedule(Date.now() + 60000); // 1 minute
await this.schedule("2026-01-28T00:00:00Z"); // ISO string
return new Response("Scheduled");
}
async alarm() {
// Called when schedule fires (SQLite-backed, survives restarts)
}
}
```
**⚠️ Don't override `alarm()` directly when using `schedule()` helper.**
## State Inspection
### External state check
```typescript
const state = await container.getState();
// state.status: "starting" | "running" | "stopping" | "stopped"
```
### Internal state check
```typescript
export class MyContainer extends Container {
async fetch(request: Request) {
if (this.ctx.container.running) { ... }
}
}
```
**⚠️ Use `getState()` for external checks, `ctx.container.running` for internal.**