Misconfigured environment variables are a leading cause of "works on my machine" failures and broken deployments. This script validates a .env file against a small JSON schema that declares which variables are required, their expected types (int, bool, url, or string), an optional default, and a minimum length. It parses the .env file safely, ignoring comments and blank lines, stripping surrounding quotes, and warning about malformed lines. Each rule is then enforced: missing required keys, wrong types, and values shorter than a minimum length all produce clear, line-itemized error messages. Variables that are present but not described in the schema generate a gentle note, helping you spot stray or deprecated settings. The script exits with a non-zero status when validation fails, so you can wire it straight into a CI pipeline or a container entrypoint as a pre-flight gate. It uses only the standard library, so there is nothing to install.
Validate a .env File Against a Schema
Check that a .env file contains all required variables with the correct types before your application starts.
16 views
Share
Script
Download .pypython
#!/usr/bin/env python3
"""Validate a .env file against a JSON schema of expected variables.
Schema example (schema.json):
{
"DATABASE_URL": {"required": true, "type": "url"},
"PORT": {"required": true, "type": "int"},
"DEBUG": {"required": false, "type": "bool", "default": "false"},
"API_KEY": {"required": true, "type": "string", "min_length": 10}
}
Pure standard library; no external dependencies.
"""
import argparse
import json
import re
import sys
URL_RE = re.compile(r"^https?://|^[a-z][a-z0-9+.-]*://", re.IGNORECASE)
BOOL_VALUES = {"true", "false", "1", "0", "yes", "no"}
def parse_env(path):
"""Parse a .env file into a dict, ignoring blanks and comments."""
values = {}
with open(path, encoding="utf-8") as f:
for lineno, raw in enumerate(f, start=1):
line = raw.strip()
if not line or line.startswith("#"):
continue
if "=" not in line:
print(f" warning: line {lineno} has no '=' -> ignored")
continue
key, _, val = line.partition("=")
key = key.strip()
val = val.strip().strip('"').strip("'")
values[key] = val
return values
def check_type(value, expected):
"""Return an error string if value does not match expected type."""
if expected == "int":
if not re.fullmatch(r"-?\d+", value):
return "expected an integer"
elif expected == "bool":
if value.lower() not in BOOL_VALUES:
return "expected a boolean (true/false)"
elif expected == "url":
if not URL_RE.match(value):
return "expected a URL"
elif expected == "string":
return None
return None
def validate(env, schema):
"""Return a list of error messages (empty list means valid)."""
errors = []
for name, rules in schema.items():
present = name in env and env[name] != ""
if not present:
if rules.get("required", False):
errors.append(f"{name}: missing required variable")
continue
value = env[name]
type_err = check_type(value, rules.get("type", "string"))
if type_err:
errors.append(f"{name}: {type_err} (got '{value}')")
min_len = rules.get("min_length")
if min_len is not None and len(value) < min_len:
errors.append(f"{name}: shorter than min_length {min_len}")
# Warn about unknown variables not described in the schema.
for name in env:
if name not in schema:
print(f" note: '{name}' is set but not in schema")
return errors
def main():
parser = argparse.ArgumentParser(description="Validate a .env file.")
parser.add_argument("env_file", help="Path to the .env file.")
parser.add_argument("schema_file", help="Path to the JSON schema file.")
args = parser.parse_args()
with open(args.schema_file, encoding="utf-8") as f:
schema = json.load(f)
env = parse_env(args.env_file)
errors = validate(env, schema)
if errors:
print(f"\nVALIDATION FAILED ({len(errors)} error(s)):")
for err in errors:
print(f" - {err}")
sys.exit(1)
print("\nVALIDATION PASSED: .env matches the schema.")
if __name__ == "__main__":
main()How to run
Review the script first, then download or copy it and run it in your environment.
You might also like
pythoncross-platformIntermediate
Cron Expression Next-Run Calculator
Given a cron expression, print the next several times it will fire along with the countdown to each.
bashlinuxIntermediate
CPU Load Average Alert
Warns by email when the one-minute load average per CPU core exceeds a configurable ratio.
bashlinuxAdvanced
Clean up old AMIs and snapshots
Deregister your old AMIs past a retention window and delete their backing EBS snapshots.