Skip to content

Environment Variables Management Guide

๐ŸŽฏ TL;DR - How It Works

You only need ONE .env file for local development.

Railway automatically provides environment variables based on which environment is deployed. You don't need separate .env files for prod/dev on Railway.


๐Ÿ“ File Structure

archety/
โ”œโ”€โ”€ .env                    # โœ… For LOCAL development only
โ”œโ”€โ”€ .env.example            # โœ… Template (committed to git)
โ”œโ”€โ”€ .gitignore              # โœ… Blocks .env from being committed
โ””โ”€โ”€ app/
    โ””โ”€โ”€ config.py           # โœ… Loads from Railway OR .env

Important: - .env = Only for local development (NEVER commit!) - .env.example = Template for other developers (safe to commit) - Railway = Provides variables automatically based on environment


๐Ÿ”„ How Environment Variables Work

1. Local Development (Your Machine)

Uses: .env file

# When you run locally:
./run.sh
# or
uvicorn app.main:app --reload

What happens: - app/config.py reads .env file - You get local development variables - ENVIRONMENT=development (from your .env) - DATABASE_URL=postgresql://localhost... (local database)

2. Railway Development Environment

Uses: Railway dashboard variables

# When you push to dev branch:
git push origin dev

What happens: - GitHub Actions deploys to Railway dev environment - Railway injects variables from development environment - app/config.py reads from environment (NOT .env) - ENVIRONMENT=development (from Railway) - DATABASE_URL= (from Railway) - BASE_URL= (often a Railway URL or a dev custom domain)

3. Railway Production Environment

Uses: Railway dashboard variables

# When you trigger manual production deploy:
# (via GitHub Actions workflow)

