.env file format
A deploy writes the .env file of an environment in a fixed layout. This page describes that layout, how values are quoted, and the rules envite follows when it reads a file back, to compare it before a deploy or to import it.
Layout
Section titled “Layout”The file is UTF-8 text with LF line endings, ending with exactly one line feed. It is a header followed by one block per section, blocks separated by exactly one blank line. Every rule is # followed by 69 hyphens.
# ---------------------------------------------------------------------# Envite · production# Generated by envite: https://github.com/Kevinsillo/envite# ---------------------------------------------------------------------# Author: Alice Example# Organization: KW Force# License: MIT# URL: https://example.com# Date: 2026-10-01# Last change: 2026-10-03 18:42 by alice# Deployed: 2026-10-03 20:15 by alice# Description: First line# second line# ---------------------------------------------------------------------
# ---------------------------------------------------------------------# General# Shared settings# ---------------------------------------------------------------------APP_ENV=production# Primary hostDB_HOST=db.local# DEBUG=true
# ---------------------------------------------------------------------# database# ---------------------------------------------------------------------DB_PASS="p a\$s word"Header
Section titled “Header”- A rule, the title
<project> · <environment>, the lineGenerated by envite: https://github.com/Kevinsillo/envite, and another rule. - The fields the project has, in this order:
Author,Organization,License,URL,Date(YYYY-MM-DD). A field the project does not have is left out. The unix group is never written. Last change: <YYYY-MM-DD HH:MM> by <member>— the last change to the environment, its sections or its variables.Deployed: <YYYY-MM-DD HH:MM> by <member>— the deploy that wrote the file, padded to line up with the line above.Description: <first line>, when the project has one, then# <line>for every further line.- A closing rule, with no blank line before it.
Times are written to the minute in the time zone of the member who deploys; the deploy time is the moment the deploy was previewed. A member who is no longer in the vault shows as unknown.
Last change is the latest update of any variable of the environment, or the latest history entry (creation, update or deletion; never a deploy or an import) of the environment, its sections, its variables, or variables deleted from its sections. Without any, it is the creation of the environment, by unknown. Deleting or reordering sections does not move it; renaming the environment or editing its deploy settings does.
Sections
Section titled “Sections”A section is written only when at least one of its variables is enabled or commented. Its block is a rule, # <title> (General for the default section), one # <line> per line of its comment (a blank comment line reads #), the same rule again, then its variables. Sections follow the order of the environment, General first; variables follow the order of their section.
Variables
Section titled “Variables”- The comment of a variable comes right before it, one
# <line>per line. - An enabled variable is
KEY=value. - A commented variable is the same entry with
#before every physical line, so it stays a comment even when its value spans several lines:# DEBUG=true. - A disabled variable is never written, nor is its comment.
Quoting
Section titled “Quoting”A value is written bare when it is not empty and every character is an ASCII letter or digit or one of _-./:@%+,=. Anything else is wrapped in double quotes, where only \, ", $ and the backtick are escaped with a backslash. Line feeds, carriage returns and tabs are written as the real characters, never as \n, \r or \t, so a value of several lines spans several physical lines. An empty value is written KEY="".
This quoting is understood by dotenv libraries, Docker Compose and a shell source.
What envite reads from a file
Section titled “What envite reads from a file”Before a deploy envite reads the file at the target and compares it with the file about to be deployed; an import reads a file the same way. Reading never fails: whatever is not an entry is ignored, without being listed or counted.
KEY=valueandexport KEY=valueare enabled entries. Spaces and tabs are allowed before the line, around the key and around=. A key not in uppercase is uppercased; an invalid key discards the line.#, optional spaces and a valid entry is a commented entry. Any other comment, the header and section titles included, is ignored. A descriptive comment that happens to be a valid entry (# HOST=10.0.0.1) is read as a commented entry.- Double-quoted values unescape
\\,\",\$,\`,\n,\rand\t; any other backslash sequence is kept as written. Single-quoted values are literal. Both may span several lines. Whatever follows the closing quote on its line is ignored. A quote never closed discards the line that opens it. - Unquoted values have no escapes, end at whitespace followed by
#or at the end of the line, and are trimmed. - When a key appears several times, the last occurrence wins, at the position of the first one.
Comparing files
Section titled “Comparing files”Files are compared by key: each key is added, removed, unchanged or changed (its value, its state or both). A file whose keys are all unchanged but whose text differs — comments, quoting, the order of the keys, a field of the header — is a formatting-only change, and is still written.
The Deployed: line is left out of the comparison, since it changes on every deploy. When it is the only difference, the deploy writes nothing and the file keeps the time of the last deploy that really changed it. The Last change: line is compared as any other line.
Changes made outside envite are detected with a fingerprint of the exact bytes of the file at the target: the history keeps the fingerprint of what each deploy wrote, and a file that no longer matches the last one needs an explicit confirmation before it is replaced.