dottie (pronounced dotty) makes .env files maintainable at scale.
Most teams start with a small .env, then over time it becomes hard to review, risky to edit, and difficult to keep in sync across environments. Dottie turns .env from a plain text dump into a structured, validated, automatable configuration document.
- Safer changes — validate values before they ship (e.g. URL, number, email, required values).
- Less drift — update local
.envfiles from an upstream template while preserving local values. - Better readability — keep sections, comments, formatting, and optional/disabled values organized.
- Automation-friendly — query values, print JSON, or render custom docs/templates from the
.envmodel. - Team-friendly workflows — treat
.envas code with predictable formatting and command-driven edits.
- Create and update values with comments, quote styles, ordering, and groups.
- Enable/disable keys without losing the original value.
- Validate values using annotation-based rules.
- Format files for consistent style.
- Print in multiple styles (compact, pretty, export, filtered, with/without disabled keys).
- Read specific values as literal or interpolated output.
- List groups and inspect file structure.
- Export JSON for external tooling.
- Render templates for generated docs or config artifacts.
- Annotations in comments (e.g.
@dottie/validate,@dottie/source) attach metadata to keys. - Groups organize keys into logical sections.
- Interpolation resolves references like
${PORT}when desired. - Disabled keys are preserved as commented assignments and can be re-enabled later.
- Upstream source templates let you evolve defaults without overwriting local intent.
Warning
Run these example commands in a directory without an existing .env file
# Create a new `.env` file
touch .env
# Create a key/value pair
dottie set my_key=value
# Create another key (PORT) with value "3306"
# * One comment
# * One validation rule that the value must be a number
# * "none" quote style from the default "double"
dottie set \
--comment 'A port for some service' \
--comment '@dottie/validate number' \
--quote-style none \
PORT=3306
# Check validation (success)
dottie validate
# Print the file
dottie print
# Print the file (but pretty)
dottie print --pretty
# Change the "PORT" value to a "test" (a non-number).
# NOTE: the comments are kept in the file, even if they are omitted here
dottie set PORT=test
# Test validation again (it now fails)
dottie validate
# Fix the port value
dottie set PORT=3306
# Create a new key/value pair in a group named "database"
# NOTE: the group will be created on-demand if it does not exist
dottie set \
--group database \
--comment 'the hostname to the database' \
DB_HOST="db"
# Create a "DB_PORT" key pair in the same "database" group as before
# NOTE: this value refers to the 'PORT' key we set above via interpolation
dottie set \
--group database \
--comment 'the port for the database' \
--comment '@dottie/validate number' \
DB_PORT='${PORT}'
# Print the file again
dottie print --pretty
# Disable the DB_PORT key
dottie disable DB_PORT
# Print the file again
# NOTE: the DB_PORT key/value is now gone
dottie print --pretty
# Print the file again, but include commented disabled keys
# NOTE: the DB_PORT key/value is printed (but still disabled)
dottie print --pretty --with-disabled
# Enable the DB_PORT key again
dottie enable DB_PORTThis flow shows the core Dottie lifecycle:
- Create and annotate keys (
set+ comments + validation rules) - Validate correctness (
validate) - Inspect output in different modes (
print,value,json) - Temporarily toggle behavior (
disable/enable) - Keep everything readable and consistent over time (
fmt,update)
brew install jippi/tap/dottieecho 'deb [trusted=yes] https://pkg.jippi.dev/apt/ * *' | sudo tee /etc/apt/sources.list.d/dottie.list
sudo apt update
sudo apt install dottieecho '[dottie]
name=dottie
baseurl=https://pkg.jippi.dev/yum/
enabled=1
gpgcheck=0' | sudo tee /etc/yum.repos.d/dottie.repo
sudo yum install dottiesudo snap install dottiescoop bucket add dottie https://github.com/jippi/scoop-bucket.git
scoop install dottieyay -S dottie-binDownload the .deb, .rpm or .apk packages from the releases page and install them with the appropriate tools.
go install github.com/jippi/dottie@latestAll artifacts are checksummed, and the checksum file is signed with cosign.
-
Download the files you want, and the
checksums.txt,checksum.txt.pemandchecksums.txt.sigfiles from the releases page: -
Verify the signature:
cosign verify-blob \ --certificate-identity 'https://github.com/jippi/dottie/.github/workflows/release.yml@refs/tags/v1.0.0' \ --certificate-oidc-issuer 'https://token.actions.githubusercontent.com' \ --cert 'https://github.com/jippi/dottie/releases/download/v1.0.0/checksums.txt.pem' \ --signature 'https://github.com/jippi/dottie/releases/download/v1.0.0/checksums.txt.sig' \ ./checksums.txt
-
If the signature is valid, you can then verify the SHA256 sums match with the downloaded binary:
sha256sum --ignore-missing -c checksums.txt
Our Docker images are signed with cosign.
Verify the signatures:
cosign verify \
--certificate-identity 'https://github.com/jippi/dottie/.github/workflows/release.yml@refs/tags/v1.0.0' \
--certificate-oidc-issuer 'https://token.actions.githubusercontent.com' \
jippi/dottieNote
The .pem and .sig files are the image name:tag, replacing / and : with -.
Quick navigation:
All commands support the following global flags:
| Flag | Description | Default |
|---|---|---|
-f, --file |
Load this file | .env |
-h, --help |
Help for the command |
Set/update one or multiple key=value pairs.
Related: Annotation Reference
dottie set KEY=VALUE [KEY=VALUE ...] [flags]
| Flag | Description | Default |
|---|---|---|
--after |
If the key doesn't exist, add it to the file after this KEY | |
--before |
If the key doesn't exist, add it to the file before this KEY | |
--comment |
Set one or multiple lines of comments to the KEY=VALUE pair | |
--disabled |
Set/change the flag to be disabled (commented out) | |
--error-if-missing |
Exit with an error if the KEY does not exist in the .env file already |
|
--group |
The (optional) group name to add the KEY=VALUE pair under | |
--quote-style |
The quote style to use (single, double, none) |
double |
--skip-if-exists |
If the KEY already exists, do not set or change any settings | |
--skip-if-same |
If the KEY already exists and the value is identical, do not set or change any settings | |
--validate / --no-validate |
Validate the VALUE input before saving the file | true |
Examples
Create a key with comments and a validation rule:
$ dottie set \
--comment 'The port for the web server' \
--comment '@dottie/validate number' \
--quote-style none \
PORT=8080
Key [ PORT ] was successfully upserted
File was successfully savedResulting .env entry:
# The port for the web server
# @dottie/validate number
PORT=8080Create a key inside a group:
$ dottie set --group database --comment 'Database hostname' DB_HOST=localhost
Key [ DB_HOST ] was successfully upserted
File was successfully savedThe group is created automatically if it doesn't exist:
################################################################################
# database
################################################################################
# Database hostname
DB_HOST="localhost"Validation prevents invalid values:
If a key has a @dottie/validate number annotation, setting a non-numeric value is rejected:
$ dottie set PORT=hello
PORT ( .env:5 )
* (number) The value [hello] is not a valid number.
Error: Key: 'PORT' Error:Field validation for 'PORT' failed on the 'number' tagUpdate the .env file from a source.
Related: Annotation Reference
dottie update [flags]
| Flag | Description | Default |
|---|---|---|
--backup / --no-backup |
Should the .env file be backed up before updating it? |
true |
--backup-file |
File path to write the backup to (by default it will write a .env.dottie-backup file in the same directory) |
|
--error-on-missing-key |
Error if a KEY in FILE is missing from SOURCE | |
--no-error-on-missing-key |
Add KEY to FILE if missing from SOURCE | true |
--exclude-key-prefix |
Ignore these KEY prefixes | |
--ignore-disabled |
Ignore disabled KEY/VALUE pairs from the .env file |
true |
--ignore-rule |
Ignore this validation rule (e.g. dir) |
|
--save / --no-save |
Save the document after processing | true |
--validate / --no-validate |
Validation errors will abort the update | true |
--source |
URL or local file path to the upstream source file. Takes precedence over any @dottie/source annotation in the file |
Example
The source file can be specified via a @dottie/source annotation in the .env file itself:
# @dottie/source https://example.com/template.env
APP_NAME="my-app"
DB_HOST="localhost"Or via the --source flag:
dottie update --source https://example.com/template.envThe update process:
- Fetches the source/template
.envfile - Merges your local values into the source structure
- Adds new keys from the source with their default values
- Preserves your existing values for keys that already exist
- Comments and structure come from the source template
A backup file (.env.dottie-backup) is created by default before updating.
Format a .env file. Ensures consistent spacing by adding blank lines between key/value groups, especially before comment blocks.
dottie fmt [flags]
Example
Given a .env file with inconsistent spacing:
KEY1=hello
# Comment for KEY2
KEY2=world
# Comment for KEY3
KEY3=testRunning:
$ dottie fmt
File was successfully formattedThe .env file is now properly spaced:
KEY1=hello
# Comment for KEY2
KEY2=world
# Comment for KEY3
KEY3=testBlank lines are automatically added before comment blocks to improve readability.
Disable (comment out) a KEY if it exists. The key is prefixed with # to comment it out, making it invisible to normal print output while preserving the value for later re-enabling.
dottie disable KEY [flags]
Example
Given a .env file:
APP_NAME="dottie"
# Database port
DB_PORT="3306"Running:
$ dottie disable DB_PORT
Key [ DB_PORT ] was successfully disabledThe .env file is now:
APP_NAME="dottie"
# Database port
#DB_PORT="3306"The key is commented out with # but all comments above it are preserved. Use dottie print --with-disabled to still see disabled keys in output.
Enable (uncomment) a KEY if it exists. Removes the leading # from a previously disabled key, making it active again.
dottie enable KEY [flags]
Example
Given a .env file with a disabled key:
# Database port
#DB_PORT="3306"Running:
$ dottie enable DB_PORT
Key [ DB_PORT ] was successfully enabledThe .env file is now:
# Database port
DB_PORT="3306"Run update logic against a source without forcing a file write. This is useful for checks, previews, CI validation, and troubleshooting update behavior before persisting changes.
dottie exec [flags]
| Flag | Description | Default |
|---|---|---|
--error-on-missing-key |
Error if a KEY in FILE is missing from SOURCE | |
--no-error-on-missing-key |
Add KEY to FILE if missing from SOURCE | true |
--exclude-key-prefix |
Ignore these KEY prefixes | |
--ignore-rule |
Ignore this validation rule (e.g. dir) |
|
--save / --no-save |
Save the document after processing | true |
--validate / --no-validate |
Validation errors will abort the update | true |
--source |
URL or local file path to the upstream source file. Takes precedence over any @dottie/source annotation in the file |
Example
Preview update behavior without writing changes:
dottie exec --source https://example.com/.env.template --no-saveThis will:
- Load your current
.env - Load the source/template file
- Run merge + validation logic
- Print issues if any, without saving the result
Use dottie update when you want to persist the merged output to disk.
Start an interactive dottie shell for exploring and working with your .env file in a REPL-style workflow.
dottie shell [flags]
Use this when you prefer an interactive session over one-off commands, especially while iterating on config changes.
Print environment variables.
dottie print [flags]
| Flag | Description | Default |
|---|---|---|
--blank-lines / --no-blank-lines |
Show blank lines | true |
--color / --no-color |
Enable color output | true |
--comments / --no-comments |
Show comments | false |
--export |
Prefix all key/value pairs with export statement |
|
--group |
Filter by group name (glob wildcard supported) | |
--group-banners / --no-group-banners |
Show group banners | false |
--interpolation / --no-interpolation |
Enable interpolation | true |
--key-prefix |
Filter by key prefix | |
--pretty |
Implies --color --comments --blank-lines --group-banners |
|
--with-disabled |
Include disabled assignments |
Examples
Given this .env file:
APP_NAME="dottie"
# The port for the web server
# @dottie/validate number
PORT=8080
################################################################################
# database
################################################################################
# Database hostname
DB_HOST="localhost"
# Database port
# @dottie/validate number
DB_PORT="${PORT}"Default output (compact, keys and values only):
$ dottie print
APP_NAME="dottie"
PORT=8080
DB_HOST="localhost"
DB_PORT="8080"Note: DB_PORT shows 8080 (interpolated from ${PORT}) rather than the literal ${PORT}.
Pretty output (with comments, spacing, and group banners):
$ dottie print --pretty
APP_NAME="dottie"
# The port for the web server
# @dottie/validate number
PORT=8080
################################################################################
# database
################################################################################
# Database hostname
DB_HOST="localhost"
# Database port
# @dottie/validate number
DB_PORT="8080"Export format (for sourcing in shell scripts):
$ dottie print --export
export APP_NAME="dottie"
export PORT=8080
export DB_HOST="localhost"
export DB_PORT="8080"Filter by group:
$ dottie print --group database
DB_HOST="localhost"
DB_PORT="8080"Filter by key prefix:
$ dottie print --key-prefix DB_
DB_HOST="localhost"
DB_PORT="8080"Validate a .env file.
Validation rules come from @dottie/validate annotations. See @dottie/validate Reference.
dottie validate [flags]
| Flag | Description | Default |
|---|---|---|
--exclude-prefix |
Exclude KEY with this prefix | |
--fix / --no-fix |
Guide the user to fix supported validation errors | true |
--ignore-rule |
Ignore this validation rule (e.g. dir) |
Example
Given a .env with validation annotations:
# @dottie/validate number
PORT=hello
# @dottie/validate email
ADMIN_EMAIL=not-an-email
# @dottie/validate required
API_KEY=Running validation:
$ dottie validate --no-fix
┌──────────────────────────────────────────────────────────────────────────────┐
│ 3 validation errors found │
└──────────────────────────────────────────────────────────────────────────────┘
PORT (.env:2)
* (number) The value [hello] is not a valid number.
ADMIN_EMAIL (.env:5)
* (email) The value [not-an-email] is not a valid e-mail address.
API_KEY (.env:8)
* (required) This value is required and cannot be empty.When all values are valid:
$ dottie validate
┌──────────────────────────────────────────────────────────────────────────────┐
│ No validation errors found │
└──────────────────────────────────────────────────────────────────────────────┘For the full dottie-focused validator tag reference and syntax examples, see @dottie/validate Reference.
Print the value of a .env key if it exists.
dottie value KEY [flags]
| Flag | Description | Default |
|---|---|---|
--literal |
Show literal value instead of interpolated | |
--with-disabled |
Include disabled assignments |
Example
Given a .env with DB_PORT="${PORT}" and PORT=8080:
# Interpolated value (default) - resolves variable references
$ dottie value DB_PORT
8080
# Literal value - shows the raw value as written in the file
$ dottie value DB_PORT --literal
${PORT}If a key is disabled (commented out), you need --with-disabled:
$ dottie value DB_PORT
Error: key [ DB_PORT ] exists, but is commented out - use [--with-disabled] to include it
$ dottie value DB_PORT --with-disabled
8080Print groups found in the .env file. Groups are defined by section headers using the banner format.
dottie groups [flags]
Example
Given a .env file with groups:
APP_NAME="dottie"
################################################################################
# database
################################################################################
DB_HOST="localhost"Running:
$ dottie groups
┌──────────────────────────────────────────────────────────────────────────────┐
│ Groups in .env │
└──────────────────────────────────────────────────────────────────────────────┘
database (.env:4)Group names can be used to filter output with dottie print --group database.
Print the .env file as JSON. Outputs a structured JSON representation including keys, values, comments, annotations, groups, variable dependencies, and position information.
dottie json [flags]
Example
Given a .env file:
# @dottie/validate number
PORT=8080
DB_PORT="${PORT}"Running:
dottie jsonOutputs (abbreviated):
{
"statements": [
{
"key": "PORT",
"literal": "8080",
"enabled": true,
"quote": null,
"comments": [
{
"value": "# @dottie/validate number",
"annotation": { "Key": "dottie/validate", "Value": "number" }
}
],
"dependents": {
"DB_PORT": { "key": "DB_PORT", "literal": "${PORT}" }
}
},
{
"key": "DB_PORT",
"literal": "${PORT}",
"enabled": true,
"quote": "double",
"dependencies": {
"PORT": { "Name": "PORT" }
}
}
]
}The JSON output includes variable dependency tracking (dependencies / dependents), annotation parsing, and file position information for each entry.
Render a template from a .env file model.
dottie template [flags] TEMPLATE_FILE
| Flag | Description | Default |
|---|---|---|
--interpolation / --no-interpolation |
Enable interpolation | true |
--with-disabled |
Include disabled assignments |
Example: generate docs from an env file
This is the same pattern used in the docker-pixelfed project to generate settings documentation from .env.docker:
- Template:
docs-customization/template/dot-env.template.tmpl - Source env:
.env.docker
You can see their template here: https://github.com/jippi/docker-pixelfed/blob/main/docs-customization/template/dot-env.template.tmpl#L37
And their source env file here: https://github.com/jippi/docker-pixelfed/blob/main/.env.docker
Sample template (dot-env.template.tmpl) excerpt:
{{ range .Groups }}
## {{ .String | title }}
{{ range .Assignments }}
### {{ .Name | title }} { data-toc-label="{{ .Name }}" }
{{ if .Annotation "dottie/validate" | first | default "" | contains "required" }}
<!-- md:flag required -->
{{ end }}
{{ if eq .Literal "" }}
<!-- md:default none -->
{{ else if eq .Literal .Interpolated }}
<!-- md:default `{{ .Interpolated | trim }}` -->
{{ else }}
<!-- md:default computed:`{{ .Literal | trim }}` -->
{{ end }}
{{ with .Documentation true }}{{ . | trim }}{{ end }}
{{ with .Annotation "dottie/validate" }}
**Validation rules:** `{{ . | first | trim }}`
{{ end }}
{{ end }}
{{ end }}
Run it with:
dottie template --file .env.docker docs-customization/template/dot-env.template.tmpl > docs/generated/env-settings.mdExample output (abbreviated):
## App
### App Name { data-toc-label="APP_NAME" }
<!-- md:flag required -->
<!-- md:default none -->
The name/title for your site
Validation rules: `required,ne=My Pixelfed Site`
### App Url { data-toc-label="APP_URL" }
<!-- md:default computed:`https://${APP_DOMAIN}` -->
This URL is used by the console to properly generate URLs.
Validation rules: `required,http_url`How it works:
- Dottie parses
.env.dockerinto a structured document (Groups,Assignments, comments, annotations). - The Go template can read metadata like
.Documentation,.Annotation "dottie/validate",.Literal, and.Interpolated. - Interpolation is enabled by default, so computed defaults can be rendered from variable references.
Generate shell completion scripts so dottie subcommands and flags can be tab-completed in your terminal.
dottie completion [bash|zsh|fish|powershell]
Examples
Temporary (current shell session):
# bash
source <(dottie completion bash)
# zsh
source <(dottie completion zsh)Persisted setup (example for zsh):
dottie completion zsh > ~/.zsh/completions/_dottieThen ensure your shell's completion path includes that directory.
Annotations are comment lines with this format:
# @<annotation-key> <annotation-value>
In Dottie, annotations are parsed from comments and attached to the following assignment (or treated as document-level config where relevant).
| Annotation | Scope | Value | Used By | Purpose |
|---|---|---|---|---|
@dottie/validate |
Assignment | Validation rule string (e.g. required,number) |
dottie validate, dottie set, dottie exec, dottie update (validation during updates) |
Validates assignment values using validator rules |
@dottie/source |
Document-level config | Source URL/path | dottie update |
Declares default upstream source when --source is not provided |
@dottie/exec |
Assignment | Shell command | dottie exec |
Runs command and writes command output back into assignment value |
@dottie/hidden |
Assignment | Optional/ignored | Shell completion | Hides assignment from interactive key completion suggestions |
Declares the default source file/URL used by dottie update and dottie exec when --source is not provided.
Syntax:
# @dottie/source <url-or-file-path>Example:
# @dottie/source https://example.com/.env.template
APP_NAME="my-app"Explainer:
- Use this when your project has a canonical upstream template.
--sourcealways overrides the annotation for that command run.
Defines the command used by dottie exec to compute/update the value for the annotated key.
Syntax:
# @dottie/exec <command>
KEY=""Example:
# @dottie/exec ./scripts/git-sha.sh
APP_VERSION=""Explainer:
- Command output is used as the assignment value.
- Keep one
@dottie/execannotation per assignment.
@dottie/hidden Reference
Marks an assignment as hidden from shell completion suggestions.
Syntax:
# @dottie/hidden
KEY="value"Example:
# @dottie/hidden
INTERNAL_DEBUG_TOKEN="secret"Explainer:
- Helps reduce noise for internal-only keys.
- The key still exists and behaves normally in file parsing/commands.
@dottie/validate attaches validation rules to the next assignment.
Syntax:
# @dottie/validate <rule>[,<rule>...]
KEY=valueRules are evaluated by go-playground/validator/v10 via Dottie (validator.ValidateMap), so the annotation value is passed through as validator tags.
Tag syntax (from validator/v10):
- AND: separate rules with commas:
required,email - OR: separate alternatives with pipe:
rgb|rgba - Rule parameter: use
=:min=3,oneof=dev staging prod - Escaping separators in parameters:
- Use
0x2Cfor literal comma in a parameter value - Use
0x7Cfor literal pipe in a parameter value
- Use
Validator tags Dottie can use well (for scalar .env values):
| Tag | What it checks | Dottie annotation syntax example |
|---|---|---|
required |
Value must be set/non-empty | # @dottie/validate required |
omitempty |
Skip later checks when value is empty | # @dottie/validate omitempty,email |
required_if |
Required when another key equals a value | # @dottie/validate required_if=QUEUE_DRIVER sqs |
required_unless |
Required unless another key equals a value | # @dottie/validate required_unless=APP_ENV local |
required_with |
Required if any listed keys are present | # @dottie/validate required_with=MAIL_DRIVER |
required_with_all |
Required if all listed keys are present | # @dottie/validate required_with_all=DB_HOST DB_PORT |
required_without |
Required if any listed keys are missing | # @dottie/validate required_without=REDIS_URL |
required_without_all |
Required if all listed keys are missing | # @dottie/validate required_without_all=REDIS_URL MEMCACHED_URL |
excluded_if |
Must be empty when condition matches | # @dottie/validate excluded_if=APP_ENV production |
excluded_unless |
Must be empty unless condition matches | # @dottie/validate excluded_unless=APP_ENV local |
| Tag | What it checks | Dottie annotation syntax example |
|---|---|---|
len |
Exact length / exact numeric size | # @dottie/validate len=32 |
min |
Minimum length/value | # @dottie/validate min=8 |
max |
Maximum length/value | # @dottie/validate max=255 |
eq |
Exactly equals parameter | # @dottie/validate eq=enabled |
ne |
Must not equal parameter | # @dottie/validate ne=changeme |
gt |
Greater than parameter | # @dottie/validate gt=0 |
gte |
Greater than or equal | # @dottie/validate gte=1 |
lt |
Less than parameter | # @dottie/validate lt=65536 |
lte |
Less than or equal | # @dottie/validate lte=65535 |
oneof |
Value must be one of allowed options | # @dottie/validate oneof=dev staging production |
oneofci |
Case-insensitive oneof |
# @dottie/validate oneofci=debug info warn error |
| Tag | What it checks | Dottie annotation syntax example |
|---|---|---|
number |
Numeric format | # @dottie/validate number |
numeric |
Basic numeric string | # @dottie/validate numeric |
boolean |
Bool-parsable value | # @dottie/validate boolean |
alpha |
Letters only | # @dottie/validate alpha |
alphanum |
Letters/numbers only | # @dottie/validate alphanum |
ascii |
ASCII characters only | # @dottie/validate ascii |
lowercase |
Lowercase only | # @dottie/validate lowercase |
uppercase |
Uppercase only | # @dottie/validate uppercase |
contains |
Must contain substring | # @dottie/validate contains=:// |
excludes |
Must not contain substring | # @dottie/validate excludes=@ |
startswith |
Must start with value | # @dottie/validate startswith=https:// |
endswith |
Must end with value | # @dottie/validate endswith=.example.com |
| Tag | What it checks | Dottie annotation syntax example |
|---|---|---|
email |
Valid e-mail format | # @dottie/validate email |
url |
Valid URL | # @dottie/validate url |
uri |
Valid URI | # @dottie/validate uri |
http_url |
Valid HTTP/HTTPS URL | # @dottie/validate http_url |
https_url |
Valid HTTPS URL | # @dottie/validate https_url |
hostname |
Valid hostname | # @dottie/validate hostname |
hostname_rfc1123 |
RFC1123 hostname | # @dottie/validate hostname_rfc1123 |
fqdn |
Fully qualified domain name | # @dottie/validate fqdn |
hostname_port |
Hostname + port | # @dottie/validate hostname_port |
ip |
Valid IP address | # @dottie/validate ip |
ipv4 |
Valid IPv4 address | # @dottie/validate ipv4 |
ipv6 |
Valid IPv6 address | # @dottie/validate ipv6 |
cidr |
Valid CIDR block | # @dottie/validate cidr |
mac |
Valid MAC address | # @dottie/validate mac |
dir |
Existing directory path | # @dottie/validate dir |
dirpath |
Directory path syntax | # @dottie/validate dirpath |
file |
Existing file path | # @dottie/validate file |
filepath |
File path syntax | # @dottie/validate filepath |
| Tag | What it checks | Dottie annotation syntax example |
|---|---|---|
uuid |
UUID format | # @dottie/validate uuid |
ulid |
ULID format | # @dottie/validate ulid |
semver |
Semantic version | # @dottie/validate semver |
cron |
Cron expression | # @dottie/validate cron |
json |
JSON-encoded string | # @dottie/validate json |
jwt |
JWT format | # @dottie/validate jwt |
hexcolor |
Hex color string | # @dottie/validate hexcolor |
rgb |
RGB color string | # @dottie/validate rgb |
rgba |
RGBA color string | # @dottie/validate rgba |
base64 |
Base64 string | # @dottie/validate base64 |
timezone |
Time zone identifier | # @dottie/validate timezone |
Examples:
# @dottie/validate required,oneof=dev staging production
APP_ENV=dev
# @dottie/validate required_if=QUEUE_DRIVER sqs
SQS_QUEUE=
# @dottie/validate required,dir
STORAGE_PATH=/var/lib/myapp
# @dottie/validate omitempty,oneof=debug info warn error
LOG_LEVEL=info
# @dottie/validate required,email|fqdn
CONTACT=ops@example.comNotes:
- Multiple rules are comma-separated.
- Alternative rules can be expressed with
|(OR logic). dottie validate --ignore-rule <tag>can suppress a specific failing tag (for exampledir).- Invalid rule names (for example
invalid-rule) are treated as validation configuration errors. - Dottie delegates rule behavior to validator/v10; exact availability follows the validator version in Dottie.
portis currently not safe for.envstring values with upstream validator/v10 in Dottie (it triggers a validation configuration error).- Validator reference: https://pkg.go.dev/github.com/go-playground/validator/v10
- Use
required_iffor value-based conditions- Example:
required_if=QUEUE_DRIVER sqsmeans “required only whenQUEUE_DRIVERis exactlysqs”.
- Example:
- Use
required_withfor presence-based conditions- Example:
required_with=MAIL_DRIVERmeans “required whenMAIL_DRIVERis set to any non-empty value”.
- Example:
- Cross-field rules depend on key names
- Tags like
required_ifandrequired_withreference other assignment keys by name; typos in key names make rules behave unexpectedly.
- Tags like
omitemptyshort-circuits the rest of the tag chainomitempty,emailpasses on empty values, but validates as email when a value is provided.
- OR (
|) only applies inside the same tag expressionemail|fqdnmeans either format is accepted; combine with commas for additional required checks (e.g.required,email|fqdn).
Decision table:
| If you need... | Use | Example |
|---|---|---|
| Required only when another key has a specific value | required_if |
required_if=QUEUE_DRIVER sqs |
| Required when another key is present/non-empty | required_with |
required_with=MAIL_DRIVER |
| Required when any of several keys are present | required_with with multiple fields |
required_with=HOST PORT |
| Required when another key is missing/empty | required_without |
required_without=REDIS_URL |
| Required when all listed keys are missing/empty | required_without_all |
required_without_all=REDIS_URL MEMCACHED_URL |
| Optional, but must match format when set | omitempty,<rule> |
omitempty,email |
| Accept one of two formats | ` | ` |
# @dottie/source https://example.com/.env.template
# @dottie/validate required,number
PORT=3306
# @dottie/exec ./scripts/resolve-version.sh
APP_VERSION=""
# @dottie/hidden
INTERNAL_DEBUG_TOKEN="secret"@dottie/validatesupports validator tags (for example:required,number,email,boolean,oneof,dir,file,fqdn,hostname,http_url,ne, and more).@dottie/execexpects exactly one exec annotation per assignment.- Any non-
dottie/*annotation is still parsed and preserved, but has no built-in command behavior unless consumed by your own tooling/templates.
To compile the module yourself, you can set up this repository for development.
You will need:
- Clone the repository:
git clone https://github.com/jippi/dottie.git
cd dottie- Build the module:
go build- Build the docker container:
docker build --file Dockerfile.release --tag ghcr.io/jippi/dottie:v0.15.1 .