Skip to main content

CLI Examples


title: CLI Examples audience: Developer difficulty: Beginner estimated_read_time: 6 min prerequisites:

  • CLI installed
  • Access to env.cat service related_pages:
  • ./envcat-get.md
  • ../recipes/onboard-new-dev.md

Real-world examples of using envcat in different scenarios.

Daily Development

Morning Workflow

Load secrets into your shell for the day:

cd ~/projects/my-app
eval "$(envcat get --api-base https://env.cat --bundle dev/api)"
npm run dev

Verify secrets loaded:

echo $DATABASE_URL
# postgres://localhost:5432/myapp

echo $API_KEY
# sk_test_abc123xyz

Multiple Projects

Switch between projects easily:

# Project 1
cd ~/projects/api
eval "$(envcat get --bundle dev/api)"
npm run dev

# Project 2 (new terminal)
cd ~/projects/frontend
eval "$(envcat get --bundle dev/frontend)"
npm run dev

Temporary Secrets

Load secrets for a single command:

(eval "$(envcat get --bundle dev/api)" && npm run seed)

Benefits:

  • Secrets only available during npm run seed
  • Parent shell unaffected
  • Automatic cleanup

Environment Management

Development → Staging → Production

Separate bundles for each environment:

# Development
eval "$(envcat get --bundle dev/api)"
npm run dev

# Staging (new terminal/tab)
eval "$(envcat get --bundle staging/api)"
npm start

# Production (new terminal/tab)
eval "$(envcat get --bundle prod/api)"
npm start

Feature Branch Environments

Separate bundles for feature branches:

# Main branch
git checkout main
eval "$(envcat get --bundle dev/api-main)"

# Feature branch
git checkout feature/new-auth
eval "$(envcat get --bundle dev/api-feature-auth)"

Docker & Containers

Docker Compose

Generate .env for Docker Compose:

# Get secrets
envcat get --bundle dev/api --file .env

# Start services
docker-compose up

# Cleanup
rm .env

docker-compose.yml:

version: '3.9'
services:
api:
build: .
env_file:
- .env
ports:
- "3000:3000"

Dockerfile Build Args

Pass secrets as build args:

# Get secrets to .env
envcat get --bundle ci/build --file .env

# Read into build args
source .env

# Build with args
docker build \
--build-arg NPM_TOKEN=$NPM_TOKEN \
--build-arg API_KEY=$API_KEY \
-t myapp:latest .

Docker Run

Run container with secrets:

# Get secrets
envcat get --bundle prod/api --file .env

# Run with env file
docker run --env-file .env myapp:latest

# Cleanup
rm .env

Freelance / Client Switching

Multiple Clients

Organize by client:

# Client A
cd ~/clients/acme-corp
eval "$(envcat get --bundle client-acme/api)"

# Client B
cd ~/clients/globex
eval "$(envcat get --bundle client-globex/api)"

Per-Project Bundles

Structure:

bundles:
- client-acme/api
- client-acme/frontend
- client-acme/database
- client-globex/api
- client-globex/backend

Usage:

cd ~/clients/acme-corp/api
eval "$(envcat get --bundle client-acme/api)"

cd ~/clients/acme-corp/frontend
eval "$(envcat get --bundle client-acme/frontend)"

Testing

Integration Tests

Load production-like secrets for testing:

# Get prod database (read-only credentials)
envcat get --bundle test/integration --keys DATABASE_URL,REDIS_URL --file .env.test

# Run tests
npm run test:integration

# Cleanup
rm .env.test

Specific Keys Only

Only request what you need:

# Only database for tests
eval "$(envcat get --bundle prod/api --keys DATABASE_URL)"

npm run test:db

CI/CD Testing

GitHub Actions:

name: Integration Tests

on: [pull_request]

jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3

- name: Install envcat
run: curl -fsSL https://env.cat/cli/install.sh | sh

- name: Get test secrets
run: |
envcat get --bundle ci/tests --file .env
source .env

- name: Run tests
run: npm run test:integration

Shell Integration

Bash Alias

Add to ~/.bashrc:

alias load-secrets='eval "$(envcat get --api-base https://env.cat --bundle dev/api)"'

Usage:

cd ~/projects/my-app
load-secrets
npm run dev

Fish Function

Add to ~/.config/fish/functions/secrets.fish:

function secrets
envcat get --api-base https://env.cat --bundle dev/api --format fish | source
end

Usage:

cd ~/projects/my-app
secrets
npm run dev

Direnv Integration

.envrc:

#!/bin/bash

# Load secrets when entering directory
eval "$(envcat get --bundle dev/api)"

Usage:

cd ~/projects/my-app
# direnv automatically loads secrets
direnv: loading ~/projects/my-app/.envrc
✓ Approved! Received 3 variable(s)
direnv: export +DATABASE_URL +API_KEY +PORT

Scripting

Conditional Loading

Load different bundles based on branch:

#!/bin/bash

BRANCH=$(git branch --show-current)

if [ "$BRANCH" = "main" ]; then
eval "$(envcat get --bundle prod/api)"
elif [ "$BRANCH" = "staging" ]; then
eval "$(envcat get --bundle staging/api)"
else
eval "$(envcat get --bundle dev/api)"
fi

