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

# Environment Variables & Secrets

> Manage configuration, credentials, and sensitive data securely with environment variables and encrypted secrets

## Stop Hardcoding Credentials

Every IoT deployment needs connection strings, API keys, and passwords -- but embedding them directly in your LoT code or route definitions creates security risks and makes your configuration impossible to reuse across environments. The Coreflux Broker solves this with built-in environment variable and secrets management.

* **Environment variables** store non-sensitive configuration (hostnames, ports, URLs) in a plain-text `.env` file
* **Secrets** store sensitive credentials (passwords, API keys, tokens) encrypted at rest with **AES-256-GCM**

Both are accessible from LoT Actions, Models, Routes, and broker CLI commands using a unified syntax -- no external tools or services required.

> [!TIP]
>
> **Think of it like a vault and a notebook.** Environment variables are the notebook -- quick to read, easy to update, visible if someone opens the file. Secrets are the vault -- locked with a key, encrypted on disk, only decrypted when the broker needs them at runtime.

> [!NOTE]
>
> Environment variables and secrets management is available from **Coreflux Broker v1.9.3** and above.

## When to Use Each

| Scenario | Use | Why |
| - | - | - |
| Database host, port, name | **Environment variable** | Non-sensitive, changes per environment |
| API base URLs | **Environment variable** | Configuration that varies between dev/staging/prod |
| Feature flags | **Environment variable** | Simple on/off toggles |
| Database passwords | **Secret** | Must not be readable on disk |
| API keys and tokens | **Secret** | Sensitive credentials |
| TLS passphrases | **Secret** | Security-critical values |

***

## Config Root

The broker picks its **data directory** (config root) in this order — **first match wins**:

1. `COREFLUX_DATA_PATH` (used as-is)
2. `CONFIG_PATH` (used as-is; this is what official Docker images set)
3. `-p` / `--path` (used as-is, applied later in startup — prefer the env vars)
4. Default: `{install directory}/Coreflux`

When an env var is set, **`/Coreflux` is not appended**. With `CONFIG_PATH=/etc/project`, files live at `/etc/project/.env`, not `/etc/project/Coreflux/.env`. The `/Coreflux` suffix is only added in the default case (no env var and no `-p`).

| Install | Typical data directory |
| - | - |
| Docker / Compose | `/etc/project` (`CONFIG_PATH` in the image; mount your volume here) |
| Linux APT/DNF | `/var/lib/coreflux` (`COREFLUX_DATA_PATH` in `coreflux-broker.service`) |
| Windows / portable binary | `{folder with the executable}/Coreflux` unless you set `COREFLUX_DATA_PATH` |

### File Layout

Environment and secrets files live in the data directory:

```
{data directory}/
  .env                # Plain-text environment variables (key=value)
  secrets.json        # AES-256-GCM encrypted secrets
  secret.key          # Optional: encryption key (base64, 32 bytes)
  bin/                # Internal broker data (managed automatically)
  log/                # Log files
  stats/              # Statistics
```

***

## Broker process environment variables

These names are read by the **broker process** (Docker `environment:`, systemd `Environment=`, Kubernetes `env:`). They are not the same as values you store in `.env` for `GET ENV` — though a name set in the process environment is still visible to `GET ENV` through the fallback chain.

Restart the broker after changing them.

### Data path and logging

| Variable | Default | Description |
| - | - | - |
| `COREFLUX_DATA_PATH` | `{install}/Coreflux` | Data directory, used as-is. Wins over `CONFIG_PATH` and over the `ProjectPath` config field. |
| `CONFIG_PATH` | — | Same role as `COREFLUX_DATA_PATH` if that variable is unset. Official images set this to `/etc/project`. A non-empty `ProjectPath` in broker JSON can still override it unless `COREFLUX_DATA_PATH` is set. |
| `COREFLUX_CLOUD_LOGGING` | auto in containers | `true` / `1` forces stdout JSON logs. Also on when the process runs in a container. |
| `COREFLUX_LOG_LEVEL` | `Information` | Serilog level (`Verbose`, `Debug`, `Information`, `Warning`, `Error`, `Fatal`). |

