Memory Limits
Once limits the memory pressure created by concurrent local actions. By default, it schedules against two thirds of the memory visible to the host or container. This leaves room for Once itself, the operating system, editors, and other processes.
Override the budget for any command with --memory-limit:
once --memory-limit 2147483648 build appThe value above is two gibibytes. You can also write it as 2GiB, where GiB
is the abbreviation defined by the International Electrotechnical Commission
binary-prefix standard.
Raw byte counts and decimal unit suffixes are accepted too.
The option is global, so these forms are equivalent:
once --memory-limit 2147483648 test app
once test app --memory-limit 2147483648How Scheduling Uses The Budget#
Each local action reserves its declared memory estimate before it starts. Actions without an estimate reserve 250 mebibytes. Once admits more work only when the combined reservations fit within the configured budget. An action whose estimate exceeds the entire budget runs alone instead of waiting forever.
The same budget applies to builds, lint targets, run targets, literal commands, annotated scripts, and test workers. Internal subprocesses inherit an explicit limit, so nested test and agent-tool invocations do not reset to the machine default.
When a remote cache is selected, Once carves a shared cache-transfer allowance out of the configured memory budget. It starts at one eighth of that budget, with a minimum of 32 MiB + 64 KiB and a maximum of 256 MiB. The minimum fits a streamed response frame and its bounded pipe. Actions use exactly the remainder instead of allocating a second full budget for cache requests. A finite total must exceed that minimum; otherwise the command fails before starting work.
MCP and runtime sessions reserve the same headroom even when initially using a
local cache, because their configuration can change during the session. Ordinary
local-only commands retain the full action allowance. An explicit
--memory-limit 0 keeps action admission unbounded while cache buffers retain
their default allowance.
Cloned cache providers share transfer admission. Scratch downloads have a separate bounded disk budget, and oversized requests fail instead of relying on a server-provided size to allocate arbitrarily.
Cache capture, command error output, and cached output restoration stream large files through bounded buffers and temporary files. Artifact size therefore does not become a same-sized memory allocation during these operations.
Graph actions, producer repairs, and legacy capabilities share the invocation's budget. Output restoration reserves memory for each attempt and releases it before repairing a missing producer. If an observer is cancelled or a repair times out, blocking file work keeps its reservation and action lock until it actually stops. This prevents newly admitted work from overlapping a reservation that was released too early. Cache publication uses the separate carved transfer allowance after execution finishes.
CPU Sharing And Fairness#
Set --cpu-limit COUNT to override the scheduler's CPU capacity:
once --cpu-limit 4 test appTest batches divide the parent CPU budget instead of each inheriting the full host capacity. This is a cooperative scheduling estimate, not a limit on threads a tool can start. Configure tool-specific parallelism through that tool's target kind when needed.
Host admission queues conflicting requests fairly so a stream of smaller actions cannot indefinitely bypass an older large request. Cancelling a queued request removes its claim without consuming capacity. Required minimum capacity is checked separately from estimate normalization; an impossible minimum fails instead of being silently reduced.
What The Limit Guarantees#
This is an admission-control budget based on action estimates, not a hard operating-system memory ceiling. It bounds Once's scheduling decisions and its own artifact buffering. A command that uses more memory than its estimate can still exceed the budget by itself.
Use a container or operating-system process limit when a command must be forcibly stopped at an exact resident-memory boundary. Pair that hard boundary with a lower Once budget so the scheduler leaves enough headroom for the Once process and the operating system.
Choosing A Value#
Start with the automatic default. Set a lower value in a small container or on a shared machine where other services need predictable headroom. If builds become unnecessarily serial, raise the limit gradually and declare realistic memory estimates for unusually small or large actions.
The active value is recorded in verbose internal logs as
memory_limit_bytes, together with the default estimate used for actions that
do not declare one.