The .env.schema contract file
A project with a git-authored contract keeps it in the repository as a
.env.schema file and pushes it with
varlatch contract push --schema .env.schema. This page defines the format
Varlatch accepts. Anything it does not list is unsupported.
Varlatch parses the file on your machine, resolves the environment names it
uses against the project’s environments, and pushes the result as a contract
revision. The server stores and enforces that contract, never the file
itself. Values never come from .env.schema: they live in Varlatch, and
varlatch run delivers them.
The format comes from @env-spec,
which DMNO created for Varlock. Varlatch reads the subset on this page with
its own parser and does not follow later changes to @env-spec, so a file
another tool accepts may fail here or mean something different, as with
@defaultRequired=infer below.
Fail loudly
Section titled “Fail loudly”A decorator the parser does not understand is an error, never ignored. So is
a decorator written after a value, text after a quoted value, and an
unterminated quote. An environment name in env(...) that the project does
not have is an error when you push, and the error lists the names that exist.
The only accepted no-op decorators are the presentation-only @docs,
@icon, and @tag.
Supported syntax
Section titled “Supported syntax”Root decorators, on comment lines before the first item:
| Decorator | Meaning |
|---|---|
@defaultSensitive=true or false |
Default sensitivity for items without an explicit marker. If absent, the default is true: items are Secrets unless marked otherwise. |
@defaultRequired=true, false, or infer |
Default requiredness. infer is treated as false: requiredness is never inferred from whether a value is present. |
Item decorators, on comment lines directly above an item, one per line:
| Decorator | Contract field |
|---|---|
@required or @required=true |
required in every environment |
@required=false or @optional |
never required |
@required=env(production, staging) |
required in these environments of the project, by name |
@required=tier(production) |
required in every environment of this tier: development, staging, or production |
@sensitive or @sensitive=true |
sensitive |
@sensitive=false or @public |
not sensitive |
@type=string, number, integer, boolean, url, or email |
type (integer needs Contract Semantics version 3; see Contract Semantics) |
@type=enum(a, b, ...) |
enum type with these values |
@example=... |
example (quotes stripped) |
@rotationGrace=86400 |
default grace window for a rotation, in whole seconds from 1 to 2592000 (30 days); at most once per item |
@rotationHint=... |
how to rotate this credential, shown where rotation happens (quotes stripped); at most once per item |
A rotation hint is one line: comment lines after it are still the item’s
description. It holds 1 to 1024 characters, without tabs, line breaks,
control characters or bidirectional formatting characters, which are
rejected rather than removed. Every Member can read the Contract, so a
hint must never contain a secret: write the steps, not the credential.
It never appears in generated types. An item that uses @rotationHint
needs Varlatch 0.20.0 or later on the server and in the CLI: older
servers refuse such a Contract, and older CLIs refuse it in
varlatch types.
What each type accepts, and which version of the rules a pushed revision uses, is described in Contract Semantics.
Items:
NAME=declares an item with no default.NAME=literalorNAME="literal"sets the default value.NAME=fn(...)declares an item whose value comes from elsewhere. Varlatch never runs the function and records no default.- After a value, whitespace followed by
#starts a comment:PORT=8080 # listen portgives the default8080. A#with no whitespace before it stays part of the value (P=p@ss#w0rdgivesp@ss#w0rd), and so does a#inside quotes. - Plain
# textcomment lines directly above an item become its description. - A blank line resets pending decorators and description.
Item names must match ^[A-Z][A-Z0-9_]*$. A leading UTF-8 byte-order mark
is ignored, and a file with CR-only line endings is rejected.
Environment names
Section titled “Environment names”env(...) names root environments of the project, the ones created without
a parent. A preview or personal environment follows its root. When you push,
each name is resolved to that environment’s ID, and the contract revision
stores the IDs, not the names:
- Renaming or deleting an environment later never changes a stored revision.
- The next push resolves the names again. After a rename, the old name fails the push. If a name was freed by deleting its environment and then reused by a new one, the push selects the new environment. The change shows up as a requiredness change when the revision is activated.
Use tier(...) when an item is required in every environment of a tier
rather than in specific ones.
forEnv(...) is not supported. A file that uses it fails with the
replacement: name the project’s environments with env(...), or use
tier(...). For example, @required=forEnv(prod) becomes
@required=env(production).
Known limitations
Section titled “Known limitations”- Escape sequences are not interpreted.
MULTI="a\nb"gives the literal defaulta\nb, not a newline. Multi-line values are not supported. - One decorator per line. A comment line with several decorators is rejected, not split.
What the format cannot express
Section titled “What the format cannot express”Anything outside the contract model: value sources and their arguments,
imports, code generation settings, and per-environment .env.* files.