### Secrets and audit

| Variable | Default | Description |
| - | - | - |
| `COREFLUX_SECRET_KEY` | derived key | Base64-encoded 32-byte key for `secrets.json`. Preferred in Docker/Kubernetes. |
| `COREFLUX_AUDIT_KEY` | derived key | Base64-encoded 32-byte key for encrypted audit logs (or use `audit.key` in the data directory). |

### Operational HTTP (`/health`, `/ready`, `/info`, `/metrics`)

| Variable | Default | Description |
| - | - | - |
| `COREFLUX_OPS_ENABLED` | `true` | Set `false` / `0` to disable the ops listener. |
| `COREFLUX_OPS_PORT` | `9100` | Ops TCP port. Do not publish this port to the public internet. |
| `COREFLUX_OPS_BIND_IP` | `0.0.0.0` | Ops bind address. Use `127.0.0.1` to keep probes on localhost. |

Env vars override the matching fields in broker JSON (`OpsEnabled`, `OpsPort`, `OpsBindIP`).

### Routes, durability, clustering, Python

| Variable | Description |
| - | - |
| `COREFLUX_ROUTE_OVERLOAD_POLICY` | Broker-wide default `lossless`, `balanced`, or `realtime`. See [Route Overload Configuration](/v2.14/lot-language/routes/route-config). |
| `COREFLUX_ROUTE_CHANNEL_FULL_TIMEOUT_MS` | Wait budget (ms) for `balanced` (default `50`). |
| `COREFLUX_ROUTE_CHANNEL_CAPACITY` | Shared queue ceiling (default `100000`). |
| `COREFLUX_DURABILITY_*` | Restart persistence for retained messages and sessions. See [MQTT State Durability](/v2.14/mqtt-broker/durability). |
| `COREFLUX_CLUSTER_*` | High-availability clustering. See [Clustering](/v2.14/mqtt-broker/clustering). |
| `COREFLUX_DISABLE_PYTHON` | `true` skips in-process Python (`CALL PYTHON`). |

***

## Environment Variables

### Storage

Environment variables are stored in plain text in `{data directory}/.env` using standard key=value format:

```env wrap theme={"theme":"css-variables","languages":{"custom":["/languages/lot.json"]}}
DB_HOST=postgres.example.com
DB_PORT=5432
API_BASE_URL=https://api.example.com
MQTT_BRIDGE_HOST=remote-broker.company.com
```

### Resolution Order

When the broker resolves an environment variable (via `GET ENV`, route config, or CLI), it checks multiple sources in this order:

| Priority | Source | Description |
| - | - | - |
| 1 | `.env` file (managed) | Set via `-setEnv` or `KEEP ENV`. Persisted to disk. |
| 2 | Process environment | Docker `environment:`, Kubernetes `env:`, or shell exports. |
| 3 | User environment | OS user-level environment variables (non-Docker). |
| 4 | Machine environment | OS machine-level environment variables (non-Docker). |

If not found in any source, an empty string is returned.

> [!NOTE]
>
> This fallback chain means Docker `environment:` variables work even without a `.env` file -- the broker picks them up from the process environment automatically.

***

## Secrets

### How Secrets Work

Secrets are encrypted at rest using **AES-256-GCM** and stored in `{data directory}/secrets.json`. Each secret entry contains the initialization vector, the encrypted value with authentication tag, and a creation timestamp:

```json wrap theme={"theme":"css-variables","languages":{"custom":["/languages/lot.json"]}}
{
  "DB_PASSWORD": {
    "IV": "base64...",
    "Value": "base64(ciphertext):base64(tag)",
    "Created": "2026-02-08T12:00:00Z"
  }
}
```

