How the code-server Idle Timeout Feature Works: Automatic Shutdown Explained
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) 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, the option validates that the value meets minimum requirements before the server initializes.
# 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 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.
// 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. 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.
// 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. The code specifically excludes health check endpoints (/healthz) from triggering the heartbeat to prevent false positives from monitoring systems.
// 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:
code-server --idle-timeout-seconds 900
Configure a 30-minute timeout using environment variables:
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-secondsorCODE_SERVER_IDLE_TIMEOUT_SECONDSinsrc/node/cli.ts. - Activity detection uses the
Heartclass insrc/node/heart.tsto monitor HTTP requests and track 60-second intervals. - Shutdown execution occurs in
src/node/main.tsthroughwrapper.exit(0)only when the heart state isexpiredand the idle timer completes. - Health checks (
/healthz) are explicitly excluded from activity detection insrc/node/routes/index.tsto 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 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 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 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.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →