5 · Wire .env templates
Objective — replace the vendor’s single .env with a three-environment template set (local / staging / production), preserving the original first, and generate a unique APP_KEY for local.
Steps at a glance:
- Back up the vendor env — Preserve the originals in the gitignored vault — your record of what the author expected.
- Lay down per-environment templates — Create one template per environment in the vault. Keep real secrets
out of git — only
.env.exampleis ever tracked. - Activate local & generate the key — copy the local env into place and generate APP_KEY, so the app boots locally with secrets kept out of git.
- Per-environment values (reference) — The same keys take different values per environment. The ones that matter most:.
- Final verification — Run after all templates exist and local is active.
Background
Section titled “Background”The vendor ships a .env (or .env.example). You’re about to replace it with one template per environment row in Zaj-PROJECT.md — but first preserve the original, because it often documents required keys you’d otherwise miss.
flowchart LR V["vendor .env /<br/>.env.example"] -->|back up| Vault["project vault<br/>(gitignored)"] Vault --> T["lay down<br/>.env.local / .staging / .production"] T --> A["cp .env.local .env"] A --> K["php artisan key:generate"]1. Back up the vendor env
Section titled “1. Back up the vendor env”Preserve the originals in the gitignored vault — your record of what the author expected.
-
Copy the vendor env into the vault.
Terminal window mkdir -p Admin-Local/1-Project/2-Vault[ -f .env ] && cp .env Admin-Local/1-Project/2-Vault/.env.vendor-originalcp .env.example Admin-Local/1-Project/2-Vault/.env.vendor-example# Expected: vendor .env (if present) and .env.example copied into the vault- ✅ The vendor’s original env files are preserved in
Admin-Local/1-Project/2-Vault/.
- ✅ The vendor’s original env files are preserved in
2. Lay down per-environment templates
Section titled “2. Lay down per-environment templates”Create one template per environment in the vault. Keep real secrets out of git — only .env.example is ever tracked.
-
Create the common templates from
.env.example.Terminal window cp .env.example Admin-Local/1-Project/2-Vault/.env.localcp .env.example Admin-Local/1-Project/2-Vault/.env.stagingcp .env.example Admin-Local/1-Project/2-Vault/.env.production# For additional Zaj-PROJECT.md rows, copy one file per env key:# cp .env.example Admin-Local/1-Project/2-Vault/.env.qa# cp .env.example Admin-Local/1-Project/2-Vault/.env.client-demo# Expected: .env.<environment-key> files created in the vault- ✅
.env.local,.env.production, and one.env.<env-key>for each real non-production row exist in the vault.
- ✅
-
Customize each template with runnable
sedblocks — paste real secrets from the password manager; never commit filled vault files.Local (
Admin-Local/1-Project/2-Vault/.env.local):Terminal window sed -i '' \-e 's/^APP_NAME=.*/APP_NAME="[PROJECT]"/' \-e 's/^APP_ENV=.*/APP_ENV=local/' \-e 's/^APP_DEBUG=.*/APP_DEBUG=true/' \-e 's|^APP_URL=.*|APP_URL=https://[project].test|' \-e 's/^DB_DATABASE=.*/DB_DATABASE=[project]_local_db/' \-e 's/^DB_USERNAME=.*/DB_USERNAME=[project]_local_user/' \-e 's/^DB_PASSWORD=.*/DB_PASSWORD=<FROM_SEEDED_LOCAL_ITEM_OR_VAULT>/' \Admin-Local/1-Project/2-Vault/.env.local# Expected: grep APP_ENV=local and APP_DEBUG=true in .env.localNon-production target (example env key:
staging; use the real key and URL fromZaj-PROJECT.md):Terminal window ENV_KEY="staging"NON_PROD_URL="https://nonprod.example.com"sed -i '' \-e "s/^APP_NAME=.*/APP_NAME=\"[PROJECT] ${ENV_KEY}\"/" \-e "s/^APP_ENV=.*/APP_ENV=${ENV_KEY}/" \-e 's/^APP_DEBUG=.*/APP_DEBUG=false/' \-e "s|^APP_URL=.*|APP_URL=${NON_PROD_URL}|" \-e "s/^DB_DATABASE=.*/DB_DATABASE=[project]_${ENV_KEY}_db/" \-e "s/^DB_USERNAME=.*/DB_USERNAME=[project]_${ENV_KEY}_user/" \-e 's/^DB_PASSWORD=.*/DB_PASSWORD=<FROM_SEEDED_ENV_ITEM_OR_VAULT>/' \-e 's/^SESSION_SECURE_COOKIE=.*/SESSION_SECURE_COOKIE=true/' \"Admin-Local/1-Project/2-Vault/.env.${ENV_KEY}"# Expected: APP_DEBUG=false and SESSION_SECURE_COOKIE=trueProduction:
Terminal window sed -i '' \-e 's/^APP_NAME=.*/APP_NAME="[PROJECT]"/' \-e 's/^APP_ENV=.*/APP_ENV=production/' \-e 's/^APP_DEBUG=.*/APP_DEBUG=false/' \-e 's|^APP_URL=.*|APP_URL=https://[DOMAIN]|' \-e 's/^DB_DATABASE=.*/DB_DATABASE=[project]_production_db/' \-e 's/^DB_USERNAME=.*/DB_USERNAME=[project]_production_user/' \-e 's/^DB_PASSWORD=.*/DB_PASSWORD=<FROM_SEEDED_PRODUCTION_ITEM_OR_VAULT>/' \-e 's/^LOG_LEVEL=.*/LOG_LEVEL=error/' \-e 's/^SESSION_SECURE_COOKIE=.*/SESSION_SECURE_COOKIE=true/' \Admin-Local/1-Project/2-Vault/.env.production# Expected: APP_DEBUG=false, LOG_LEVEL=error, SESSION_SECURE_COOKIE=trueOn Linux, use
sed -iwithout the empty string after-i.- ✅ Each template carries this project’s values, with secrets pasted only into the gitignored variants.
3. Activate local & generate the key
Section titled “3. Activate local & generate the key”-
Activate the local env and generate its key.
Terminal window cp Admin-Local/1-Project/2-Vault/.env.local .envphp artisan key:generate# Expected: INFO Application key set successfully.- ✅
grep -qE '^APP_KEY="?base64:' .envreturns 0 — the key line matches whether or not the value is double-quoted (quoting secrets is safe and recommended).
- ✅
4. Per-environment values (reference)
Section titled “4. Per-environment values (reference)”The same keys take different values per environment. The ones that matter most:
| Variable | Local | Non-production target(s) | Production |
|---|---|---|---|
APP_ENV | local | env key from Zaj-PROJECT.md | production |
APP_DEBUG | true | false | false |
APP_URL | https://app.test | URL from Zaj-PROJECT.md | https://x.com |
APP_KEY | unique | unique | unique |
LOG_LEVEL | debug | info | error |
MAIL_MAILER | log | smtp | smtp |
SESSION_SECURE_COOKIE | false | true | true |
5. Final verification
Section titled “5. Final verification”Run after all templates exist and local is active.
echo "=== Env template verification ==="ls -1 Admin-Local/1-Project/2-Vault/.env.* 2>/dev/null# Quote-tolerant value greps below: an optional double-quote may sit right after# the `=` because quoting secret values is safe and recommended (and mandatory in# some project rules). Each check matches the value whether or not it is quoted.grep -qE '^APP_KEY=("")?$' .env.example && echo "✅ .env.example has empty APP_KEY" || echo "❌ scrub secrets from .env.example"git check-ignore -q .env && echo "✅ live .env ignored" || echo "❌ add .env to .gitignore"grep -qE '^APP_DEBUG="?false"?' Admin-Local/1-Project/2-Vault/.env.production && echo "✅ production debug off" || echo "❌ fix production APP_DEBUG"for env_file in Admin-Local/1-Project/2-Vault/.env.*; do case "$env_file" in *.local|*.vendor-*|*.vendor-original|*.vendor-example) continue ;; esac grep -qE '^APP_DEBUG="?false"?' "$env_file" && echo "✅ $env_file debug off" || echo "❌ fix $env_file APP_DEBUG" grep -qE '^SESSION_SECURE_COOKIE="?true"?' "$env_file" && echo "✅ $env_file secure cookies" || echo "⚠ set SESSION_SECURE_COOKIE in $env_file"donegrep -qE '^APP_KEY="?base64:' .env && echo "✅ local APP_KEY set" || echo "❌ run php artisan key:generate"# Expected: all ✅ lines; no real .env in git status- ✅ Vault holds the local, production, and non-production environment templates;
.env.examplehas empty secrets; live.envis gitignored; remote templates differ from local on debug and secure cookies.
Checklist
Section titled “Checklist”Do not mark this step done until every box below is checked.
- 🤖 Vendor env backed up —
.env/.env.examplecopied to the vault. - 🤖 Credential items exist —
Local,Staging, andProduction1Password items were seeded in Prerequisites and use the flat field set. - 🔀 Templates created —
.env.local,.env.production, and one.env.<env-key>for each real non-production row exist in the vault. - 🤖 Local active + keyed —
.envactive and a uniqueAPP_KEYgenerated (grep -qE '^APP_KEY="?base64:' .env— passes whether or not the value is quoted). - 👤 Off-local debug off — every non-local template sets
APP_DEBUG=false. - 🤖 No secrets staged —
git statusshows no real.envfiles staged.