Secret values are only decrypted at runtime when accessed via `GET SECRET` or route configuration. They are never logged or displayed -- even the `-listSecrets` command only shows secret names, never values.

### Encryption Key

The broker resolves the encryption key in this order:

| Priority | Source | Notes |
| - | - | - |
| 1 | `COREFLUX_SECRET_KEY` env var | Best for Docker/Kubernetes. Base64-encoded, 32 bytes. |
| 2 | `{data directory}/secret.key` file | Good for mounted volumes. Base64-encoded, 32 bytes. |
| 3 | Derived from machine GUID | Auto-generated fallback. Machine-specific -- secrets become unreadable if moved to a different machine. |

#### Generating a Key

Use OpenSSL to generate a cryptographically secure 32-byte key:

```bash wrap theme={"theme":"css-variables","languages":{"custom":["/languages/lot.json"]}}
openssl rand -base64 32
# Example output: K7x2mN8pQ1rT5uW3yB6dF9hJ0kL4nP7sV2xZ8cG1eA=
```

> [!WARNING]
>
> If you use the derived key fallback (no explicit key), your secrets are tied to the specific machine. Moving the `secrets.json` file to another machine or container will make the secrets unreadable. Always use an explicit key for portable deployments.

***

## Using in LoT

Environment variables and secrets can be read, written, and deleted from within LoT Actions, Models, and route configurations.

### Reading Values

Use `GET ENV` to read an environment variable and `GET SECRET` to read an encrypted secret (decrypted at runtime):

```lot wrap theme={"theme":"css-variables","languages":{"custom":["/languages/lot.json"]}}
-- Read configuration from environment
SET "myHost" WITH (GET ENV "DB_HOST")
SET "myPort" WITH (GET ENV "DB_PORT")

-- Read credentials from encrypted secrets
SET "dbPass" WITH (GET SECRET "DB_PASSWORD")
SET "apiKey" WITH (GET SECRET "API_KEY")
```

### Persisting Values

Use `KEEP ENV` to save a new environment variable to the `.env` file, and `KEEP SECRET` to encrypt and store a new secret:

```lot wrap theme={"theme":"css-variables","languages":{"custom":["/languages/lot.json"]}}
-- Save an environment variable (persisted to .env)
KEEP ENV "LAST_RUN" WITH TIMESTAMP "UTC"

-- Save an encrypted secret (persisted to secrets.json)
KEEP SECRET "API_KEY" WITH "sk-abc123"
```

### Deleting Values

Use `DELETE ENV` and `DELETE SECRET` to remove values:

```lot wrap theme={"theme":"css-variables","languages":{"custom":["/languages/lot.json"]}}
-- Remove an environment variable
DELETE ENV "OLD_CONFIG"

-- Remove a secret
DELETE SECRET "OLD_API_KEY"
```

### Complete Example

This action reads database configuration from environment variables and credentials from secrets on broker startup, then reports the status:

```lot wrap theme={"theme":"css-variables","languages":{"custom":["/languages/lot.json"]}}
DEFINE ACTION ConnectToDatabase
ON START DO
    -- Read connection settings from environment
    SET "host" WITH (GET ENV "DB_HOST")
    SET "port" WITH (GET ENV "DB_PORT")
    SET "dbName" WITH (GET ENV "DB_NAME")

    -- Read credentials from encrypted secrets
    SET "user" WITH (GET SECRET "DB_USER")
    SET "pass" WITH (GET SECRET "DB_PASSWORD")

    IF {host} == EMPTY THEN
        PUBLISH TOPIC "system/errors" WITH "DB_HOST not configured"
    ELSE
        PUBLISH TOPIC "system/status" WITH "Database configured: " + {host} + ":" + {port}

    -- Track when we last initialized
    KEEP ENV "LAST_DB_INIT" WITH TIMESTAMP "UTC"
```

***

## Using in Routes

Environment variables and secrets can be referenced directly in route definitions, keeping connection details out of your LoT code.

### Standard Syntax

Use `GET ENV` and `GET SECRET` in route configuration blocks to inject values at runtime:

```lot wrap theme={"theme":"css-variables","languages":{"custom":["/languages/lot.json"]}}
DEFINE ROUTE MyDB WITH TYPE POSTGRESQL
    ADD SQL_CONFIG
        WITH SERVER GET ENV "DB_HOST"
        WITH PORT 5432
        WITH DATABASE GET ENV "DB_NAME"
        WITH USERNAME GET ENV "DB_USER"
        WITH PASSWORD GET SECRET "DB_PASSWORD"
```

### Legacy Prefix Syntax

The `ENV:` and `SECRET:` prefix syntax is also supported for backward compatibility in route `ADD CONFIG` sections:

```lot wrap theme={"theme":"css-variables","languages":{"custom":["/languages/lot.json"]}}
WITH SERVER ENV:DB_HOST
WITH PASSWORD SECRET:DB_PASSWORD
```

### Event Query Placeholders

In route event queries (e.g. `WITH QUERY`), use curly-brace placeholders that are resolved at execution time:

```lot wrap theme={"theme":"css-variables","languages":{"custom":["/languages/lot.json"]}}
ADD EVENT StoreReading
    WITH SOURCE_TOPIC "sensors/#"
    WITH QUERY "INSERT INTO readings (host, value) VALUES ('{env.DB_HOST}', '{payload}')"
```

| Placeholder | Resolves To |
| - | - |
| `{env.NAME}` | Environment variable value |
| `{secret.NAME}` | Decrypted secret value |

***

## CLI Commands

Manage environment variables and secrets at runtime by publishing commands to `$SYS/Coreflux/Command` using any MQTT client (such as MQTT Explorer).

### Environment Variable Commands

| Command | Description |
| - | - |
| `-setEnv NAME=value` | Set an environment variable (persisted to `.env` file) |
| `-removeEnv NAME` | Remove an environment variable |
| `-listEnv` | List all managed environment variables |

Publish these messages to `$SYS/Coreflux/Command` to manage environment variables:

```bash wrap theme={"theme":"css-variables","languages":{"custom":["/languages/lot.json"]}}
# Set an environment variable
-setEnv DB_HOST=postgres.example.com

# List all environment variables
-listEnv

# Remove an environment variable
-removeEnv OLD_CONFIG
```

### Secret Commands

| Command | Description |
| - | - |
| `-setSecret NAME=value` | Set a secret (encrypted and persisted to `secrets.json`) |
| `-removeSecret NAME` | Remove a secret |
| `-listSecrets` | List secret names (values are never shown) |

Publish these messages to `$SYS/Coreflux/Command` to manage secrets:

```bash wrap theme={"theme":"css-variables","languages":{"custom":["/languages/lot.json"]}}
# Set a secret
-setSecret DB_PASSWORD=my_secure_password

# List secret names
-listSecrets

# Remove a secret
-removeSecret OLD_API_KEY
```

> [!NOTE]
>
> Subscribe to `$SYS/Coreflux/Command/Output` to receive confirmation responses from commands.

***

## Deployment

Set up environment variables and secrets across different deployment targets.

**Windows**

On Windows, the data directory defaults to the broker's executable folder + `\Coreflux` unless `COREFLUX_DATA_PATH` is set (used as-is).

**1. Locate the data directory**

