> ## Documentation Index
> Fetch the complete documentation index at: https://sonamu.cartanova.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# .env Setup

> Creating and managing environment variable files

Sonamu uses `.env` files to apply different settings for each environment. Sensitive information such as database connection details, API keys, and session secrets should be stored in `.env` files and referenced from `sonamu.config.ts`.

<Warning>
  Never commit `.env` files to Git! Make sure `.env` is included in your `.gitignore`.
</Warning>

## Quick Start

<Steps>
  <Step title="Copy .env.example" icon="copy">
    Copy `.env.example` from the project root to create a `.env` file.

    ```bash theme={null}
    cp .env.example .env
    ```
  </Step>

  <Step title="Set Environment Variables" icon="pen">
    Open the `.env` file and modify it with actual values.

    ```bash theme={null}
    # Example
    DB_HOST=localhost
    DB_PORT=5432
    DB_USER=postgres
    DB_PASSWORD=your-db-password
    ```
  </Step>

  <Step title="Reference in Config File" icon="code">
    Read environment variables using `process.env` in `sonamu.config.ts`.

    ```typescript theme={null}
    database: {
      defaultOptions: {
        connection: {
          host: process.env.DB_HOST || "0.0.0.0",
          password: process.env.DB_PASSWORD,
        },
      },
    }
    ```
  </Step>
</Steps>

## .env File Structure

The `.env` file is written in `KEY=VALUE` format.

```bash theme={null}
# Project Settings
PROJECT_NAME=MyProject

# Database
DB_HOST=localhost
DB_PORT=5432
DB_USER=postgres
DB_PASSWORD=your-db-password

# Session
SESSION_SECRET=your-session-secret  # Minimum 64 characters
SESSION_SALT=your-session-salt  # Minimum 16 characters

# Storage (fs or s3)
DRIVE_DISK=fs

# AWS S3 (when DRIVE_DISK=s3)
AWS_ACCESS_KEY_ID=your-aws-access-key-id
AWS_SECRET_ACCESS_KEY=your-aws-secret-access-key
S3_REGION=ap-northeast-2
S3_BUCKET=my-bucket

# External APIs
OPENAI_API_KEY=your-openai-api-key

# Worker
DISABLE_WORKER=false
```

<Info>
  Comments start with `#`. Blank lines are ignored.
</Info>

## Environment-Specific Settings

<Tabs>
  <Tab title="Development" icon="laptop-code">
    ```bash title=".env.development" theme={null}
    # Local development settings
    PROJECT_NAME=MyProject-Dev

    DB_HOST=localhost
    DB_PORT=5432
    DB_USER=postgres
    DB_PASSWORD=your-dev-password
    DATABASE_NAME=myproject_dev

    SESSION_SECRET=your-dev-session-secret
    SESSION_SALT=your-dev-session-salt

    DRIVE_DISK=fs

    # Development OpenAI (optional)
    OPENAI_API_KEY=sk-***

    DISABLE_WORKER=false
    ```

    **Characteristics:**

    * Uses local database
    * File system storage
    * Simple secret keys (security not required)
  </Tab>

  <Tab title="Staging" icon="flask">
    ```bash title=".env.staging" theme={null}
    # Test server settings
    PROJECT_NAME=MyProject-Staging

    DB_HOST=staging-db.example.com
    DB_PORT=5432
    DB_USER=myproject_user
    DB_PASSWORD=your-staging-password  # Minimum 32 characters
    DATABASE_NAME=myproject_staging

    SESSION_SECRET=your-staging-session-secret  # Minimum 64 characters
    SESSION_SALT=your-staging-session-salt

    DRIVE_DISK=s3
    AWS_ACCESS_KEY_ID=your-staging-aws-key-id
    AWS_SECRET_ACCESS_KEY=your-staging-aws-secret-key
    S3_REGION=ap-northeast-2
    S3_BUCKET=myproject-staging

    OPENAI_API_KEY=your-staging-openai-key

    DISABLE_WORKER=false
    ```

    **Characteristics:**

    * Remote database
    * S3 storage
    * Production-like environment
  </Tab>

  <Tab title="Production" icon="server">
    ```bash title=".env.production" theme={null}
    # Production server settings
    PROJECT_NAME=MyProject

    DB_HOST=prod-db.example.com
    DB_PORT=5432
    DB_USER=myproject_prod
    DB_PASSWORD=your-production-password  # Minimum 64 characters
    DATABASE_NAME=myproject_prod

    SESSION_SECRET=your-production-session-secret  # Minimum 64 characters
    SESSION_SALT=your-production-session-salt

    DRIVE_DISK=s3
    AWS_ACCESS_KEY_ID=your-production-aws-key-id
    AWS_SECRET_ACCESS_KEY=your-production-aws-secret-key
    S3_REGION=ap-northeast-2
    S3_BUCKET=myproject-production

    OPENAI_API_KEY=your-production-openai-key

    DISABLE_WORKER=false
    ```

    **Characteristics:**

    * High-availability database
    * S3 storage (scalability)
    * Strong security keys
  </Tab>
