once.toml Manifest

Once uses once.toml files for workspace configuration and typed graph targets. The file at the workspace root owns settings shared by the whole repository. Additional manifests declare targets for the package directory that contains them.

Script execution metadata does not belong in a manifest. Annotated scripts keep their contract in # once headers described by Scripted Automation.

Discovery#

By default, Once discovers every once.toml below the workspace root while skipping hidden directories. The root manifest can limit that scan:

toml
[workspace]
include = ["apps/*/once.toml", "packages/*/once.toml"]
exclude = ["packages/experimental/once.toml"]

include and exclude contain workspace-relative glob patterns. They match both once.toml manifests and native project markers such as Cargo.toml and mix.exs. An excluded path is always omitted. When include is empty, every discovered manifest and native project is included unless exclude removes it.

Root-only Tables#

These tables are read only from the root manifest:

TablePurpose
[workspace]Limits manifest discovery with include and exclude.
[workspace.configuration]Selects the target operating system, architecture, and additional configuration tokens.
[modules]Loads project target-kind modules from paths.
[infrastructures.<name>]Declares a named infrastructure provider.
[infrastructure.cache]Chooses the shared cache provider.
[infrastructure.execution]Chooses the remote execution provider.

Package manifests that declare [modules] are rejected. Keep shared module and infrastructure configuration at the workspace root so every package sees the same definitions.

See Modules and Infrastructure for the contracts owned by those tables.

The target configuration defaults to the host. Set it explicitly when analysis and dependency selection should describe another platform:

toml
[workspace.configuration]
os = "linux"
arch = "arm64"
tokens = ["release"]

Once normalizes common operating system and architecture names. For example, darwin becomes macos, arm64 becomes aarch64, and amd64 becomes x86_64. The ordered selection tokens include the most specific operating-system and architecture combinations, their aliases, the individual values, the additional tokens, and default. Use once query workspace to inspect the exact configuration seen by target kinds.

once build, once lint, once run, and once test accept --config overrides that layer on top of these workspace defaults for a single invocation. See the configurations guide for the override model, precedence, and how outputs stay separated.

An execution-only provider can select a sandbox adapter and immutable tool environment:

toml
[infrastructures.remote_tests]
kind = "microsandbox"
image = "node:22.18.0-alpine"
[infrastructure.execution]
provider = "remote_tests"

The provider name is a workspace policy label. Script headers and command-line options can select it without coupling the script to Microsandbox.

Hosted execution providers select their immutable environment with a template or image:

toml
[infrastructures.e2b_tests]
kind = "e2b"
template = "vitest-node-22"
[infrastructures.daytona_tests]
kind = "daytona"
image = "node:22.18.0-bookworm"

E2B, Daytona, and Microsandbox provide execution only. Tuist provides shared caching. Bind each capability independently when a workspace uses both.

Targets#

The root manifest and package manifests can declare one or more targets:

toml
[[target]]
name = "hello"
kind = "rust_binary"
srcs = ["src/**/*.rs"]
deps = ["../greeting/greeting"]
[target.attrs]
crate_root = "src/main.rs"
edition = "2024"

Every target accepts these common fields:

FieldRequiredMeaning
nameyesName unique within the package.
kindyesTarget kind that defines attributes, dependencies, providers, and capabilities.
srcsnoPackage-relative source paths or glob patterns.
depsnoTarget identifiers consumed by this target.
dependenciesnoNamed dependency roles declared by the target kind. Each role contains target identifiers and validates its own provider contract.
visibilitynoConsumers allowed to depend on this target. An empty list is public.
attrsnoTarget-kind-specific values validated against the selected schema.

Unknown manifest fields are rejected. Use once query schema <kind> to inspect the attributes and dependency contracts accepted by a target kind.

Use deps for the target kind's default dependency role. Use [target.dependencies] when the schema exposes more precise roles:

toml
[[target]]
name = "app"
kind = "rust_binary"
deps = ["./library"]
[target.dependencies]
proc_macro_deps = ["./derive"]
link_deps = ["./native"]

Validation checks each role against its matching schema entry. Analysis keeps deps in declared order and exposes the other roles separately, so a target kind can distinguish compiler plug-ins, runtime-only dependencies, native links, and other semantics without hardcoding them in Once. Target kinds can also set minimum and maximum counts for each role. Validation reports an attribute-scoped repair before an edit can commit too few or too many dependencies.

Target Identifiers#

A target identifier combines its package path and target name. A target named hello in apps/hello/once.toml has the identifier apps/hello/hello. A target in the root manifest uses its name directly.

Dependency references resolve as follows:

  • packages/logging/logging is relative to the workspace root.
  • ./support is relative to the package containing the current manifest.
  • ../shared/shared moves from the current package to a sibling package.

Use one of these identifiers with once query target, once build, once run, and once test.

Target-valued entries under [target.attrs] use the same normalization rules. once query validate-workspace checks that these references resolve to a declared target.

Visibility#

Targets are public unless visibility restricts them:

toml
[[target]]
name = "Core"
kind = "rust_library"
visibility = ["package:apps/client", "subtree:tools", "tests/CoreTests"]

Each entry grants access to one class of consumer:

  • public grants access to every target.
  • private grants access to targets in the same package.
  • package:apps/client grants access to targets in that exact package.
  • subtree:tools grants access to targets in tools and its child packages.
  • tests/CoreTests grants access to one exact target.

Exact targets use the same workspace-relative and package-relative normalization as dependencies. Complete-workspace validation returns invalid_visibility for malformed entries and dependency_not_visible when a dependency edge crosses the declared boundary.

Conditional Values#

Target kinds can accept select values for configurable attributes. A target can also select dependencies for the workspace target configuration:

toml
[target.deps.select]
macos = ["./apple_support"]
linux = ["./linux_support"]
default = ["./portable_support"]

The target-kind schema reports both configurable and implemented for every attribute. Validation rejects select on a non-configurable attribute and rejects an unavailable compatibility attribute marked implemented = false. Schemas can also report allowed_values for string attributes. Validation rejects other values with the target, attribute, and accepted replacements. Schemas can report disallowed_values when only a small reserved set should be rejected. Validation ignores surrounding whitespace for those comparisons and reports an attribute-scoped replacement before analysis. Generic target kinds use the tokens returned by once query workspace. Ecosystem target kinds can add their own tokens and restrictions.

Inspect#

Use the graph before running work:

bash
once query targets
once query target apps/hello/hello
once query schema rust_binary

These commands show resolved target identifiers, selected target kinds, dependencies, capabilities, and accepted attributes.