If the broker is at `C:\Coreflux\CorefluxMQTTBroker.exe`, the default data directory is `C:\Coreflux\Coreflux\`.

To pin a custom path, set a machine environment variable (no extra `\Coreflux` is appended):

```powershell wrap theme={"theme":"css-variables","languages":{"custom":["/languages/lot.json"]}}
[Environment]::SetEnvironmentVariable("COREFLUX_DATA_PATH", "C:\CorefluxData", "Machine")
```

Files then live directly under `C:\CorefluxData\`.

**2. Create the .env File**

Create a `.env` file in the data directory:

```powershell wrap theme={"theme":"css-variables","languages":{"custom":["/languages/lot.json"]}}
@"
DB_HOST=postgres.example.com
DB_PORT=5432
API_BASE_URL=https://api.example.com
"@ | Out-File -FilePath "C:\CorefluxData\.env" -Encoding UTF8
```

**3. Generate an Encryption Key**

Generate and save a `secret.key` file for encrypting secrets:

```powershell wrap theme={"theme":"css-variables","languages":{"custom":["/languages/lot.json"]}}
openssl rand -base64 32 > "C:\CorefluxData\secret.key"
```

**4. Set Secrets After Start**

Start the broker, then set secrets using any MQTT client (such as MQTT Explorer). Publish to `$SYS/Coreflux/Command`:

```
-setSecret DB_PASSWORD=my_secure_password
```

> [!TIP]
>
> Subscribe to `$SYS/Coreflux/Command/Output` to confirm the secret was stored.

**Linux**

APT/DNF installs already set `COREFLUX_DATA_PATH=/var/lib/coreflux` on `coreflux-broker.service`. Put `.env` and `secret.key` there.

**1. Create the .env file**

Write your environment variables and restrict permissions:

```bash wrap theme={"theme":"css-variables","languages":{"custom":["/languages/lot.json"]}}
sudo tee /var/lib/coreflux/.env << 'EOF'
DB_HOST=postgres.example.com
DB_PORT=5432
API_BASE_URL=https://api.example.com
EOF
sudo chown coreflux:coreflux /var/lib/coreflux/.env
sudo chmod 600 /var/lib/coreflux/.env
```

**2. Generate an encryption key**

```bash wrap theme={"theme":"css-variables","languages":{"custom":["/languages/lot.json"]}}
openssl rand -base64 32 | sudo tee /var/lib/coreflux/secret.key >/dev/null
sudo chown coreflux:coreflux /var/lib/coreflux/secret.key
sudo chmod 600 /var/lib/coreflux/secret.key
```

**3. Restart the service**

```bash wrap theme={"theme":"css-variables","languages":{"custom":["/languages/lot.json"]}}
sudo systemctl restart coreflux-broker
```

**4. Set Secrets After Start**

Using any MQTT client, publish to `$SYS/Coreflux/Command`:

```
-setSecret DB_PASSWORD=my_secure_password
```

> [!TIP]
>
> Verify with `-listSecrets` -- the secret name should appear in the output.

**Docker Compose**

### Option 1: Mount a Config Volume (Recommended)

Pre-create the config files on the host and mount them into the container.

**1. Prepare the host directory:**

Create the config directory, generate an encryption key, and write your environment variables:

```bash wrap theme={"theme":"css-variables","languages":{"custom":["/languages/lot.json"]}}
mkdir -p ./coreflux-data

# Generate encryption key
openssl rand -base64 32 > ./coreflux-data/secret.key

# Create .env file
cat > ./coreflux-data/.env << 'EOF'
DB_HOST=postgres.example.com
DB_PORT=5432
API_BASE_URL=https://api.example.com
EOF
```

**2. Docker Compose file:**

Mount the host directory at `/etc/project` (the image's `CONFIG_PATH`):

```yaml wrap theme={"theme":"css-variables","languages":{"custom":["/languages/lot.json"]}}
services:
  coreflux-broker:
    image: coreflux/coreflux-mqtt-broker:latest
    container_name: coreflux-broker
    ports:
      - "1883:1883"
      - "8883:8883"
      - "5000:5000"
      - "9100:9100"
    volumes:
      - ./coreflux-data:/etc/project
    restart: unless-stopped