</Tabs>

## sonamu.config.ts Integration

How to use environment variables in `sonamu.config.ts`.

### Basic Pattern

```typescript theme={null}
import { defineConfig } from "sonamu";

export default defineConfig({
  projectName: process.env.PROJECT_NAME ?? "DefaultName",
  
  database: {
    name: process.env.DATABASE_NAME ?? "database_name",
    defaultOptions: {
      connection: {
        host: process.env.DB_HOST || "0.0.0.0",
        port: Number(process.env.DB_PORT) || 5432,
        user: process.env.DB_USER || "postgres",
        password: process.env.DB_PASSWORD,
      },
    },
  },
  
  // ...
});
```

### Nullish Coalescing vs OR

<CodeGroup>
  ```typescript Nullish Coalescing (??) theme={null}
  // Recommended: Only replaces undefined/null
  const name = process.env.PROJECT_NAME ?? "DefaultName";

  // undefined, null → "DefaultName"
  // ""(empty string) → "" preserved
  // 0 → 0 preserved
  ```

  ```typescript Logical OR (||) theme={null}
  // Caution: Replaces all falsy values
  const name = process.env.PROJECT_NAME || "DefaultName";

  // undefined, null, "", 0, false → "DefaultName"
  // Empty strings are also replaced with default
  ```
</CodeGroup>

<Tip>
  Use `??` when you only want to use the default value if the environment variable is not set. `||` treats empty strings as falsy.
</Tip>

### Number Conversion

```typescript theme={null}
// ✅ Correct method
port: Number(process.env.DB_PORT) || 5432

// ❌ Incorrect method
port: process.env.DB_PORT || 5432  // Can become string "5432"
```

### Boolean Conversion

```typescript theme={null}
// ✅ Correct method
enableWorker: !["true", "1"].includes(process.env.DISABLE_WORKER ?? "false")

// Or
enableCache: process.env.ENABLE_CACHE === "true"

// ❌ Incorrect method
enableCache: process.env.ENABLE_CACHE || false  // "false" is also truthy
```

## Security Best Practices

<Accordion title="Secret Key Generation" icon="key">
  ### Generating Strong Secret Keys

  ```bash theme={null}
  # Generate 64-character random string
  openssl rand -base64 48

  # Or
  node -e "console.log(require('crypto').randomBytes(48).toString('base64'))"
  ```

  **SESSION\_SECRET example:**

  ```bash theme={null}
  SESSION_SECRET=your-64-character-random-session-secret-change-in-production
  ```

  **Minimum lengths:**

  * SESSION\_SECRET: 64+ characters
  * SESSION\_SALT: 16+ characters
  * DB\_PASSWORD: 32+ characters (production)
</Accordion>

<Accordion title="Git Security" icon="git-alt">
  ### .gitignore Configuration

  ```bash title=".gitignore" theme={null}
  # Environment variables
  .env
  .env.local
  .env.*.local

  # Never commit production environment variables
  .env.production

  # Test environments may be allowed (if no sensitive info)
  # .env.test
  ```

  ### Maintaining .env.example

  ```bash title=".env.example" theme={null}
  # List keys only without actual values
  PROJECT_NAME=

  DB_HOST=localhost
  DB_PORT=5432
  DB_USER=
  DB_PASSWORD=

  SESSION_SECRET=
  SESSION_SALT=
  ```

  <Info>
    Commit `.env.example` to Git so team members can reference it.
  </Info>
