# How the code-server Idle Timeout Feature Works: Automatic Shutdown Explained

> Understand the code server idle timeout feature. Learn how inactivity triggers automatic shutdown after 60 seconds and your configured duration.

- Repository: [Coder/code-server](https://github.com/coder/code-server)
- Tags: internals
- Published: 2026-03-01

---

**The code-server idle timeout feature shuts down the server automatically after a period of inactivity, triggered only when no HTTP requests (except health checks) have been received for 60 seconds followed by the configured idle timeout duration.**

The `coder/code-server` repository implements automatic shutdown through a two-phase detection system that monitors HTTP activity via a heartbeat mechanism. This feature helps manage resource consumption in containerized or cloud environments where idle processes should terminate to free up compute resources.

## What Triggers the Automatic Shutdown?

Automatic shutdown occurs through a specific sequence of inactivity detection. First, the **heartbeat monitor** ([`src/node/heart.ts`](https://github.com/coder/code-server/blob/main/src/node/heart.ts)) tracks incoming HTTP requests and enters an `expired` state when no activity occurs for approximately 60 seconds. Only when this heartbeat expires does the **idle shutdown timer** begin counting down the configured timeout period. If no new requests arrive during this countdown, `wrapper.exit(0)` terminates the process.

The shutdown is **not** triggered by the initial idle timeout value alone. The server must first pass through the heartbeat expiration phase (indicating true idleness) before the countdown begins. Any incoming request during either phase resets the timers and prevents shutdown.

## How the Idle Timeout Mechanism Works

### Configuration via CLI and Environment Variables

The idle timeout duration is configured through the `--idle-timeout-seconds` command-line flag or the `CODE_SERVER_IDLE_TIMEOUT_SECONDS` environment variable. According to the source code in [`src/node/cli.ts`](https://github.com/coder/code-server/blob/main/src/node/cli.ts), the option validates that the value meets minimum requirements before the server initializes.

```bash

# Start with a 15-minute idle timeout

code-server --idle-timeout-seconds 900

# Or use environment variable for 30 minutes

export CODE_SERVER_IDLE_TIMEOUT_SECONDS=1800
code-server

```

### The Heartbeat Activity Monitor

The `Heart` class in [`src/node/heart.ts`](https://github.com/coder/code-server/blob/main/src/node/heart.ts) implements the core activity detection logic. On each incoming request, the `beat()` method updates a timestamp and resets an internal 60-second timer. If this timer fires without subsequent activity, the heart state changes to `expired`.

```typescript
// src/node/heart.ts – activity detection
public async beat(): Promise<void> {
  if (this.alive()) { this.setState("alive"); return; }

  this.lastHeartbeat = Date.now();
  if (this.heartbeatTimer) clearTimeout(this.heartbeatTimer);

  // Reset after heartbeatInterval (60 s) if no further activity
  this.heartbeatTimer = setTimeout(async () => {
    if (await this.isActive()) {
      this.beat();            // keep alive
    } else {
      this.setState("expired"); // no activity → idle
    }
  }, this.heartbeatInterval);
}

```

### The Idle Shutdown Timer

The orchestration logic resides in [`src/node/main.ts`](https://github.com/coder/code-server/blob/main/src/node/main.ts). When `--idle-timeout-seconds` is present, the code creates a `setTimeout` that calls `wrapper.exit(0)`. Crucially, this timer only starts (or restarts) when the heart state changes to `expired`, and clears immediately upon any state change to `alive`.

```typescript
// src/node/main.ts – idle-shutdown timer setup
if (args["idle-timeout-seconds"]) {
  let idleShutdownTimer: NodeJS.Timeout | undefined;
  const startIdleShutdownTimer = () => {
    idleShutdownTimer = setTimeout(() => {
      logger.warn(`Idle timeout of ${args["idle-timeout-seconds"]} seconds exceeded`);
      wrapper.exit(0);
    }, args["idle-timeout-seconds"]! * 1000);
  };
  startIdleShutdownTimer();

  // Reset timer whenever heart state changes
  heart.onChange(state => {
    clearTimeout(idleShutdownTimer);
    if (state === "expired") {
      startIdleShutdownTimer();
    }
  });
}

```

### Request Hook Integration

Every HTTP request triggers activity tracking through middleware in [`src/node/routes/index.ts`](https://github.com/coder/code-server/blob/main/src/node/routes/index.ts). The code specifically excludes health check endpoints (`/healthz`) from triggering the heartbeat to prevent false positives from monitoring systems.

```typescript
// src/node/routes/index.ts – record activity on each request
if (!/^\/healthz\/?$/.test(req.url)) {
  // do not await – we don’t want to delay the response
  heart.beat();
}

```

## Practical Configuration Examples

Configure a 15-minute idle timeout using the CLI flag:

```bash
code-server --idle-timeout-seconds 900

```

Configure a 30-minute timeout using environment variables:

```bash
export CODE_SERVER_IDLE_TIMEOUT_SECONDS=1800
code-server

```

Note that the CLI flag takes precedence over the environment variable when both are set.

## Summary

- The idle timeout feature requires **two consecutive idle periods**: first a 60-second heartbeat expiration, then the configured timeout duration.
- **Configuration** happens via `--idle-timeout-seconds` or `CODE_SERVER_IDLE_TIMEOUT_SECONDS` in [`src/node/cli.ts`](https://github.com/coder/code-server/blob/main/src/node/cli.ts).
- **Activity detection** uses the `Heart` class in [`src/node/heart.ts`](https://github.com/coder/code-server/blob/main/src/node/heart.ts) to monitor HTTP requests and track 60-second intervals.
- **Shutdown execution** occurs in [`src/node/main.ts`](https://github.com/coder/code-server/blob/main/src/node/main.ts) through `wrapper.exit(0)` only when the heart state is `expired` and the idle timer completes.
- **Health checks** (`/healthz`) are explicitly excluded from activity detection in [`src/node/routes/index.ts`](https://github.com/coder/code-server/blob/main/src/node/routes/index.ts) to prevent keeping the server alive artificially.

## Frequently Asked Questions

### How do I disable the idle timeout feature?

**Do not set the `--idle-timeout-seconds` flag or the `CODE_SERVER_IDLE_TIMEOUT_SECONDS` environment variable.** When these values are absent, [`src/node/main.ts`](https://github.com/coder/code-server/blob/main/src/node/main.ts) skips the idle shutdown timer initialization entirely, allowing the server to run indefinitely regardless of activity levels.

### Why does the server take longer than my configured timeout to shut down?

**The actual shutdown time equals your configured timeout plus the 60-second heartbeat interval.** The server waits for the heartbeat to expire (60 seconds of no requests) before starting your configured countdown. For example, a 300-second (5-minute) setting results in approximately 6 minutes of total idle time before shutdown.

### Do WebSocket connections or terminal activity count as HTTP requests?

**Yes, any request passing through the Express middleware in [`src/node/routes/index.ts`](https://github.com/coder/code-server/blob/main/src/node/routes/index.ts) triggers `heart.beat()`,** including WebSocket upgrade requests and terminal data. The heartbeat mechanism monitors all incoming traffic except explicit health check endpoints, ensuring active development sessions prevent shutdown.

### What happens if I set the timeout to a very low value?

**The CLI validation in [`src/node/cli.ts`](https://github.com/coder/code-server/blob/main/src/node/cli.ts) enforces minimum values to prevent accidental immediate shutdown.** Setting extremely low values (below practical thresholds) may be rejected during argument parsing, or cause the server to shut down rapidly after the initial 60-second heartbeat expiration period completes.