```

The broker resolves:

* `CONFIG_PATH=/etc/project` (baked into the image) — data directory is `/etc/project`
* `.env` from `/etc/project/.env` (your `./coreflux-data/.env`)
* `secret.key` from `/etc/project/secret.key`
* All broker state persists in the mounted directory

**3. Set secrets after the broker starts:**

Using any MQTT client, publish to `$SYS/Coreflux/Command`:

```
-setSecret DB_PASSWORD=my_secure_password
```

### Option 2: Pass Env Vars via Docker (No .env File)

If you prefer not to manage a `.env` file, pass variables directly through Docker's `environment:`. The resolution fallback to process environment picks them up:

```yaml wrap theme={"theme":"css-variables","languages":{"custom":["/languages/lot.json"]}}
services:
  coreflux-broker:
    image: coreflux/coreflux-mqtt-broker:latest
    ports:
      - "1883:1883"
      - "9100:9100"
    environment:
      - DB_HOST=postgres.example.com
      - DB_PORT=5432
      - API_BASE_URL=https://api.example.com
      - COREFLUX_SECRET_KEY=K7x2mN8pQ1rT5uW3yB6dF9hJ0kL4nP7sV2xZ8cG1eA=
    volumes:
      - coreflux-data:/etc/project

volumes:
  coreflux-data:
```

Variables set this way:

* Are available to LoT via `GET ENV "DB_HOST"`
* Are available to routes via `GET ENV "DB_HOST"` and legacy `ENV:DB_HOST`
* Are **not** persisted to `.env` (they exist only in the process environment)
* Will be lost if the container restarts without the same `environment:` block

> [!NOTE]
>
> Secrets still need a volume for `secrets.json` persistence, even when passing the encryption key via `COREFLUX_SECRET_KEY`.

**Kubernetes**

Use Kubernetes ConfigMaps for environment variables and Kubernetes Secrets for the encryption key.

**1. ConfigMap for environment variables:**

Store non-sensitive configuration in a ConfigMap:

```yaml wrap theme={"theme":"css-variables","languages":{"custom":["/languages/lot.json"]}}
apiVersion: v1
kind: ConfigMap
metadata:
  name: coreflux-env
data:
  DB_HOST: "postgres.cluster.local"
  DB_PORT: "5432"
  API_BASE_URL: "https://api.example.com"
```

**2. Kubernetes Secret for the encryption key:**

Store the encryption key in a Kubernetes Secret (base64-encoded):

```yaml wrap theme={"theme":"css-variables","languages":{"custom":["/languages/lot.json"]}}
apiVersion: v1
kind: Secret
metadata:
  name: coreflux-secrets
type: Opaque
data:
  COREFLUX_SECRET_KEY: SzdsMm1OOHBRMXJUNXVXM3lCNmRGOWhKMGtMNG5QN3NWMnhaOGNHMWVBPQ==
```

**3. Deployment:**

Inject the ConfigMap as environment variables via `envFrom`, and the encryption key from the Kubernetes Secret:

```yaml wrap theme={"theme":"css-variables","languages":{"custom":["/languages/lot.json"]}}
apiVersion: apps/v1
kind: Deployment
metadata:
  name: coreflux-broker
spec:
  replicas: 1
  selector:
    matchLabels:
      app: coreflux-broker
  template:
    metadata:
      labels:
        app: coreflux-broker
    spec:
      containers:
        - name: broker
          image: coreflux/coreflux-mqtt-broker:latest
          ports:
            - containerPort: 1883
            - containerPort: 5000
            - containerPort: 9100
          env:
            - name: CONFIG_PATH
              value: "/etc/project"
            - name: COREFLUX_SECRET_KEY
              valueFrom:
                secretKeyRef:
                  name: coreflux-secrets
                  key: COREFLUX_SECRET_KEY
          envFrom:
            - configMapRef:
                name: coreflux-env
          volumeMounts:
            - name: data
              mountPath: /etc/project
      volumes:
        - name: data
          persistentVolumeClaim:
            claimName: coreflux-pvc
