Directives
Control how .env.example variables are interpreted using comment-based directives.
Directives are special comments in .env.example files that control how the CLI interprets variables. They are entirely optional — inference handles most cases automatically. Use directives when you need to override the inferred behavior.
Section directives
Section directives assign all following variables to a bucket until the next section appears. You can optionally include a prefix after the section name:
# @server SERVER_
SERVER_DATABASE_URL=postgres://user:pass@localhost:5432/app
SERVER_PORT=3000
# @client NEXT_PUBLIC_
NEXT_PUBLIC_API_URL=https://example.com
# @shared
NODE_ENV=development
The three sections correspond to the server, client, and shared fields in your envDefinition. Variables without a section default to server.
When a prefix is provided (e.g. # @server SERVER_), the CLI strips the prefix from each key to produce the schema key. The generated envDefinition stores the prefix config:
export const envDefinition = {
prefix: {
server: "SERVER_",
client: "NEXT_PUBLIC_",
shared: "",
},
server: {
DATABASE_URL: withDefault(postgresUrl, "postgres://user:pass@localhost:5432/app"),
PORT: withDefault(port, 3000),
},
client: {
API_URL: withDefault(url, "https://example.com"),
},
// ...
}
When envil add example regenerates the .env.example, it reads the prefix from the envDefinition and emits the combined section+prefix form automatically.
CLI flags (--client-prefix, --server-prefix, --shared-prefix, --framework) take priority over section-level prefix directives.
Per-variable directives
Per-variable directives override inference for individual variables. Place them on the line above the assignment, or inline after the value:
# Above the variable
# @type integer
TIMEOUT=30
# Inline
VERBOSE=true # @optional @redacted
Multiple directives can be combined on a single line.
@type
Overrides the inferred schema kind:
# @type number
RATE=3.14
# @type requiredString
CODE=12345
Accepted values: requiredString, boolean, integer, number, port, url, postgresUrl, redisUrl, mongoUrl, mysqlUrl, commaSeparated, commaSeparatedNumbers, commaSeparatedUrls, json.
Aliases are also accepted: string for requiredString, bool for boolean, int for integer.
@type enum
A special form of @type that generates a stringEnum schema. List the allowed values as a comma-separated list:
# @type enum dev,staging,prod
NODE_ENV=dev
This generates NODE_ENV: withDefault(stringEnum(["dev", "staging", "prod"]), "dev").
@optional
Marks the variable as optional. The generated code wraps it with optional(schema), making it accept undefined:
# @optional
DEBUG_HOST=localhost
Produces DEBUG_HOST: withDefault(optional(requiredString), "localhost") — the variable has a default but is explicitly typed as optional.
Pass false to disable: # @optional false.
@redacted
Marks the variable as sensitive. The generated code wraps it with redacted(schema), producing a Redacted<T> value that won’t leak in logs or serialization:
# @redacted
API_SECRET=my-secret
Pass false to disable: # @redacted false.
@bucket
Overrides the bucket for a single variable, regardless of the active section:
# @server
PORT=3000
# This variable goes to shared even though we're in the server section
# @bucket shared
NODE_ENV=development
@no-default
By default, variables with an assigned value use that value as the default. Use @no-default to opt out, making the variable required at runtime:
# @no-default
PORT=3000
This generates PORT: port with no withDefault wrapper. The assigned value 3000 is still used for type inference, but the variable is required at runtime.
Bucket resolution order
When determining which bucket a variable belongs to, the CLI checks in this order:
- Inline
@bucketdirective on the variable - Active section (
# @server,# @client,# @shared) - Prefix inference (e.g. a key starting with
NEXT_PUBLIC_maps toclientwhen that prefix is configured) - Falls back to
server
Full example
# @server SERVER_
SERVER_PORT=3000
SERVER_DATABASE_URL=postgres://user:pass@localhost:5432/app
# @redacted
SERVER_API_SECRET=change-me
# @type integer
# @no-default
SERVER_MAX_RETRIES=3
# @type enum dev,staging,prod
SERVER_NODE_ENV=dev
# @client NEXT_PUBLIC_
NEXT_PUBLIC_API_URL=https://api.example.com
# @shared
# @optional
DEBUG=false