npm start

Error Handling

Check if secrets loaded successfully:

#!/bin/bash

if envcat get --bundle dev/api --file .env; then
echo "✓ Secrets loaded"
source .env
npm start
else
echo "✗ Failed to load secrets (exit code: $?)"
exit 1
fi

Automated Deployment

Deployment script:

#!/bin/bash
set -e

# Get production secrets
echo "Loading production secrets..."
envcat get --bundle prod/api --file .env

# Build
echo "Building application..."
docker build -t myapp:latest .

# Deploy
echo "Deploying to production..."
docker run --env-file .env myapp:latest

# Cleanup
rm .env
echo "✓ Deployed successfully"

Advanced Patterns

Layered Secrets

Combine base + environment secrets:

#!/bin/bash

# Base secrets (shared across environments)
envcat get --bundle shared/base --file .env.base

# Environment-specific secrets
envcat get --bundle prod/api --file .env.prod

# Merge (prod overrides base)
cat .env.base .env.prod > .env

# Cleanup
rm .env.base .env.prod

# Use merged .env
source .env
npm start

Secret Rotation

Automated secret refresh:

#!/bin/bash

# Cron job runs every 6 hours
# 0 */6 * * * /home/user/scripts/refresh-secrets.sh

# Get latest secrets
envcat get --bundle prod/api --file /etc/myapp/.env

# Reload application
systemctl reload myapp

echo "$(date): Secrets refreshed" >> /var/log/myapp/secrets.log

Backup Before Update

Backup .env before overwriting:

#!/bin/bash

# Backup existing .env
if [ -f .env ]; then
cp .env .env.backup.$(date +%Y%m%d-%H%M%S)
fi

# Get new secrets
envcat get --bundle dev/api --file .env

echo "✓ Secrets updated (backup saved)"

Platform-Specific

Heroku Alternative

Use envcat instead of Heroku config vars:

# Get secrets
envcat get --bundle prod/heroku --file .env

# Deploy to Heroku with .env
heroku config:set $(cat .env | xargs)

# Cleanup
rm .env

AWS Lambda

Deploy Lambda with secrets:

# Get secrets
envcat get --bundle prod/lambda --file .env

# Convert to Lambda environment variables JSON
cat .env | jq -R 'split("=") | {(.[0]): .[1]}' | jq -s 'add' > env.json

# Deploy
aws lambda update-function-configuration \
--function-name my-function \
--environment "Variables=$(cat env.json)"

# Cleanup
rm .env env.json

Kubernetes Secrets

Create Kubernetes secret from envcat:

# Get secrets
envcat get --bundle prod/k8s --file .env

# Create Kubernetes secret
kubectl create secret generic app-secrets --from-env-file=.env

# Cleanup
rm .env

Deployment YAML:

apiVersion: v1
kind: Pod
metadata:
name: myapp
spec:
containers:
- name: app
image: myapp:latest
envFrom:
- secretRef:
name: app-secrets

Security Patterns

Minimal Exposure

Only request keys you need:

# Bad: Request entire bundle
eval "$(envcat get --bundle prod/api)"

# Good: Request specific keys
eval "$(envcat get --bundle prod/api --keys DATABASE_URL,API_KEY)"

Time-Limited Access

Load secrets only for specific task:

# Load secrets in subshell
(
eval "$(envcat get --bundle prod/api)"
npm run migrate
)

# Secrets no longer available
echo $DATABASE_URL
# (empty)

Audit Logging

Log secret access:

#!/bin/bash

# Log access
echo "$(date): $(whoami) loaded secrets for bundle: $1" >> ~/.envcat-audit.log

# Load secrets
eval "$(envcat get --bundle $1)"

Usage:

source load-secrets.sh dev/api

Git Safety

Never commit .env files:

# Add to .gitignore
echo ".env" >> .gitignore
echo ".env.*" >> .gitignore
echo "!.env.example" >> .gitignore

git add .gitignore
git commit -m "Add .env to gitignore"

Create .env.example template:

# Get secrets to .env
envcat get --bundle dev/api --file .env

# Create template (values masked)
sed 's/=.*/=/' .env > .env.example

# Commit template
git add .env.example
git commit -m "Add .env.example template"

Troubleshooting Examples

Debug Mode

See what's happening:

# Enable verbose output (future feature)
envcat get --bundle dev/api --verbose

# Or check exit code
envcat get --bundle dev/api --file .env
echo "Exit code: $?"

Dry Run

Preview without approving (future feature):

envcat get --bundle dev/api --dry-run
# Shows: Would request 5 keys from bundle 'dev/api'
# Keys: DATABASE_URL, REDIS_URL, API_KEY, PORT, DEBUG

Retry on Failure

Auto-retry on network errors:

#!/bin/bash

MAX_RETRIES=3
RETRY_COUNT=0

until envcat get --bundle dev/api --file .env; do
RETRY_COUNT=$((RETRY_COUNT + 1))

if [ $RETRY_COUNT -ge $MAX_RETRIES ]; then
echo "Failed after $MAX_RETRIES attempts"
exit 1
fi

echo "Retry $RETRY_COUNT/$MAX_RETRIES..."
sleep 5
done

echo "✓ Secrets loaded"

See Also