```

**4. PersistentVolumeClaim:**

Provide persistent storage for broker data, secrets, and configuration:

```yaml wrap theme={"theme":"css-variables","languages":{"custom":["/languages/lot.json"]}}
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: coreflux-pvc
spec:
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 1Gi
```

Apply all resources:

```bash wrap theme={"theme":"css-variables","languages":{"custom":["/languages/lot.json"]}}
kubectl apply -f coreflux-configmap.yaml
kubectl apply -f coreflux-secret.yaml
kubectl apply -f coreflux-pvc.yaml
kubectl apply -f coreflux-deployment.yaml
```

ConfigMap values are injected as process environment variables via `envFrom`, so `GET ENV` picks them up through the fallback chain. The `COREFLUX_SECRET_KEY` from the Kubernetes Secret enables portable secret encryption.

***

## Best Practices

> **Use explicit encryption keys in production**
>
> Never rely on the derived key fallback for production deployments. Always provide a `COREFLUX_SECRET_KEY` environment variable or a `secret.key` file. The derived key is machine-specific -- if you migrate, scale, or recreate a container, your secrets become unreadable.

> **Restrict file permissions**
>
> On Linux, restrict access to sensitive files to the broker's service user only:
>
> ```bash wrap theme={"theme":"css-variables","languages":{"custom":["/languages/lot.json"]}}
> chmod 600 /var/lib/coreflux/.env
> chmod 600 /var/lib/coreflux/secret.key
> chmod 600 /var/lib/coreflux/secrets.json
> ```

> **Prefer GET ENV over hardcoded values**
>
> Even for values that seem static (like a database port), use `GET ENV` so you can change configuration without redeploying LoT code. This makes your Actions and Routes portable across dev, staging, and production.

> **Use mounted volumes for Docker**
>
> Always mount a persistent volume at the data directory (`/etc/project` in Docker, `/var/lib/coreflux` on Linux packages). Without a volume, `.env`, `secrets.json`, and broker state are lost when the container is recreated.

> **Never commit secrets to version control**
>
> Keep `secret.key`, `secrets.json`, and `.env` files out of Git. Add them to `.gitignore` and use your deployment pipeline to inject them at runtime.

***

## Resolution Reference

### Where Each Syntax Reads From

| Syntax | Where It Works | Resolved By |
| - | - | - |
| `GET ENV "NAME"` | Actions, Models, Route configs | `.env` file, then process env fallback |
| `GET SECRET "NAME"` | Actions, Models, Route configs | Decrypts from `secrets.json` |
| `ENV:NAME` | Route `ADD CONFIG` sections only | Same as `GET ENV` |
| `SECRET:NAME` | Route `ADD CONFIG` sections only | Same as `GET SECRET` |
| `{env.NAME}` | Event queries (`WITH QUERY`) | Replaced at event execution time |
| `{secret.NAME}` | Event queries (`WITH QUERY`) | Replaced at event execution time |

### Encryption Key Resolution Order

| Priority | Source | Notes |
| - | - | - |
| 1 | `COREFLUX_SECRET_KEY` env var | Best for Docker/Kubernetes. Base64-encoded, 32 bytes. |
| 2 | `{data directory}/secret.key` file | Good for mounted volumes. Base64-encoded, 32 bytes. |
| 3 | Derived from machine GUID | Auto-generated fallback. Machine-specific -- secrets won't decrypt on a different machine. |

### GetEnv Resolution Order

| Priority | Source | Notes |
| - | - | - |
| 1 | `.env` file (managed) | Set via `-setEnv` or `KEEP ENV`. Persisted to disk. |
| 2 | Process environment | Docker `environment:`, Kubernetes `env:`, or shell exports. |
| 3 | User environment | OS user-level env vars (non-Docker). |
| 4 | Machine environment | OS machine-level env vars (non-Docker). |

***

## Next Steps

> **[Broker Commands](/v2.14/mqtt-broker/commands)**
>
> Full reference for all broker CLI commands including env and secret management.

> **[Operations Reference](/v2.14/lot-language/actions/operations)**
>
> See GET ENV and GET SECRET in the complete LoT operations reference.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.