Concepts
Lifecycle & wake-on-join

Lifecycle & wake-on-join

TrueTick servers are scale-to-zero. An idle server hibernates — it stops consuming CPU/RAM and stops billing — and comes back online the moment someone needs it. This is the mechanism behind metered billing: you pay for runtime, not for a box sitting idle.

States

A server moves through a small set of states, reported in state:

StateMeaning
stopped / hibernatedScale-to-zero. Not running, not billing. Data preserved
startingContainer booting / world loading
runningLive and serving players. Billing accrues (metered plan)
stoppingGraceful shutdown in progress (world saved)
installing / install_failedModpack pre-install in progress / failed (see Mods)

You drive transitions with start, stop, and restart. Always treat state as the source of truth and poll it after a transition rather than assuming instant completion.

Wake-on-join

A hibernated server has a lightweight proxy listening on its Minecraft port. When a player connects to my-smp.truetick.gg:25565, the proxy:

  1. Parses the connection handshake.
  2. Boots the real server container.
  3. Hands the player through once it's ready.

The player sees a brief "waking up" experience instead of a dead address. No API call is needed — this is automatic. The sleeping proxy also answers the server-list ping with a MOTD and a sleep line, so the server still looks alive in the multiplayer list.

Programmatic wake. If you want to bring a server up without a player joining (e.g. before a scheduled event, or in a CI job), call POST /v1/servers/{id}:start. Same boot path, triggered by you instead of a join.

Cold start

Boot time depends on the core and content:

  • Vanilla / Paper / Purpur: typically ~12 s to ready.
  • Modded (Forge/NeoForge/Fabric with mods): longer — large modpacks take minutes on first boot, and TrueTick allows up to a 10-minute start window for modded servers.

After boot, the readiness check confirms the server is actually accepting players before marking it running.

Idle hibernation

When a server has had no players for idleTimeoutMinutes, the idle watcher hibernates it back to scale-to-zero. Set the timeout per server via setProperties(id, { idleTimeoutMinutes }). A shorter timeout saves money on bursty workloads; a longer one avoids re-waking during brief lulls.

Putting it together

A typical metered lifecycle:

create (stopped, $0)
   → player joins  ──► wake-on-join ──► running (billing)
   → empty for idleTimeoutMinutes ──► hibernate (stopped, $0)
   → player joins again ──► wake ──► running …

For an agent or CI workflow that controls timing explicitly:

await client.servers.start("ci-test");        // cold start (~12s for Paper)
// … poll until state === "running", run your tests …
await client.servers.stop("ci-test");          // stop billing immediately

See Billing for how runtime maps to cost, and the Ephemeral test server guide for the CI pattern end to end.