What happens: - GitHub Actions deploys to Railway production environment - Railway injects variables from production environment - ENVIRONMENT=production (from Railway) - DATABASE_URL= (from Railway) - BASE_URL= (canonical is typically https://api.ikiro.ai)


๐Ÿ”ง Configuration Code (How It Works)

app/config.py automatically handles this:

class Settings(BaseSettings):
    model_config = ConfigDict(
        # Only load .env in development, Railway provides env vars directly
        env_file=".env" if os.path.exists(".env") else None,
        env_file_encoding="utf-8",
        case_sensitive=False,
        extra="ignore",
    )

Priority order: 1. Railway environment variables (if on Railway) 2. .env file (if running locally and file exists) 3. Defaults in config.py


๐Ÿ“ Example .env (Local Development)

This is an example .env for local development. Do not paste real keys into documentation or commit them to git.

Use .env.example as the canonical template.

# Local development settings
ENVIRONMENT=development
LOG_LEVEL=INFO
BASE_URL=http://localhost:8000

# Database (local)
DATABASE_URL=<your_postgres_connection_string>

# API Keys (shared across environments usually)
SUPERMEMORY_API_KEY=<supermemory_api_key>  # Primary memory service (optional if using mem0)
MEM0_API_KEY=<mem0_api_key>  # Legacy fallback (optional if using supermemory)
OPENAI_API_KEY=<openai_api_key>
PERPLEXITY_API_KEY=<perplexity_api_key>

# OAuth (for local testing)
GOOGLE_CLIENT_ID=...
GOOGLE_CLIENT_SECRET=...
OAUTH_REDIRECT_URI=http://localhost:8000/auth/callback

# Security (local development keys)
SECRET_KEY=<generate_with_openssl_rand_hex_32>
FERNET_KEY=<generate_with_fernet>
EDGE_SECRET=<generate_with_openssl_rand_hex_32>

๐Ÿšซ What NOT to Do

โŒ Don't create .env.prod or .env.dev

Why not? - Railway handles prod/dev separation automatically - Risk of accidentally committing production secrets - Unnecessary complexity - Railway injects the correct variables based on environment

โŒ Don't commit .env to git

Already protected by .gitignore:

# Environment variables
.env
.env.local
.env.production
.env.development


โœ… What TO Do

1. Keep ONE .env for Local Development

Your current .env file is perfect for local dev:

ENVIRONMENT=development
LOG_LEVEL=INFO
BASE_URL=http://localhost:8000
DATABASE_URL=<your_postgres_connection_string>
# ... other local variables

2. Use Railway Dashboard for Prod/Dev Variables

Set variables via Railway CLI or dashboard:

# Production environment
railway link --environment production --service <your-prod-service>
railway variables set ENVIRONMENT=production
railway variables set BASE_URL=https://api.ikiro.ai

# Development environment
railway link --environment development --service <your-dev-service>
railway variables set ENVIRONMENT=development
railway variables set BASE_URL=<dev_base_url>

3. Use .env.example for Team Sharing

Already exists - keep it updated:

# .env.example (committed to git, no secrets)
ENVIRONMENT=development
LOG_LEVEL=INFO
BASE_URL=http://localhost:8000

# Memory Service Configuration
SUPERMEMORY_API_KEY=your_supermemory_api_key  # Primary (get from supermemory.ai)
MEM0_API_KEY=your_mem0_api_key  # Legacy fallback (optional)

# LLM Providers
OPENAI_API_KEY=your_openai_api_key
PERPLEXITY_API_KEY=your_perplexity_api_key

# OAuth
GOOGLE_CLIENT_ID=your_google_client_id
GOOGLE_CLIENT_SECRET=your_google_client_secret
OAUTH_REDIRECT_URI=http://localhost:8000/auth/callback

# Security (generate your own!)
SECRET_KEY=generate_with_openssl_rand_hex_32
FERNET_KEY=generate_with_fernet
EDGE_SECRET=generate_with_openssl_rand_hex_32

๐Ÿ”„ Typical Workflow

Local Development

# 1. Copy .env.example to .env (first time only)
cp .env.example .env

# 2. Fill in your API keys in .env
# Edit .env with your actual keys

# 3. Run locally
./run.sh

# The app reads from .env automatically

Deploy to Development

# 1. Make changes on dev branch
git checkout dev
# ... make changes ...

# 2. Commit and push
git add .
git commit -m "feat: new feature"
git push origin dev

# 3. GitHub Actions auto-deploys to Railway dev
# Railway injects development environment variables
# No .env file needed - Railway provides everything!

Deploy to Production

# 1. Merge dev to master
git checkout master
git merge dev
git push origin master

# 2. Manually trigger production deploy
# Go to: GitHub Actions โ†’ Deploy to Production
# Type "DEPLOY TO PRODUCTION" to confirm

# 3. GitHub Actions deploys to Railway prod
# Railway injects production environment variables
# No .env file needed!

๐Ÿงช Testing Different Environments Locally

Scenario: You want to test against dev or prod database locally

Option 1: Temporarily change .env

# In .env, temporarily change:
DATABASE_URL=<copy from Railway dev or prod>
BASE_URL=<dev_base_url>

# Run locally
./run.sh

# REMEMBER to change back when done!

Option 2: Use environment variables directly

# Override specific variables for one run
ENVIRONMENT=development \
BASE_URL=<dev_base_url> \
DATABASE_URL=<railway dev database> \
python -m uvicorn app.main:app --reload

Option 3: Use Railway run (connects to Railway environment)

# Run locally but with Railway dev variables
railway link --environment development --service <your-dev-service>
railway run python -m uvicorn app.main:app --reload

# Or prod
railway link --environment production --service <your-prod-service>
railway run python -m uvicorn app.main:app --reload


๐Ÿ” Security Best Practices

Local .env File

โœ… Do: - Keep .env for local development - Use weak/test keys in local .env (not production keys!) - Never commit .env - Share .env.example (without secrets)

โŒ Don't: - Put production secrets in local .env - Commit .env to git - Share .env file directly (use .env.example)

Railway Variables

โœ… Do: - Use Railway dashboard or CLI to set variables - Use different SECRET_KEY/FERNET_KEY/EDGE_SECRET per environment - Review variables before deploying

โŒ Don't: - Hardcode secrets in code - Share production secrets in Slack/email - Use same security keys across environments


๐Ÿ“Š Variable Comparison

Variable Local (.env) Railway Dev Railway Prod
ENVIRONMENT development development production
BASE_URL http://localhost:8000 https://api.ikiro.ai
DATABASE_URL localhost postgres Railway dev postgres Railway prod postgres
SECRET_KEY Local test key Unique dev key Unique prod key
API Keys Your personal keys Shared/separate Production keys

๐Ÿ†˜ Troubleshooting

"Config loading wrong values"

Check which config is loading:

# Add to app/main.py temporarily
from app.config import settings
logger.info(f"ENVIRONMENT: {settings.environment}")
logger.info(f"BASE_URL: {settings.base_url}")
logger.info(f"Loading from .env: {os.path.exists('.env')}")

"Railway using .env file"

Railway should NOT use .env: - Railway doesn't have access to your .env file - Railway injects variables directly - If it's using .env, you might be running locally

"Variables not updating"

After changing Railway variables: 1. Trigger a new deploy (Railway doesn't auto-reload) 2. Check Railway logs to see what values are loaded 3. Verify you're in the correct environment


โœ… Summary

How to manage environment variables:

  1. Local development: Use .env file โœ…
  2. Railway dev: Set variables in Railway dashboard (development environment) โœ…
  3. Railway prod: Set variables in Railway dashboard (production environment) โœ…
  4. Team sharing: Use .env.example (committed to git) โœ…

You do NOT need: - โŒ .env.prod file - โŒ .env.dev file - โŒ Multiple .env files

Railway handles everything automatically based on which environment is deployed!


๐ŸŽฏ Quick Reference Commands

# View local config
cat .env

# View Railway dev config
railway link --environment development --service <your-dev-service>
railway variables

# View Railway prod config
railway link --environment production --service <your-prod-service>
railway variables

# Set Railway dev variable
railway link --environment development --service <your-dev-service>
railway variables set KEY=value

# Set Railway prod variable
railway link --environment production --service <your-prod-service>
railway variables set KEY=value

# Run locally with .env
./run.sh

# Run locally with Railway dev variables
railway link --environment development --service <your-dev-service>
railway run ./run.sh

๐Ÿ“ง Email Configuration (Resend)

Overview

Archety uses Resend for transactional emails (welcome, billing notifications, account alerts). The email service is optional - if not configured, emails are logged but not sent.

Environment Variables

Variable Description Example
EMAIL_API_KEY Resend API key (required for sending) re_XXXXX...
EMAIL_PROVIDER Email provider name resend
EMAIL_FROM_ADDRESS Sender address with display name Sage <sage@archety.ai>
EMAIL_REPLY_TO Reply-to address support@archety.ai
EMAIL_ENABLED Master toggle true or false

Setup

1. Get API Key: - Sign up at https://resend.com - Create an API key in the dashboard - Verify your sending domain (sage@archety.ai)

2. Configure Environment Variable:

# Local development (.env)
EMAIL_API_KEY=re_test_...
EMAIL_ENABLED=true

# Railway Development
railway variables set EMAIL_API_KEY=re_live_...
railway variables set EMAIL_PROVIDER=resend
railway variables set EMAIL_FROM_ADDRESS="Sage <sage@archety.ai>"
railway variables set EMAIL_ENABLED=true

# Railway Production (same keys or separate)
railway variables set EMAIL_API_KEY=re_live_...

Fallback Behavior

The system works WITHOUT email configured: - If EMAIL_API_KEY is not set โ†’ emails are logged only - If EMAIL_ENABLED=false โ†’ emails are disabled - Email failures never block the main operation

Testing

# Test email locally
python -c "
from app.email.service import get_email_service
svc = get_email_service()
print(f'Available: {svc.is_available()}')
"

Documentation

For detailed email system guide, see: docs/implementation/EMAIL_NOTIFICATION_SYSTEM.md


๐Ÿšฉ LaunchDarkly Feature Flags

Overview

LaunchDarkly provides runtime configuration and feature flags without requiring deployments. The integration is optional - if not configured, the system uses default values.

Setup

1. Get SDK Key: - Log into LaunchDarkly dashboard - Navigate to: Account Settings โ†’ Projects โ†’ archety - Copy SDK key for your environment

2. Configure Environment Variable:

# Local development (.env)
LAUNCHDARKLY_SDK_KEY=sdk-your-local-key

# Railway Development
railway variables set LAUNCHDARKLY_SDK_KEY=sdk-dev-key

# Railway Production
railway variables set LAUNCHDARKLY_SDK_KEY=sdk-prod-key

3. Verify:

# Check feature flags status
curl http://localhost:8000/admin/feature-flags/status

# Expected response:
{
  "initialized": true,
  "is_connected": true,
  "circuit_breaker_open": false
}

Fallback Behavior (Important!)

The system works WITHOUT LaunchDarkly: - If LAUNCHDARKLY_SDK_KEY is not set โ†’ uses default values - If LaunchDarkly is unavailable โ†’ automatic fallback to defaults - Circuit breaker protects against failures (falls back after 3 errors)

This ensures the application always runs, even if LaunchDarkly is down.

Common Use Cases

  1. Token Limit Control:
  2. Adjust LLM token limits without deployment
  3. Emergency cost reduction via llm.force_basic_mode

  4. Feature Rollouts:

  5. Gradual rollout of new features (0% โ†’ 10% โ†’ 50% โ†’ 100%)
  6. Instant rollback if issues detected

  7. Cache Configuration:

  8. Tune cache TTLs based on load
  9. Enable/disable caching dynamically

Monitoring

# Check if LaunchDarkly is connected
curl http://localhost:8000/admin/feature-flags/status

# List all available flags
curl http://localhost:8000/admin/feature-flags/list

Documentation

For detailed operations guide, see: docs/operations/feature_flags.md