src/config.ts — the public schema
The single source of truth for what users can write in vx.config.ts.
Pure types + two identity helpers; no runtime logic.
Purpose
Section titled “Purpose”Defines every interface the rest of the codebase consumes:
ProjectConfig, TaskConfig, ExecConfig, ExecEnv,
PersistentConfig, CacheConfig, CacheInputs, CacheOutputs,
WorkspaceConfig.
Exports two helpers — defineProject and defineWorkspace — that
exist purely so TypeScript can narrow the user’s literal types via the
generic parameter.
Public surface
Section titled “Public surface”// Typesexport interface ProjectConfigexport interface WorkspaceConfigexport interface TaskConfigexport interface ExecConfigexport interface ExecEnvexport interface PersistentConfigexport interface CacheConfigexport interface CacheInputsexport interface CacheOutputs
// Helpers (identity functions)export function defineProject<T extends ProjectConfig>(config: T): Texport function defineWorkspace<T extends WorkspaceConfig>(config: T): TTaskConfig.dependsOn is readonly string[] (Turbo/Nx
micro-syntax — see schema.md).
CacheInputs.tasks is the same shape with * / ^* / ! filter
extras.
See ../schema.md for the full reference of every
field’s meaning.
Why an identity helper
Section titled “Why an identity helper”export function defineProject<T extends ProjectConfig>(config: T): T { return config}Two reasons:
- Type inference. When a user writes
defineProject({ tasks: {...} }), the genericT extends ProjectConfiglets TypeScript infer the literal types of nested fields (so task names autocomplete and union types narrow correctly). - Forward compat. If we ever need to do runtime validation or
transformation on the config,
defineProjectis the place; user code already calls through it.
The function body is a one-liner today and that’s by design.
Invariants
Section titled “Invariants”- The exported types and helpers are the only public contract.
Internal modules import them; user code imports them via
@vzn/vx. - No field is optional in the schema if it’s required for correctness.
When
cacheis provided,cache.inputs.filesandcache.outputs.filesare required by the type system (not just at runtime). - The types are JSON-serializable. No
Functionfields, noDateobjects. This is what makestaskConfigHash = sha256(JSON.stringify(config))well-defined.
Replacing this module
Section titled “Replacing this module”You wouldn’t, normally — the schema is the user-facing API. Changes here are breaking.
If you’re forking the project, the things you might want to change:
- Add a new top-level field. Update
TaskConfig, propagate throughorchestrator.ts:executeTask, and bumpCACHE_VERSIONif the field affects caching. - Drop a field. Mark deprecated in JSDoc for a release, then
remove. Bump
CACHE_VERSION. - Tighten a field’s type. Same considerations as add, but check every consumer module.
config.test.ts covers identity behavior + generic type preservation.
Type-level correctness is enforced by tsc -b at build time across
all consumers.