</Accordion>

<Accordion title="Permission Management" icon="shield">
  ### File Permission Settings

  ```bash theme={null}
  # Set .env file permissions to owner read/write only
  chmod 600 .env

  # Verify
  ls -la .env
  # -rw------- 1 user user 512 Jan 09 10:00 .env
  ```

  ### Restricting Environment Variable Access

  ```typescript theme={null}
  // ✅ Access only where needed
  const dbPassword = process.env.DB_PASSWORD;

  // ❌ Never output to logs
  console.log("Password:", process.env.DB_PASSWORD);

  // ❌ Never expose to client
  res.send({ secret: process.env.SESSION_SECRET });
  ```
</Accordion>

<Accordion title="CI/CD Environment Variables" icon="gears">
  ### GitHub Actions

  ```yaml title=".github/workflows/deploy.yml" theme={null}
  jobs:
    deploy:
      steps:
        - name: Deploy
          env:
            DB_HOST: ${{ secrets.DB_HOST }}
            DB_PASSWORD: ${{ secrets.DB_PASSWORD }}
            SESSION_SECRET: ${{ secrets.SESSION_SECRET }}
          run: |
            npm run deploy
  ```

  ### Vercel/Netlify

  1. Project Settings → Environment Variables
  2. Add each variable individually
  3. Set different values per environment (Production/Preview/Development)

  <Warning>
    Never use production secrets in development/staging environments!
  </Warning>
</Accordion>

## Troubleshooting

<Accordion title="Environment Variable is undefined" icon="circle-question">
  **Symptom:** `process.env.DB_PASSWORD` is `undefined`

  **Causes:**

  1. `.env` file doesn't exist
  2. `.env` file is in wrong location
  3. Typo in variable name
  4. Server not restarted

  **Solution:**

  ```bash theme={null}
  # 1. Check .env file
  cat .env | grep DB_PASSWORD

  # 2. Verify .env file location (project root)
  ls -la .env

  # 3. Restart server
  npm run dev
  ```
</Accordion>

<Accordion title="Environment Variable Changes Not Applied" icon="rotate">
  **Symptom:** Changed environment variable but still using old value

  **Cause:**

  * Node.js only reads `.env` file when the process starts
  * Server restart required after file changes

  **Solution:**

  ```bash theme={null}
  # Restart development server
  # Stop with Ctrl+C then
  npm run dev
  ```

  <Info>
    HMR (Hot Module Replacement) only auto-reloads code; environment variables require a restart to apply.
  </Info>
</Accordion>

<Accordion title="Environment Variables Fail to Load in Production" icon="server">
  **Symptom:** Works locally but `undefined` in production

  **Causes:**

  * `.env` file doesn't exist on production server
  * Hosting platform environment variables not configured

  **Solutions:**

  **Method 1: Deploy .env file to server**

  ```bash theme={null}
  # After SSH connection
  cd /path/to/app
  nano .env
  # Paste content and save
  ```

  **Method 2: Use hosting platform environment variables**

  * Vercel: Project Settings → Environment Variables
  * AWS EC2: `/etc/environment` or `~/.bashrc`
  * Docker: `docker run -e DB_HOST=... -e DB_PASSWORD=...`
</Accordion>

## Next Steps

<CardGroup cols={2}>
  <Card title="Database Credentials" icon="database" href="/en/configuration/environment-variables/database-credentials">
    Set up DB connection information securely
  </Card>

  <Card title="API Key Management" icon="key" href="/en/configuration/environment-variables/api-keys">
    Manage external service API keys securely
  </Card>

  <Card title="sonamu.config.ts" icon="gear" href="/en/configuration/sonamu-config">
    Configure your entire project settings
  </Card>

  <Card title="Authentication Setup" icon="shield" href="/en/api-development/authentication/setup">
    Set up authentication and session security
  </Card>
</CardGroup>
