# Environment Variables (https://www.librechat.ai/docs/configuration/dotenv)

Welcome to the comprehensive guide for configuring your application's environment with the `.env` file. This document is your one-stop resource for understanding and customizing the environment variables that will shape your application's behavior in different contexts.

While the default settings provide a solid foundation for a standard `docker` installation, delving into this guide will unveil the full potential of LibreChat. This guide empowers you to tailor LibreChat to your precise needs. Discover how to adjust language model availability, integrate social logins, manage the automatic moderation system, and much more. It's all about giving you the control to fine-tune LibreChat for an optimal user experience.

> **Reminder: Please restart LibreChat for the configuration changes to take effect**

Alternatively, you can create a new file named `docker-compose.override.yml` in the same directory as your main `docker-compose.yml` file for LibreChat, where you can set your .env variables as needed under `environment`, or modify the default configuration provided by the main `docker-compose.yml`, without the need to directly edit or duplicate the whole file.

For more info see:

- Our quick guide:
  - **[Docker Override](/docs/configuration/docker_override)**

- The official docker documentation:
  - **[docker docs - understanding-multiple-compose-files](https://docs.docker.com/compose/how-tos/multiple-compose-files/extends/)**
  - **[docker docs - merge-compose-files](https://docs.docker.com/compose/how-tos/multiple-compose-files/merge/)**
  - **[docker docs - specifying-multiple-compose-files](https://docs.docker.com/compose/reference/#specifying-multiple-compose-files)**

- You can also view an example of an override file for LibreChat in your LibreChat folder and on GitHub:
  - **[docker-compose.override.example](https://github.com/danny-avila/LibreChat/blob/main/docker-compose.override.yml.example)**

---

## Server Configuration

### Port

- The server listens on a specific port.
- The `PORT` environment variable sets the port where the server listens. By default, it is set to `3080`.

<OptionTable
  options={[
    ['HOST', 'string', 'Specifies the host.', 'HOST=localhost'],
    ['PORT', 'number', 'Specifies the port.', 'PORT=3080'],
  ]}
/>

### HTTP Server Timeouts

These optional values configure the Node.js HTTP server. Leave them unset to retain Node's defaults. A value of `0` disables that timeout.

<OptionTable
  options={[
    [
      'HTTP_KEEP_ALIVE_TIMEOUT_MS',
      'integer',
      'Idle keep-alive timeout in milliseconds. Set this above the load balancer idle timeout to avoid reused connections racing server closure. Node default: 5000.',
      '# HTTP_KEEP_ALIVE_TIMEOUT_MS=70000',
    ],
    [
      'HTTP_KEEP_ALIVE_TIMEOUT_BUFFER_MS',
      'integer',
      'Additional socket timeout buffer in milliseconds. Node default: 1000.',
      '# HTTP_KEEP_ALIVE_TIMEOUT_BUFFER_MS=5000',
    ],
    [
      'HTTP_HEADERS_TIMEOUT_MS',
      'integer',
      'Time allowed to receive complete request headers. Node default: 60000.',
      '# HTTP_HEADERS_TIMEOUT_MS=80000',
    ],
    [
      'HTTP_REQUEST_TIMEOUT_MS',
      'integer',
      'Time allowed to receive the complete request. Node default: 300000.',
      '# HTTP_REQUEST_TIMEOUT_MS=300000',
    ],
  ]}
/>

Values must be non-negative safe integers; invalid values are ignored. When both header and request timeouts are enabled, LibreChat clamps the header timeout to the request timeout if it is higher. Node checks header and request expiry on a 30-second connection sweep, so values below `30000` are not enforced at exact millisecond precision. Bun currently accepts these settings but does not enforce them; LibreChat logs a warning when the API server runs under Bun.

### Trust proxy

Use the address that is at most n number of hops away from the Express application.
req.socket.remoteAddress is the first hop, and the rest are looked for in the X-Forwarded-For header from right to left.
A value of 0 means that the first untrusted address would be req.socket.remoteAddress, i.e. there is no reverse proxy.
The `TRUST_PROXY` environment variable default is set to `1`.

Refer to [Express.js - trust proxy](https://expressjs.com/en/guide/behind-proxies.html) for more information about this.

<OptionTable
  options={[['TRUST_PROXY', 'number', 'Specifies the number of hops.', 'TRUST_PROXY=1']]}
/>

### Trusted Tenant Header

`TRUST_TENANT_HEADER` controls whether LibreChat accepts `X-Tenant-Id` before authentication on the `/oauth`, `/api/auth`, and `/api/share` route trees. It is disabled by default; while disabled, those routes ignore the header.

<OptionTable
  options={[
    [
      'TRUST_TENANT_HEADER',
      'boolean',
      'Trust X-Tenant-Id on pre-authentication routes. Enable only behind a trusted proxy that replaces client-supplied values.',
      'TRUST_TENANT_HEADER=false',
    ],
  ]}
/>

<Callout type="warning" title="Do not trust client-supplied tenant headers">
  Enable this setting only when a trusted reverse proxy strips every incoming `X-Tenant-Id` value and sets the authoritative tenant ID itself. Otherwise, an untrusted client could choose the tenant context used before authentication. LibreChat logs a security warning when the setting is enabled.
</Callout>

When `TENANT_ISOLATION_STRICT` is enabled but `TRUST_TENANT_HEADER` is disabled, LibreChat warns at startup that pre-authentication tenant headers will be ignored.

### Credentials Configuration

LibreChat uses `CREDS_KEY` and `CREDS_IV` to encrypt supported credentials stored in the database. Configure fixed, unique values for production and share the same values across every replica.

<OptionTable
  options={[
    [
      'CREDS_KEY',
      'string',
      '32-byte key (64 hexadecimal characters) for securely storing credentials.',
      'CREDS_KEY=',
    ],
    [
      'CREDS_IV',
      'string',
      '16-byte IV (32 hexadecimal characters) for securely storing credentials.',
      'CREDS_IV=',
    ],
    [
      'LIBRECHAT_TEMP_CREDENTIALS_PATH',
      'string',
      'Path used to persist automatically generated temporary credentials. Defaults to `.env.temp` in the process working directory.',
      '# LIBRECHAT_TEMP_CREDENTIALS_PATH=/app/data/.env.temp',
    ],
  ]}
/>

When any of `CREDS_KEY`, `CREDS_IV`, `JWT_SECRET`, or `JWT_REFRESH_SECRET` is blank, LibreChat first reuses a valid value from the temporary credentials file. If none exists, it generates a cryptographically random value and writes the file with owner-only permissions. Explicit environment values always take precedence. LibreChat refuses to use `.env` or `.env.example` as the generated file path, preventing accidental replacement of either configuration file.

LibreChat also refuses to start when `JWT_SECRET` or `JWT_REFRESH_SECRET` still uses one of the retired published defaults, whether the value comes from the environment or the temporary credentials file. Generate unique replacements rather than carrying old sample secrets into a deployment.

The bundled Docker Compose files persist `/app/data/.env.temp` in the `librechat-data` volume, so a single Compose deployment can restart without changing these generated values. If the file cannot be persisted, the values are process-local and sessions or encrypted records may become inaccessible after restart.

<Callout type="warning" title="Set permanent values for production">
  Temporary generation is a bootstrap convenience, not a credential-rotation system. Before production use, generate permanent values with the [Credentials Generator](/toolkit/creds_generator), store them in your secret manager, and provide the same values to every replica. Changing an established key does not re-encrypt existing records. LibreChat records credential fingerprints in the database and warns when active values drift; do not overwrite that marker instead of performing a controlled migration.
</Callout>

### Security Headers and Content Security Policy

LibreChat sends baseline HSTS, framing, content-type, opener, resource, and referrer headers by default. `SECURITY_HEADERS=false` disables all of them and is also the global CSP kill switch.

Nonce-based CSP is separately opt-in with `CSP_ENABLED=true` and defaults to report-only mode. Start with `CSP_REPORT_ONLY=true`, inspect violations, and add only the origins your deployment requires before enforcing. When CSP is active, the SPA shell is always sent with `Cache-Control: no-store` so its per-response nonce cannot be reused from cache.

See [HTTP Security Headers](/docs/configuration/security_headers) for every baseline and CSP variable, accepted values, defaults, source-list overrides, and rollout guidance.

### Static File Handling

<OptionTable
  options={[
    [
      'STATIC_CACHE_MAX_AGE',
      'string',
      'Cache-Control max-age in seconds',
      'STATIC_CACHE_MAX_AGE=172800',
    ],
    [
      'STATIC_CACHE_S_MAX_AGE',
      'string',
      'Cache-Control s-maxage in seconds for shared caches (CDNs and proxies)',
      'STATIC_CACHE_S_MAX_AGE="86400"',
    ],
    [
      'DISABLE_COMPRESSION',
      'boolean',
      'Disables compression for static files.',
      'DISABLE_COMPRESSION=false',
    ],
    [
      'ENABLE_IMAGE_OUTPUT_GZIP_SCAN',
      'boolean',
      'Enables serving gzipped versions of uploaded images if present in the same folder.',
      'ENABLE_IMAGE_OUTPUT_GZIP_SCAN=true',
    ],
    [
      'ENABLE_STATIC_ASSET_BROTLI',
      'boolean',
      'Enables serving precompressed Brotli versions of static app assets when available.',
      'ENABLE_STATIC_ASSET_BROTLI=true',
    ],
  ]}
/>

**Behaviour:**

Sets the [Cache-Control](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cache-Control) headers for static files. These configurations only trigger when the `NODE_ENV` is set to `production`.

- Uncomment `STATIC_CACHE_MAX_AGE` to change the local `max-age` for static files. By default this is set to 2 days (172800 seconds).
- Uncomment `STATIC_CACHE_S_MAX_AGE` to set the `s-maxage` for shared caches (CDNs and proxies). By default this is set to 1 day (86400 seconds).
- Uncomment `DISABLE_COMPRESSION` to disable compression for static files. By default, compression is enabled.
- Uncomment `ENABLE_IMAGE_OUTPUT_GZIP_SCAN` to enable scanning and serving of gzipped version of images if they have been pre-compressed in the same folder, with the same name and a .gz extension. By default, gzip scan for uploaded images is disabled.
- Uncomment `ENABLE_STATIC_ASSET_BROTLI` to serve precompressed `.br` versions of static app assets when they exist. When enabled, Brotli is preferred before gzip for API-served static files.

<Callout type="warning" title="Warning">
  - This only affects static files served by the API server and is not applicable to _Firebase_,
  _NGINX_, or any other configurations.
</Callout>

### Index HTML Cache Control

<OptionTable
  options={[
    [
      'INDEX_CACHE_CONTROL',
      'string',
      'Cache-Control header for index.html',
      'INDEX_CACHE_CONTROL=no-cache, no-store, must-revalidate',
    ],
    ['INDEX_PRAGMA', 'string', 'Pragma header for index.html', 'INDEX_PRAGMA=no-cache'],
    ['INDEX_EXPIRES', 'string', 'Expires header for index.html', 'INDEX_EXPIRES=0'],
  ]}
/>

**Behaviour:**

Controls caching headers specifically for the index.html response. By default, these settings prevent caching to ensure users always get the latest version of the application.

<Callout type="note" title="Note">
  Unlike static assets which are cached for performance, the index.html file's cache headers are
  configured separately to ensure users always get the latest application shell.
</Callout>

### MongoDB Database

<OptionTable
  options={[
    [
      'MONGO_URI',
      'string',
      'Specifies the MongoDB URI.',
      'MONGO_URI=mongodb://127.0.0.1:27017/LibreChat',
    ],
  ]}
/>

Change this to your MongoDB URI if different. You should add `LibreChat` or your own `APP_TITLE` as the database name in the URI.

If you are using an online database, the URI format is `mongodb+srv://<username>:<password>@<host>/<database>?<options>`. Your `MONGO_URI` should look like this:

- `mongodb+srv://username:password@host.mongodb.net/LibreChat?retryWrites=true` (`retryWrites` is the only option you need when using the online database.)

#### MongoDB Connection Pool Configuration

<OptionTable
  options={[
    [
      'MONGO_MAX_POOL_SIZE',
      'number',
      'The maximum number of connections in the connection pool.',
      '# MONGO_MAX_POOL_SIZE=',
    ],
    [
      'MONGO_MIN_POOL_SIZE',
      'number',
      'The minimum number of connections in the connection pool.',
      '# MONGO_MIN_POOL_SIZE=',
    ],
    [
      'MONGO_MAX_CONNECTING',
      'number',
      'The maximum number of connections that may be in the process of being established concurrently by the connection pool.',
      '# MONGO_MAX_CONNECTING=',
    ],
    [
      'MONGO_MAX_IDLE_TIME_MS',
      'number',
      'The maximum number of milliseconds that a connection can remain idle in the pool before being removed and closed.',
      '# MONGO_MAX_IDLE_TIME_MS=',
    ],
    [
      'MONGO_WAIT_QUEUE_TIMEOUT_MS',
      'number',
      'The maximum time in milliseconds that a thread can wait for a connection to become available.',
      '# MONGO_WAIT_QUEUE_TIMEOUT_MS=',
    ],
  ]}
/>

#### MongoDB Schema Configuration

<OptionTable
  options={[
    [
      'MONGO_AUTO_INDEX',
      'boolean',
      'Set to false to disable automatic index creation for all models associated with this connection. When omitted, uses Mongoose default behavior.',
      '# MONGO_AUTO_INDEX=',
    ],
    [
      'MONGO_AUTO_CREATE',
      'boolean',
      'Set to false to disable Mongoose automatically calling createCollection() on every model created on this connection. When omitted, uses Mongoose default behavior.',
      '# MONGO_AUTO_CREATE=',
    ],
  ]}
/>

Amazon DocumentDB 5.0+ instance-based clusters are a supported target. DocumentDB requires `retryWrites=false` and TLS with the AWS CA bundle; elastic clusters are unsupported because they do not provide unique indexes. A typical URI has this form:

`mongodb://username:password@cluster:27017/librechat?tls=true&tlsCAFile=/path-to-ca/global-bundle.pem&replicaSet=rs0&readPreference=secondaryPreferred&retryWrites=false`

DocumentDB 4.0 can run with reduced partial-unique-index enforcement. See [Amazon DocumentDB Compatibility](/docs/user_guides/mongodb#amazon-documentdb-compatibility) for the supported target and caveats.

See also:

- [MongoDB Atlas](/docs/configuration/mongodb/mongodb_atlas) for instructions on how to create an online MongoDB Atlas database (useful for use without Docker)
- [MongoDB Community Server](/docs/configuration/mongodb/mongodb_community) for instructions on how to create a local MongoDB database (without Docker)
- [MongoDB Authentication](/docs/configuration/mongodb/mongodb_auth) To enable explicit authentication for MongoDB in Docker.
- [Manage your database with Mongo Express](/blog/2023-11-30_mongoexpress) for securely accessing your Docker MongoDB database

### Application Domains

To configure LibreChat for local use or custom domain deployment, set the following environment variables:

<OptionTable
  options={[
    [
      'DOMAIN_CLIENT',
      'string',
      'Specifies the client-side domain.',
      'DOMAIN_CLIENT=http://localhost:3080',
    ],
    [
      'DOMAIN_SERVER',
      'string',
      'Specifies the server-side domain.',
      'DOMAIN_SERVER=http://localhost:3080',
    ],
    [
      'ADMIN_PANEL_URL',
      'string',
      'External admin panel base URL used for admin OAuth/SSO redirects and the admin-only Settings > General link. Do not include a trailing slash.',
      'ADMIN_PANEL_URL=https://admin.example.com/admin',
    ],
    [
      'ADMIN_PANEL_SESSION_SECRET',
      'string',
      'Required session encryption key for the bundled admin panel (min 32 characters). The docker-compose and deploy-compose admin-panel services read it as their SESSION_SECRET. Generate with `openssl rand -hex 32` before starting the stack.',
      'ADMIN_PANEL_SESSION_SECRET=<your-32-char-random-string>',
    ],
    [
      'ADMIN_PANEL_PORT',
      'number',
      'Host port for the bundled admin panel in the default docker-compose. In deploy-compose the panel is served at http://admin.localhost via nginx instead.',
      'ADMIN_PANEL_PORT=3000',
    ],
  ]}
/>

When deploying LibreChat to a custom domain, replace `http://localhost:3080` with your deployed URL

- e.g. `https://librechat.example.com`.

### Prevent Public Search Engines Indexing

By default, your website will not be indexed by public search engines (e.g. Google, Bing, …). This means that people will not be able to find your website through these search engines. If you want to make your website more visible and searchable, you can change the following setting to `false`

<OptionTable
  options={[
    [
      'NO_INDEX',
      'boolean',
      'Prevents public search engines from indexing your website.',
      'NO_INDEX=true',
    ],
  ]}
/>

❗**Note:** This method is not guaranteed to work for all search engines, and some search engines may still index your website or web page for other purposes, such as caching or archiving. Therefore, you should not rely solely on this method to protect sensitive or confidential information on your website or web page.

### Logging

LibreChat has built-in central logging, see [Logging System](/docs/configuration/logging) for more info.

#### Log Files

- Debug logging is enabled by default and crucial for development.
- To report issues, reproduce the error and submit logs from `./api/logs/debug-%DATE%.log` at: **[LibreChat GitHub Issues](https://github.com/danny-avila/LibreChat/issues)**
- Error logs are stored in the same location.

#### Environment Variables

<OptionTable
  options={[
    ['DEBUG_LOGGING', 'boolean', 'Keep debug logs active.', 'DEBUG_LOGGING=true'],
    [
      'DEBUG_CONSOLE',
      'boolean',
      'Enable verbose console/stdout logs in the same format as file debug logs.',
      'DEBUG_CONSOLE=false',
    ],
    [
      'CONSOLE_LOG_LEVEL',
      'string',
      'Set console verbosity to error, warn, info, http, verbose, debug, activity, silly, or silent. Defaults to info, or debug when DEBUG_CONSOLE=true; an explicit value takes precedence.',
      '# CONSOLE_LOG_LEVEL=info',
    ],
    [
      'LOG_TO_FILE',
      'boolean',
      'Set to false to disable file-backed Winston transports while keeping console logging available.',
      'LOG_TO_FILE=true',
    ],
    [
      'CONSOLE_JSON',
      'boolean',
      'Enable verbose JSON console/stdout logs suitable for cloud deployments like GCP/AWS.',
      'CONSOLE_JSON=false',
    ],
    [
      'CONSOLE_JSON_STRING_LENGTH',
      'number',
      'Configure the truncation size for string values in JSON console/stdout logs. Default: 255.',
      '# CONSOLE_JSON_STRING_LENGTH=255',
    ],
    [
      'LIBRECHAT_LOG_DIR',
      'string',
      'Custom directory for log files. Defaults to /app/logs (Docker) or api/logs (local dev).',
      '# LIBRECHAT_LOG_DIR=/custom/log/path',
    ],
    [
      'MEM_DIAG',
      'boolean',
      'Enable memory diagnostics — logs heap/RSS snapshots every 60 seconds. Auto-enabled when running with --inspect.',
      '# MEM_DIAG=true',
    ],
    [
      'AGENT_DEBUG_LOGGING',
      'boolean',
      'Enables verbose debug logging in the agent controller (token counts, context pruning diagnostics).',
      '# AGENT_DEBUG_LOGGING=true',
    ],
  ]}
/>

Note:

- `DEBUG_LOGGING` can be used with either `DEBUG_CONSOLE` or `CONSOLE_JSON` but not both.
- `DEBUG_CONSOLE` and `CONSOLE_JSON` are mutually exclusive.
- `CONSOLE_LOG_LEVEL=silent` disables console output without disabling file logging. Invalid values fall back to the normal default and emit a warning.
- `CONSOLE_JSON`: When handling console logs in cloud deployments (such as GCP or AWS), enabling this will dump the logs with a UTC timestamp and format them as JSON.
  - See: [feat: Add CONSOLE_JSON](https://github.com/danny-avila/LibreChat/pull/2146)

Note: `DEBUG_CONSOLE` is not recommended, as the outputs can be quite verbose, and so it's disabled by default.

### Permission

> UID and GID are numbers assigned by Linux to each user and group on the system. If you have permission problems, set here the UID and GID of the user running the Docker Compose command. The applications in the container will run with these UID/GID.

<OptionTable
  options={[
    ['UID', 'number', 'The user ID.', '# UID=1000'],
    ['GID', 'number', 'The group ID.', '# GID=1000'],
  ]}
/>

### Langfuse Tracing and Tenant Fanout

Use the standard Langfuse variables for one central observability project. The optional fanout deployment can additionally route tenant traces, media, and feedback scores to tenant-specific Langfuse projects. See [Langfuse Tracing](/docs/configuration/langfuse) for setup, in-app connection management, and architecture.

<OptionTable
  options={[
    ['LANGFUSE_PUBLIC_KEY', 'string', 'Public key for the central Langfuse project.', '# LANGFUSE_PUBLIC_KEY='],
    ['LANGFUSE_SECRET_KEY', 'string', 'Secret key for the central Langfuse project.', '# LANGFUSE_SECRET_KEY='],
    ['LANGFUSE_BASE_URL', 'string', 'Base URL for central tracing and feedback scores.', '# LANGFUSE_BASE_URL=https://cloud.langfuse.com'],
    ['LANGFUSE_PROJECT_ID', 'string', 'Stable central Langfuse project ID. When omitted, LibreChat discovers and caches it in the background for feedback routing.', '# LANGFUSE_PROJECT_ID='],
    ['LANGFUSE_TRACING_ENABLED', 'boolean', 'Set to false to disable Langfuse traces and feedback scores. Default: true.', '# LANGFUSE_TRACING_ENABLED=true'],
    ['LANGFUSE_SAMPLE_RATE', 'number', 'Deterministic trace-level sample rate from 0 to 1. Sampled-out traces do not receive feedback scores. Default: 1.', '# LANGFUSE_SAMPLE_RATE=1'],
    ['LANGFUSE_FANOUT_ENABLED', 'boolean', 'Enable routing through the optional fanout gateway.', '# LANGFUSE_FANOUT_ENABLED=false'],
    ['LANGFUSE_FANOUT_COLLECTOR_URL', 'string', 'Gateway URL used by the LibreChat API.', '# LANGFUSE_FANOUT_COLLECTOR_URL=http://langfuse-fanout-collector:4318'],
    ['LANGFUSE_FANOUT_CENTRAL_MEDIA_UPLOAD_DISABLED', 'boolean', 'Prevent the LibreChat SDK from creating media uploads for central or fallback collector traces. Tenant-routed media uploads are unchanged.', '# LANGFUSE_FANOUT_CENTRAL_MEDIA_UPLOAD_DISABLED=false'],
    ['LANGFUSE_FANOUT_LISTEN_ADDR', 'string', 'Gateway HTTP listen address. Default: :4318.', '# LANGFUSE_FANOUT_LISTEN_ADDR=:4318'],
    ['LANGFUSE_FANOUT_TENANT_EXPORT_DISABLED', 'boolean', 'Emergency switch that disables tenant trace and score export while retaining central export.', '# LANGFUSE_FANOUT_TENANT_EXPORT_DISABLED=false'],
    ['LANGFUSE_FANOUT_CENTRAL_BASE_URL', 'string', 'Central Langfuse base URL used by the gateway.', '# LANGFUSE_FANOUT_CENTRAL_BASE_URL=https://cloud.langfuse.com'],
    ['LANGFUSE_FANOUT_CENTRAL_AUTH_HEADER', 'string', 'Full Basic authorization header for central trace and media export.', '# LANGFUSE_FANOUT_CENTRAL_AUTH_HEADER=Basic <base64-public-colon-secret>'],
    ['LANGFUSE_FANOUT_CENTRAL_MEDIA_EXPORT_DISABLED', 'boolean', 'Disable central media fanout without disabling central traces.', '# LANGFUSE_FANOUT_CENTRAL_MEDIA_EXPORT_DISABLED=false'],
    ['LANGFUSE_FANOUT_TENANT_DESTINATIONS', 'string', 'Comma-separated destination key and base URL mappings allowed at startup.', '# LANGFUSE_FANOUT_TENANT_DESTINATIONS=eu=https://cloud.langfuse.com,us=https://us.cloud.langfuse.com'],
    ['LANGFUSE_FANOUT_TRACE_DESTINATION_KEYS', 'string', 'Destination keys supported by the collector routing configuration.', '# LANGFUSE_FANOUT_TRACE_DESTINATION_KEYS=eu,us,jp'],
    ['LANGFUSE_FANOUT_PUBLIC_URL', 'string', 'Gateway base URL used to create one-time media upload URLs.', '# LANGFUSE_FANOUT_PUBLIC_URL=http://langfuse-fanout-collector:4318'],
    ['LANGFUSE_FANOUT_TRACE_COLLECTOR_URL', 'string', 'Internal gateway-to-collector trace endpoint.', '# LANGFUSE_FANOUT_TRACE_COLLECTOR_URL=http://langfuse-fanout-otel:4319'],
    ['LANGFUSE_FANOUT_REDIS_URI', 'string', 'Redis URI for one-time media upload plans.', '# LANGFUSE_FANOUT_REDIS_URI=redis://langfuse-fanout-redis:6379'],
    ['LANGFUSE_FANOUT_REDIS_USERNAME', 'string', 'Optional Redis username for the fanout gateway.', '# LANGFUSE_FANOUT_REDIS_USERNAME='],
    ['LANGFUSE_FANOUT_REDIS_PASSWORD', 'string', 'Optional Redis password for the fanout gateway.', '# LANGFUSE_FANOUT_REDIS_PASSWORD='],
    ['LANGFUSE_FANOUT_REDIS_KEY_PREFIX', 'string', 'Redis key prefix for fanout media plans.', '# LANGFUSE_FANOUT_REDIS_KEY_PREFIX=langfuse-fanout'],
    ['LANGFUSE_FANOUT_OTEL_RECEIVER_ENDPOINT', 'string', 'Internal collector receiver bind address.', '# LANGFUSE_FANOUT_OTEL_RECEIVER_ENDPOINT=0.0.0.0:4319'],
    ['LANGFUSE_FANOUT_TENANT_EU_BASE_URL', 'string', 'Static EU destination URL for the included Compose collector.', '# LANGFUSE_FANOUT_TENANT_EU_BASE_URL=https://cloud.langfuse.com'],
    ['LANGFUSE_FANOUT_TENANT_US_BASE_URL', 'string', 'Static US destination URL for the included Compose collector.', '# LANGFUSE_FANOUT_TENANT_US_BASE_URL=https://us.cloud.langfuse.com'],
    ['LANGFUSE_FANOUT_TENANT_JP_BASE_URL', 'string', 'Static JP destination URL for the included Compose collector.', '# LANGFUSE_FANOUT_TENANT_JP_BASE_URL=https://jp.cloud.langfuse.com'],
    ['LANGFUSE_FANOUT_UPSTREAM_TIMEOUT', 'duration', 'Timeout for gateway requests to Langfuse and media upload URLs.', '# LANGFUSE_FANOUT_UPSTREAM_TIMEOUT=30s'],
    ['LANGFUSE_FANOUT_METRICS_SECRET', 'string', 'Bearer token required to scrape the gateway metrics endpoint.', '# LANGFUSE_FANOUT_METRICS_SECRET='],
    ['LANGFUSE_FANOUT_MEMORY_LIMIT_MIB', 'number', 'Collector memory limit in MiB.', '# LANGFUSE_FANOUT_MEMORY_LIMIT_MIB=256'],
    ['LANGFUSE_FANOUT_MEMORY_SPIKE_LIMIT_MIB', 'number', 'Collector memory spike allowance in MiB.', '# LANGFUSE_FANOUT_MEMORY_SPIKE_LIMIT_MIB=64'],
    ['LANGFUSE_FANOUT_BATCH_TIMEOUT', 'duration', 'Collector batch flush timeout.', '# LANGFUSE_FANOUT_BATCH_TIMEOUT=1s'],
    ['LANGFUSE_FANOUT_BATCH_SEND_SIZE', 'number', 'Collector batch send size.', '# LANGFUSE_FANOUT_BATCH_SEND_SIZE=128'],
    ['LANGFUSE_FANOUT_METADATA_CARDINALITY_LIMIT', 'number', 'Collector metadata cardinality limit.', '# LANGFUSE_FANOUT_METADATA_CARDINALITY_LIMIT=1000'],
  ]}
/>

In a single-tenant deployment without complete `LANGFUSE_PUBLIC_KEY` and `LANGFUSE_SECRET_KEY` environment credentials, an authorized administrator can configure one encrypted connection under **Settings → Langfuse**. Complete environment credentials take precedence and hide that setting. Fanout deployments use the same setting for the tenant connection when fanout and tenant export are enabled.

`LANGFUSE_BASE_URL` is canonical. `LANGFUSE_HOST` and `LANGFUSE_BASEURL` remain compatibility aliases and are consulted in that order only when the canonical setting is absent.

### OpenTelemetry Tracing

LibreChat can emit backend OpenTelemetry traces for general API, HTTP, MongoDB, Mongoose, Redis, and outbound request visibility. Redis command-level spans are opt-in so default traces stay high-level. Use Langfuse for GenAI-specific prompt/model observability.

<OptionTable
  options={[
    [
      'OTEL_TRACING_ENABLED',
      'boolean',
      'Enable backend OpenTelemetry tracing. Tracing remains disabled when OTEL_SDK_DISABLED=true.',
      '# OTEL_TRACING_ENABLED=false',
    ],
    [
      'OTEL_SERVICE_NAME',
      'string',
      'Service name reported to OpenTelemetry. Default: librechat.',
      '# OTEL_SERVICE_NAME=librechat',
    ],
    [
      'OTEL_SERVICE_VERSION',
      'string',
      'Service version reported to OpenTelemetry. Defaults to the package version when unset.',
      '# OTEL_SERVICE_VERSION=',
    ],
    [
      'OTEL_EXPORTER_OTLP_ENDPOINT',
      'string',
      'Base OTLP exporter endpoint.',
      '# OTEL_EXPORTER_OTLP_ENDPOINT=http://localhost:4318',
    ],
    [
      'OTEL_EXPORTER_OTLP_TRACES_ENDPOINT',
      'string',
      'Trace-specific OTLP endpoint. Overrides the base endpoint for traces when set.',
      '# OTEL_EXPORTER_OTLP_TRACES_ENDPOINT=',
    ],
    [
      'OTEL_EXPORTER_OTLP_HEADERS',
      'string',
      'Comma-separated OTLP exporter headers, such as authorization metadata.',
      '# OTEL_EXPORTER_OTLP_HEADERS=',
    ],
    ['OTEL_TRACES_EXPORTER', 'string', 'Trace exporter selection.', '# OTEL_TRACES_EXPORTER=otlp'],
    [
      'OTEL_TRACES_SAMPLER',
      'string',
      'OpenTelemetry trace sampler. Default example: parentbased_always_on.',
      '# OTEL_TRACES_SAMPLER=parentbased_always_on',
    ],
    ['OTEL_LOG_LEVEL', 'string', 'OpenTelemetry SDK log level.', '# OTEL_LOG_LEVEL=INFO'],
    [
      'OTEL_SDK_DISABLED',
      'boolean',
      'Disable the OpenTelemetry SDK even if tracing is enabled.',
      '# OTEL_SDK_DISABLED=false',
    ],
    [
      'OTEL_IOREDIS_TRACING_ENABLED',
      'boolean',
      'Enable Redis command-level spans. Disabled by default to keep backend traces high-level.',
      '# OTEL_IOREDIS_TRACING_ENABLED=false',
    ],
  ]}
/>

### Real User Monitoring (Browser)

LibreChat can publish browser Real User Monitoring (RUM) telemetry to HyperDX-compatible OTLP collectors. RUM is disabled by default.

<OptionTable
  options={[
    [
      'RUM_ENABLED',
      'boolean',
      'Enable browser Real User Monitoring. Default: false.',
      '# RUM_ENABLED=false',
    ],
    [
      'RUM_PROVIDER',
      'string',
      'Browser RUM provider. Currently supports `hyperdx`.',
      '# RUM_PROVIDER=hyperdx',
    ],
    [
      'RUM_URL',
      'string',
      'Public collector URL used by public-token mode.',
      '# RUM_URL=http://localhost:4318',
    ],
    [
      'RUM_SERVICE_NAME',
      'string',
      'Service name reported by the browser SDK. Default: librechat-web.',
      '# RUM_SERVICE_NAME=librechat-web',
    ],
    [
      'RUM_ENVIRONMENT',
      'string',
      'Environment label reported with browser telemetry.',
      '# RUM_ENVIRONMENT=development',
    ],
    [
      'RUM_AUTH_MODE',
      'string',
      'Authentication mode for browser telemetry. Use `publicToken` or `proxy`.',
      '# RUM_AUTH_MODE=publicToken',
    ],
    [
      'RUM_PUBLIC_TOKEN',
      'string',
      'Public browser token for public-token mode. Treat this as public and restrict ingestion at the collector.',
      '# RUM_PUBLIC_TOKEN=',
    ],
    [
      'RUM_PROXY_TARGET_URL',
      'string',
      'Collector base URL used by authenticated proxy mode. Required when `RUM_AUTH_MODE=proxy`.',
      '# RUM_PROXY_TARGET_URL=http://otel-collector:4318',
    ],
    [
      'RUM_PROXY_TIMEOUT_MS',
      'number',
      'Proxy request timeout in milliseconds. Default: 10000.',
      '# RUM_PROXY_TIMEOUT_MS=10000',
    ],
    [
      'RUM_TRACE_PROPAGATION_TARGETS',
      'string',
      'Comma-separated first-party HTTPS origins or URLs that should receive traceparent headers.',
      '# RUM_TRACE_PROPAGATION_TARGETS=https://api.example.com',
    ],
    [
      'RUM_DISABLE_REPLAY',
      'boolean',
      'Disable browser session replay. Default: true.',
      '# RUM_DISABLE_REPLAY=true',
    ],
    [
      'RUM_CONSOLE_CAPTURE',
      'boolean',
      'Capture browser console logs. May collect sensitive prompts, responses, or payloads.',
      '# RUM_CONSOLE_CAPTURE=false',
    ],
    [
      'RUM_ADVANCED_NETWORK_CAPTURE',
      'boolean',
      'Capture detailed network payloads. May collect sensitive prompts, responses, or payloads.',
      '# RUM_ADVANCED_NETWORK_CAPTURE=false',
    ],
    [
      'RUM_SAMPLE_RATE',
      'number',
      'Browser telemetry sample rate from 0 to 1. Default: 1.',
      '# RUM_SAMPLE_RATE=1',
    ],
  ]}
/>

In `publicToken` mode, the browser sends telemetry directly to `RUM_URL` with `RUM_PUBLIC_TOKEN`. In `proxy` mode, the browser sends telemetry through LibreChat; the backend validates the user session, strips app authentication headers, and forwards telemetry to `RUM_PROXY_TARGET_URL`. Invalid or expired sessions are dropped with a `204` response so browser telemetry failures do not surface normal API authentication errors. Proxy outcomes are counted in `rum_proxy_requests_total` with `endpoint` and `result` labels on the LibreChat API `/metrics` endpoint.

For sampled page loads, LibreChat emits one `page-load-diagnostics` action when First Contentful Paint is observed. It includes navigation timing attribution such as time to first byte, first-byte-to-FCP time, service-worker timing, navigation type, and a normalized route instead of raw conversation IDs. RUM also records early page lifecycle, service-worker, stale-asset recovery, and single-page-app route-change events. Diagnostics are best-effort and never delay startup or trigger recovery behavior; early events are discarded when the page is not sampled.

### Configuration Path - `librechat.yaml`

Specify an alternative location for the LibreChat configuration file.
You may specify an **absolute path**, a **relative path**, or a **URL**. The filename in the path is flexible and does not have to be `librechat.yaml`; any valid configuration file will work.

> **Note**: If you prefer LibreChat to search for the configuration file in the root directory (which is the default behavior), simply leave this option commented out.

<OptionTable
  options={[
    [
      'CONFIG_PATH',
      'string',
      'An alternative location for the LibreChat configuration file.',
      '# CONFIG_PATH=https://raw.githubusercontent.com/danny-avila/LibreChat/main/librechat.example.yaml',
    ],
  ]}
/>

### Deployment Skills

Deployment Skills are loaded read-only at startup from the filesystem and exposed to users who have the Skills capability enabled.

<OptionTable
  options={[
    [
      'DEPLOYMENT_SKILLS_DIR',
      'string',
      'Directory containing deployment-provided Skills. Defaults to `./skill` at the project root.',
      '# DEPLOYMENT_SKILLS_DIR=./skill',
    ],
  ]}
/>

Restart LibreChat after changing this directory or any files inside it. Deployment-provided Skills take precedence over persisted Skills with the same name.

### Agent Plugins (Experimental)

LibreChat can load experimental Agent Plugins from immediate child directories at startup. A plugin can bundle deployment Skills, MCP servers, and optional command hooks.

<OptionTable
  options={[
    [
      'DEPLOYMENT_PLUGINS_DIR',
      'string',
      'Directory containing Agent Plugin packages. Defaults to `./plugin` at the project root.',
      '# DEPLOYMENT_PLUGINS_DIR=./plugin',
    ],
    [
      'DEPLOYMENT_PLUGIN_DATA_DIR',
      'string',
      'Persistent data root for Agent Plugins. Defaults to `./data/plugins` at the project root.',
      '# DEPLOYMENT_PLUGIN_DATA_DIR=./data/plugins',
    ],
    [
      'DEPLOYMENT_PLUGIN_HOOKS',
      'boolean',
      'Runs trusted `command` handlers declared in `ai.librechat/hooks/hooks.json`. Disabled by default. Commands execute as child processes on the API host.',
      '# DEPLOYMENT_PLUGIN_HOOKS=true',
    ],
  ]}
/>

See [Agent Plugins](/docs/features/agent_plugins) for package layout, schema versions, supported components, precedence, and current limitations.

### Configuration Validation

By default, LibreChat will exit with an error (exit code 1) if the `librechat.yaml` configuration file contains validation errors. This fail-fast behavior helps catch configuration issues early in deployment pipelines and prevents running with unintended default settings.

<OptionTable
  options={[
    [
      'CONFIG_BYPASS_VALIDATION',
      'boolean',
      'When set to `true`, the server will log a warning and continue starting with default configuration even if `librechat.yaml` has validation errors. This preserves the legacy behavior.',
      '# CONFIG_BYPASS_VALIDATION=true',
    ],
  ]}
/>

<Callout type="warning" title="Warning">
  Using `CONFIG_BYPASS_VALIDATION=true` is not recommended for production environments. It is
  intended as a temporary workaround while debugging configuration issues. Always fix validation
  errors in your configuration file.
</Callout>

### Uncaught Exception Handling

By default, LibreChat will exit the process when an uncaught exception occurs, which is the standard Node.js behavior. You can override this to keep the app running after uncaught exceptions.

<OptionTable
  options={[
    [
      'CONTINUE_ON_UNCAUGHT_EXCEPTION',
      'boolean',
      'When set to `true`, the app will continue running after encountering uncaught exceptions instead of exiting the process.',
      '# CONTINUE_ON_UNCAUGHT_EXCEPTION=false',
    ],
  ]}
/>

<Callout type="warning" title="Warning">
  Not recommended for production unless necessary. Uncaught exceptions may leave the application in
  an unpredictable state.
</Callout>

## Endpoints

In this section, you can configure the endpoints and models selection, their API keys, and the proxy and reverse proxy settings for the endpoints that support it.

### General Config

Uncomment `ENDPOINTS` to customize the available endpoints in LibreChat.

<OptionTable
  options={[
    [
      'ENDPOINTS',
      'string',
      'Comma-separated list of available endpoints.',
      '# ENDPOINTS=openAI,agents,assistants,gptPlugins,azureOpenAI,google,anthropic,bingAI,custom',
    ],
    [
      'PROXY',
      'string',
      'Outbound proxy for supported server-side clients. Applies to both HTTP and HTTPS targets.',
      'PROXY=',
    ],
    [
      'HTTP_PROXY',
      'string',
      'HTTP proxy fallback used by supported server-side clients when PROXY is unset.',
      '# HTTP_PROXY=',
    ],
    [
      'HTTPS_PROXY',
      'string',
      'HTTPS proxy fallback used by supported server-side clients when PROXY is unset.',
      '# HTTPS_PROXY=',
    ],
    [
      'NO_PROXY',
      'string',
      'Comma-separated hosts, domains, or IP ranges that supported server-side clients should bypass. The lowercase no_proxy variant is also honored.',
      '# NO_PROXY=',
    ],
    ['TITLE_CONVO', 'boolean', 'Enable titling for all endpoints.', 'TITLE_CONVO=true'],
  ]}
/>

### Known Endpoints - `librechat.yaml`

- see also: [Custom Endpoints & Configuration](/docs/configuration/librechat_yaml)

<OptionTable
  options={[
    ['ANYSCALE_API_KEY', 'string', 'API key for Anyscale.', '# ANYSCALE_API_KEY='],
    ['APIPIE_API_KEY', 'string', 'API key for Apipie.', '# APIPIE_API_KEY='],
    ['COHERE_API_KEY', 'string', 'API key for Cohere.', '# COHERE_API_KEY='],
    ['FIREWORKS_API_KEY', 'string', 'API key for Fireworks.', '# FIREWORKS_API_KEY='],
    ['GROQ_API_KEY', 'string', 'API key for Groq.', '# GROQ_API_KEY='],
    ['MISTRAL_API_KEY', 'string', 'API key for Mistral.', '# MISTRAL_API_KEY='],
    ['OPENROUTER_KEY', 'string', 'API key for OpenRouter.', '# OPENROUTER_KEY='],
    ['PERPLEXITY_API_KEY', 'string', 'API key for Perplexity.', '# PERPLEXITY_API_KEY='],
    ['SHUTTLEAI_API_KEY', 'string', 'API key for ShuttleAI.', '# SHUTTLEAI_API_KEY='],
    ['TOGETHERAI_API_KEY', 'string', 'API key for TogetherAI.', '# TOGETHERAI_API_KEY='],
    ['DEEPSEEK_API_KEY', 'string', 'API key for Deepseek API', '# DEEPSEEK_API_KEY='],
  ]}
/>

### Web Search

The web search feature enables internet search capabilities within LibreChat.

**Important**: The exact environment variable names shown below are default references and can be customized through the `librechat.yaml` configuration file to use any variable names you prefer.

For detailed configuration and customization options, see: [Web Search Configuration](/docs/configuration/librechat_yaml/object_structure/web_search)

<OptionTable
  options={[
    [
      'SERPER_API_KEY',
      'string',
      'API key for Serper search provider. Get your key from https://serper.dev/api-keys',
      '# SERPER_API_KEY=',
    ],
    [
      'TAVILY_API_KEY',
      'string',
      'API key for Tavily search and scraper provider. Get your key from https://app.tavily.com/home',
      '# TAVILY_API_KEY=',
    ],
    [
      'TAVILY_SEARCH_URL',
      'string',
      'Custom Tavily Search API URL (optional). Only needed for custom or proxy Tavily-compatible search endpoints.',
      '# TAVILY_SEARCH_URL=',
    ],
    [
      'TAVILY_EXTRACT_URL',
      'string',
      'Custom Tavily Extract API URL (optional). Only needed for custom or proxy Tavily-compatible extract endpoints.',
      '# TAVILY_EXTRACT_URL=',
    ],
    [
      'KEENABLE_API_KEY',
      'string',
      'Optional Keenable API key for search and page fetch. Public endpoints work keyless; a key raises their rate limits.',
      '# KEENABLE_API_KEY=',
    ],
    [
      'KEENABLE_API_URL',
      'string',
      'Optional custom Keenable search API URL.',
      '# KEENABLE_API_URL=',
    ],
    [
      'KEENABLE_FETCH_URL',
      'string',
      'Optional custom Keenable page-fetch API URL used when scraperProvider is keenable.',
      '# KEENABLE_FETCH_URL=',
    ],
    [
      'FIRECRAWL_API_KEY',
      'string',
      'API key for Firecrawl scraper service. Get your key from https://docs.firecrawl.dev/introduction#api-key',
      '# FIRECRAWL_API_KEY=',
    ],
    [
      'FIRECRAWL_API_URL',
      'string',
      'Custom Firecrawl API URL (optional). Only needed for custom Firecrawl instances.',
      '# FIRECRAWL_API_URL=',
    ],
    ['FIRECRAWL_VERSION', 'string', 'Firecrawl API version (v0 or v1).', '# FIRECRAWL_VERSION=v1'],
    [
      'JINA_API_KEY',
      'string',
      'API key for Jina reranker service. Get your key from https://jina.ai/api-dashboard/',
      '# JINA_API_KEY=',
    ],
    [
      'JINA_API_URL',
      'string',
      'Custom Jina API URL (optional). Only needed for custom Jina instances.',
      '# JINA_API_URL=',
    ],
    [
      'COHERE_API_KEY',
      'string',
      'API key for Cohere reranker service. Get your key from https://dashboard.cohere.com/welcome/login',
      '# COHERE_API_KEY=',
    ],
  ]}
/>

**Note**: Most variable names can be customized in your `librechat.yaml` configuration file. For example, you could use `CUSTOM_SERPER_KEY` instead of `SERPER_API_KEY` by configuring it in the web search settings. `KEENABLE_FETCH_URL` is environment-only. See the [Web Search Configuration](/docs/configuration/librechat_yaml/object_structure/web_search) documentation for details.

### Anthropic

see: [Anthropic Endpoint](/docs/configuration/pre_configured_ai/anthropic)

- You can request an access key from https://platform.claude.com/
- Leave `ANTHROPIC_API_KEY=` blank to disable this endpoint
- Set `ANTHROPIC_API_KEY=` to "user_provided" to allow users to provide their own API key from the WebUI
- If you have access to a reverse proxy for `Anthropic`, you can set it with `ANTHROPIC_REVERSE_PROXY=`
  - leave blank or comment it out to use default base url

<OptionTable
  options={[
    [
      'ANTHROPIC_API_KEY',
      'string',
      'Anthropic API key or "user_provided" to allow users to provide their own API key.',
      'Defaults to an empty string.',
    ],
    [
      'ANTHROPIC_MODELS',
      'string',
      'Comma-separated list of Anthropic models to use.',
      '# ANTHROPIC_MODELS=claude-fable-5-1,claude-fable-5,claude-opus-5,claude-opus-4-8,claude-opus-4-7,claude-sonnet-5,claude-sonnet-4-6,claude-opus-4-6,claude-opus-4-20250514,claude-3-7-sonnet-20250219,claude-3-5-sonnet-20241022,claude-3-5-haiku-20241022',
    ],
    [
      'ANTHROPIC_REVERSE_PROXY',
      'string',
      'Reverse proxy for Anthropic.',
      '# ANTHROPIC_REVERSE_PROXY=',
    ],
    [
      'ANTHROPIC_TITLE_MODEL',
      'string',
      'DEPRECATED: Model to use for titling with Anthropic.',
      '# ANTHROPIC_TITLE_MODEL=claude-3-haiku-20240307',
    ],
  ]}
/>

- `ANTHROPIC_TITLE_MODEL` is now deprecated and will be removed in future versions. Use the [`titleModel` Endpoint Setting](/docs/configuration/librechat_yaml/object_structure/shared_endpoint_settings#titlemodel) instead in the `librechat.yaml` config instead.

> **Note:** Must be compatible with the Anthropic Endpoint. Also, Claude 2 and Claude 3 models perform best at this task, with `claude-3-haiku` models being the cheapest.

Claude Fable 5.1 and Fable 5 are included in the default Anthropic model list. Fable/Mythos-class
models use the modern Anthropic behavior in LibreChat: 1M context, adaptive thinking
support, prompt caching support, and `thinkingDisplay` handling for summarized or
omitted reasoning output.

#### Anthropic via Vertex AI

You can also use Anthropic Claude models through Google Cloud Vertex AI. For detailed YAML configuration options, see: [Anthropic Vertex AI Configuration](/docs/configuration/librechat_yaml/object_structure/anthropic_vertex)

<OptionTable
  options={[
    [
      'ANTHROPIC_USE_VERTEX',
      'boolean',
      'Set to true to use Anthropic models through Google Vertex AI instead of direct API.',
      'ANTHROPIC_USE_VERTEX=true',
    ],
    [
      'ANTHROPIC_VERTEX_REGION',
      'string',
      'The Google Cloud location for Vertex AI. Default: us-east5. Use global, us, or eu for Opus 4.7+, Opus 5, Sonnet 5, and Fable/Mythos 5.',
      'ANTHROPIC_VERTEX_REGION=global',
    ],
  ]}
/>

> **Note:** When using Vertex AI, you must also configure `GOOGLE_SERVICE_KEY_FILE` (see [Google Configuration](#google)) with a service account that has the `Vertex AI User` role.

### AWS Bedrock

See: [AWS Bedrock Setup](/docs/configuration/pre_configured_ai/bedrock)

<OptionTable
  options={[
    [
      'BEDROCK_AWS_DEFAULT_REGION',
      'string',
      'A default AWS region must be provided for Bedrock.',
      'BEDROCK_AWS_DEFAULT_REGION=us-east-1',
    ],
    [
      'BEDROCK_AWS_ACCESS_KEY_ID',
      'string',
      'AWS access key ID for Bedrock. Optional if using default AWS credentials chain.',
      '# BEDROCK_AWS_ACCESS_KEY_ID=your_access_key_id',
    ],
    [
      'BEDROCK_AWS_SECRET_ACCESS_KEY',
      'string',
      'AWS secret access key for Bedrock. Optional if using default AWS credentials chain.',
      '# BEDROCK_AWS_SECRET_ACCESS_KEY=your_secret_access_key',
    ],
    [
      'BEDROCK_AWS_SESSION_TOKEN',
      'string',
      'AWS session token for temporary credentials. Optional.',
      '# BEDROCK_AWS_SESSION_TOKEN=your_session_token',
    ],
    [
      'BEDROCK_AWS_PROFILE',
      'string',
      'AWS shared config profile name for Bedrock. Optional if using the default AWS credentials chain.',
      '# BEDROCK_AWS_PROFILE=your-profile-name',
    ],
    [
      'BEDROCK_AWS_BEARER_TOKEN',
      'string',
      'Amazon Bedrock API key for bearer auth, or user_provided to let users enter their own Bedrock API key in the UI.',
      '# BEDROCK_AWS_BEARER_TOKEN=your_bedrock_api_key',
    ],
    [
      'BEDROCK_AWS_MODELS',
      'string',
      'Comma-separated list of Bedrock model IDs. If omitted, all known supported models are included.',
      '# BEDROCK_AWS_MODELS=global.anthropic.claude-fable-5-1,global.anthropic.claude-fable-5,global.anthropic.claude-opus-5,global.anthropic.claude-opus-4-8,global.anthropic.claude-opus-4-7,global.anthropic.claude-sonnet-5,global.anthropic.claude-sonnet-4-6,meta.llama3-1-8b-instruct-v1:0',
    ],
  ]}
/>

> **Note:** You can omit the access keys to use the default AWS credentials chain (environment variables, SSO credentials, shared credentials files, or EC2/ECS Instance Metadata Service). See [AWS Bedrock Setup](/docs/configuration/pre_configured_ai/bedrock) for more details.

Claude Fable/Mythos-class models on Bedrock are inference-profile only. Use a profile
ID such as `global.anthropic.claude-fable-5-1`, and enable the required Anthropic data
sharing setting in the Bedrock console or Data Retention API before invoking them.

### BingAI

Bing, also used for Sydney, jailbreak, and Bing Image Creator

<OptionTable
  options={[
    [
      'BINGAI_TOKEN',
      'string',
      'Bing access token. Leave blank to disable. Can be set to "user_provided" to allow users to provide their own token from the WebUI.',
      'BINGAI_TOKEN=user_provided',
    ],
    [
      'BINGAI_HOST',
      'string',
      'Bing host URL. Leave commented out to use default server.',
      '# BINGAI_HOST=https://cn.bing.com',
    ],
  ]}
/>

Note: It is recommended to leave it as "user_provided" and provide the token from the WebUI.

### Google

Follow these instructions to setup the [Google Endpoint](/docs/configuration/pre_configured_ai/google)

<OptionTable
  options={[
    [
      'GOOGLE_KEY',
      'string',
      'Google API key. Set to "user_provided" to allow users to provide their own API key from the WebUI.',
      'GOOGLE_KEY=user_provided',
    ],
    [
      'GOOGLE_SERVICE_KEY_FILE',
      'string',
      'Path to Google service account JSON key file, URL to fetch it from, or stringified JSON. Used for Vertex AI authentication (e.g., OCR features).',
      'GOOGLE_SERVICE_KEY_FILE=/path/to/auth.json',
    ],
    ['GOOGLE_REVERSE_PROXY', 'string', 'Google reverse proxy URL.', 'GOOGLE_REVERSE_PROXY='],
    [
      'GOOGLE_AUTH_HEADER',
      'boolean',
      'Use Authorization header instead of X-goog-api-key. Some reverse proxies require this.',
      '# GOOGLE_AUTH_HEADER=true',
    ],
    [
      'GOOGLE_MODELS',
      'string',
      'Available Gemini API Google models, separated by commas.',
      'GOOGLE_MODELS=gemini-3.8-flash,gemini-3.7-flash,gemini-3.6-flash,gemini-3.5-flash,gemini-3.5-flash-lite,gemini-3.1-pro-preview,gemini-3.1-pro-preview-customtools,gemini-3.1-flash-lite-preview,gemini-2.5-pro,gemini-2.5-flash,gemini-2.5-flash-lite,gemini-2.0-flash,gemini-2.0-flash-lite',
    ],
    [
      'GOOGLE_MODELS',
      'string',
      'Available Vertex AI Google models, separated by commas.',
      'GOOGLE_MODELS=gemini-3.8-flash,gemini-3.7-flash,gemini-3.6-flash,gemini-3.5-flash,gemini-3.5-flash-lite,gemini-3.1-pro-preview,gemini-3.1-pro-preview-customtools,gemini-3.1-flash-lite-preview,gemini-2.5-pro,gemini-2.5-flash,gemini-2.5-flash-lite,gemini-2.0-flash-001,gemini-2.0-flash-lite-001',
    ],
    [
      'GOOGLE_TITLE_MODEL',
      'string',
      'DEPRECATED: The model used for titling with Google.',
      'GOOGLE_TITLE_MODEL=gemini-pro',
    ],
    [
      'GOOGLE_LOC',
      'string',
      'Specifies the Google Cloud location for processing API requests',
      'GOOGLE_LOC=us-central1',
    ],
    [
      'GOOGLE_CLOUD_LOCATION',
      'string',
      'Alternative region for Gemini Image Generation (e.g., global).',
      '# GOOGLE_CLOUD_LOCATION=global',
    ],
    [
      'GOOGLE_EXCLUDE_SAFETY_SETTINGS',
      'string',
      'Completely omit the safety settings that are included by default, which will use provider defaults',
      'GOOGLE_EXCLUDE_SAFETY_SETTINGS=true',
    ],
    [
      'GOOGLE_SAFETY_SEXUALLY_EXPLICIT',
      'string',
      'Safety setting for sexually explicit content. Options are BLOCK_ALL, BLOCK_ONLY_HIGH, WARN_ONLY, and OFF.',
      'GOOGLE_SAFETY_SEXUALLY_EXPLICIT=BLOCK_ONLY_HIGH',
    ],
    [
      'GOOGLE_SAFETY_HATE_SPEECH',
      'string',
      'Safety setting for hate speech content. Options are BLOCK_ALL, BLOCK_ONLY_HIGH, WARN_ONLY, and OFF.',
      'GOOGLE_SAFETY_HATE_SPEECH=BLOCK_ONLY_HIGH',
    ],
    [
      'GOOGLE_SAFETY_HARASSMENT',
      'string',
      'Safety setting for harassment content. Options are BLOCK_ALL, BLOCK_ONLY_HIGH, WARN_ONLY, and OFF.',
      'GOOGLE_SAFETY_HARASSMENT=BLOCK_ONLY_HIGH',
    ],
    [
      'GOOGLE_SAFETY_DANGEROUS_CONTENT',
      'string',
      'Safety setting for dangerous content. Options are BLOCK_ALL, BLOCK_ONLY_HIGH, WARN_ONLY, and OFF.',
      'GOOGLE_SAFETY_DANGEROUS_CONTENT=BLOCK_ONLY_HIGH',
    ],
    [
      'GOOGLE_SAFETY_CIVIC_INTEGRITY',
      'string',
      'Safety setting for civic integrity content. Options are BLOCK_ALL, BLOCK_ONLY_HIGH, WARN_ONLY, and OFF.',
      '# GOOGLE_SAFETY_CIVIC_INTEGRITY=BLOCK_ONLY_HIGH',
    ],
  ]}
/>

Customize the available models, separated by commas, **without spaces**. The first will be default. Leave it blank or commented out to use internal settings.

- `GOOGLE_TITLE_MODEL` is now deprecated and will be removed in future versions. Use the [`titleModel` Endpoint Setting](/docs/configuration/librechat_yaml/object_structure/shared_endpoint_settings#titlemodel) instead in the `librechat.yaml` config instead.

**Note:** For the Vertex AI `GOOGLE_SAFETY` variables, you do not have access to the `BLOCK_NONE` setting by default. To use this restricted `HarmBlockThreshold` setting, you will need to either:

- (a) Get access through an allowlist via your Google account team
- (b) Switch your account type to monthly invoiced billing following this instruction:
  https://cloud.google.com/billing/docs/how-to/invoiced-billing

#### Gemini Image Generation

Gemini Image Generation is a tool for Agents that supports both the Gemini API and Vertex AI. See: [Gemini Image Generation](/docs/configuration/tools/gemini_image_gen)

<OptionTable
  options={[
    [
      'GEMINI_API_KEY',
      'string',
      'Dedicated Gemini API key for image generation. Falls back to GOOGLE_KEY if not set.',
      '# GEMINI_API_KEY=your_gemini_api_key',
    ],
    [
      'GEMINI_IMAGE_MODEL',
      'string',
      'Gemini model for image generation. Default: gemini-2.5-flash-image.',
      '# GEMINI_IMAGE_MODEL=gemini-2.5-flash-image',
    ],
  ]}
/>

> **Note:** When no API key is configured, the tool automatically falls back to Vertex AI using the service account from `GOOGLE_SERVICE_KEY_FILE`. The service account must have the `Vertex AI User` role.

### OpenAI

See: [OpenAI Setup](/docs/configuration/pre_configured_ai/openai)

<OptionTable
  options={[
    [
      'OPENAI_API_KEY',
      'string',
      'Your OpenAI API key. Leave blank to disable this endpoint or set to "user_provided" to allow users to provide their own API key from the WebUI.',
      'OPENAI_API_KEY=user_provided',
    ],
    [
      'OPENAI_MODELS',
      'string',
      'Customize the available models, separated by commas, without spaces. The first will be default. Leave commented out to use internal settings.',
      '# OPENAI_MODELS=gpt-5,gpt-5-codex,gpt-5-mini,gpt-5-nano,o3-pro,o3,o4-mini,gpt-4.1,gpt-4.1-mini,gpt-4.1-nano,o3-mini,o1-pro,o1,gpt-4o,gpt-4o-mini',
    ],
    ['DEBUG_OPENAI', 'boolean', 'Enable debug mode for the OpenAI endpoint.', 'DEBUG_OPENAI=false'],
    [
      'OPENAI_SUMMARIZE',
      'boolean',
      'Enable message summarization. False by default',
      '# OPENAI_SUMMARIZE=true',
    ],
    [
      'OPENAI_SUMMARY_MODEL',
      'string',
      'The model used for OpenAI summarization.',
      '# OPENAI_SUMMARY_MODEL=gpt-3.5-turbo',
    ],
    [
      'OPENAI_FORCE_PROMPT',
      'boolean',
      'Force the API to be called with a prompt payload instead of a messages payload.',
      '# OPENAI_FORCE_PROMPT=false',
    ],
    [
      'OPENAI_ORGANIZATION',
      'string',
      'Specify which organization to use for each API request to OpenAI. Optional',
      '# OPENAI_ORGANIZATION=',
    ],
    [
      'OPENAI_REVERSE_PROXY',
      'string',
      'DEPRECATED: Reverse proxy settings for OpenAI.',
      '# OPENAI_REVERSE_PROXY=',
    ],
    [
      'OPENAI_TITLE_MODEL',
      'string',
      'DEPRECATED: The model used for OpenAI titling.',
      '# OPENAI_TITLE_MODEL=gpt-3.5-turbo',
    ],
  ]}
/>

- `OPENAI_TITLE_MODEL` is now deprecated and will be removed in future versions. Use the [`titleModel` Endpoint Setting](/docs/configuration/librechat_yaml/object_structure/shared_endpoint_settings#titlemodel) instead in the `librechat.yaml` config instead.
- `OPENAI_REVERSE_PROXY` is now deprecated and will be removed in future versions. Use a [custom endpoint](/docs/quick_start/custom_endpoints) instead.

### Assistants

See: [Assistants Setup](/docs/configuration/pre_configured_ai/assistants)

<OptionTable
  options={[
    [
      'ASSISTANTS_API_KEY',
      'string',
      'Your OpenAI API key for Assistants API. Leave blank to disable this endpoint or set to "user_provided" to allow users to provide their own API key from the WebUI.',
      'ASSISTANTS_API_KEY=user_provided',
    ],
    [
      'ASSISTANTS_MODELS',
      'string',
      'Customize the available models, separated by commas, without spaces. The first will be default. Leave blank to use internal settings.',
      '# ASSISTANTS_MODELS=gpt-3.5-turbo-0125,gpt-3.5-turbo-16k-0613,gpt-3.5-turbo-16k,gpt-3.5-turbo,gpt-4,gpt-4-0314,gpt-4-32k-0314,gpt-4-0613,gpt-3.5-turbo-0613,gpt-3.5-turbo-1106,gpt-4-0125-preview,gpt-4-turbo-preview,gpt-4-1106-preview',
    ],
    [
      'ASSISTANTS_BASE_URL',
      'string',
      'Alternate base URL for Assistants API.',
      '# ASSISTANTS_BASE_URL=',
    ],
  ]}
/>

Note: You can customize the available models, separated by commas, without spaces. The first will be default. Leave it blank or commented out to use internal settings.

### Tavily

Get your API key here: **[https://tavily.com/#api](https://tavily.com/#api)**

**Environment Variables:**

<OptionTable options={[['TAVILY_API_KEY', 'string', 'Tavily API key.', 'TAVILY_API_KEY=']]} />

### Traversaal

**Description:** LLM-enhanced search tool.

Get API key here: **https://api.traversaal.ai/dashboard**

**Environment Variables:**

<OptionTable
  options={[['TRAVERSAAL_API_KEY', 'string', 'Traversaal API key.', 'TRAVERSAAL_API_KEY=']]}
/>

### WolframAlpha

See detailed instructions here: **[Wolfram Alpha](/docs/configuration/tools/wolfram)**

**Environment Variables:**

<OptionTable options={[['WOLFRAM_APP_ID', 'string', 'Wolfram Alpha App ID.', 'WOLFRAM_APP_ID=']]} />

### Zapier

**Description:** - You need a Zapier account. Get your API key from here: **[Zapier](https://nla.zapier.com/credentials/)**

- Create allowed actions - Follow step 3 in this getting start guide from Zapier

**Note:** Zapier is known to be finicky with certain actions. Writing email drafts is probably the best use of it.

**Environment Variables:**

<OptionTable
  options={[['ZAPIER_NLA_API_KEY', 'string', 'Zapier NLA API key.', 'ZAPIER_NLA_API_KEY=']]}
/>

### OpenWeather

See detailed instructions here: **[OpenWeather](/docs/configuration/tools/openweather)**

<OptionTable
  options={[
    [
      'OPENWEATHER_API_KEY',
      'string',
      'OpenWeather API key for the One Call API 3.0.',
      'OPENWEATHER_API_KEY=',
    ],
  ]}
/>

## File Uploads

<OptionTable
  options={[
    [
      'FILE_UPLOAD_SSE_ENABLED',
      'boolean',
      'Stream upload responses with heartbeat events during long-running file processing. Default: false.',
      '# FILE_UPLOAD_SSE_ENABLED=false',
    ],
    [
      'REMOTE_FILE_FETCH_TIMEOUT_MS',
      'number',
      'Timeout in milliseconds for server-side remote file downloads. Default: 15000.',
      '# REMOTE_FILE_FETCH_TIMEOUT_MS=15000',
    ],
    [
      'REMOTE_FILE_FETCH_MAX_BYTES',
      'number',
      'Maximum size in bytes for server-side remote file downloads. Default: 536870912 (512 MiB).',
      '# REMOTE_FILE_FETCH_MAX_BYTES=536870912',
    ],
  ]}
/>

With `FILE_UPLOAD_SSE_ENABLED=true`, clients that request `text/event-stream` receive one-second heartbeat events while upload processing is still running, followed by a `data` or `error` event and a final `close` event. Clients that do not request SSE continue to receive the normal JSON response. This is useful when a reverse proxy would otherwise close an idle connection during long OCR, parsing, or RAG work.

The remote fetch controls apply when LibreChat ingests an HTTP or HTTPS file URL into local, Firebase, Azure, or S3/CloudFront storage. LibreChat checks both a declared `Content-Length` and the bytes actually streamed, so the limit still applies when the remote server omits or misstates its length. These controls are independent of the per-upload limits in [`fileConfig`](/docs/configuration/librechat_yaml/object_structure/file_config).

## Code Interpreter

The Code Interpreter API provides a secure environment for executing code and managing files. See: [Code Interpreter API](/docs/features/code_interpreter)

<OptionTable
  options={[
    [
      'LIBRECHAT_CODE_API_KEY',
      'string',
      'API key for the Code Interpreter service. When set globally, provides access to all users.',
      'LIBRECHAT_CODE_API_KEY=your-api-key',
    ],
    [
      'LIBRECHAT_CODE_BASEURL',
      'string',
      'Base URL for the normal stateless Code Interpreter service.',
      '# LIBRECHAT_CODE_BASEURL=https://your-custom-domain.com',
    ],
    [
      'LIBRECHAT_CODE_BASEURL_STATEFUL',
      'string',
      'Default Code Interpreter base URL for highly experimental stateful Agent sessions when no named statefulCodeSessions environment is selected. The service must advertise the stateful profile.',
      '# LIBRECHAT_CODE_BASEURL_STATEFUL=https://your-stateful-code-domain.com',
    ],
    [
      'CODE_SANDBOX_PREWARM',
      'boolean',
      'Prewarm selected stateful sandboxes in parallel with model generation. Set to false to disable. Default: true.',
      '# CODE_SANDBOX_PREWARM=true',
    ],
    [
      'CODE_SANDBOX_COLD_AFTER_MS',
      'number',
      'Time in milliseconds before LibreChat treats a tracked sandbox as cold. Default: 2100000 (35 minutes).',
      '# CODE_SANDBOX_COLD_AFTER_MS=2100000',
    ],
    [
      'LIBRECHAT_CODE_SANDBOX_OUTPUT_MAX_SIZE',
      'number',
      "Sandbox stdout budget in bytes used to derive image-read window sizes. Match the runner's SANDBOX_OUTPUT_MAX_SIZE to minimize execution round trips. Default: 65536.",
      '# LIBRECHAT_CODE_SANDBOX_OUTPUT_MAX_SIZE=65536',
    ],
    [
      'LIBRECHAT_CODE_IMAGE_CHUNK_BYTES',
      'number',
      'Exact bytes read per sandbox image window. Overrides the size derived from LIBRECHAT_CODE_SANDBOX_OUTPUT_MAX_SIZE; leave unset unless an exact override is required.',
      '# LIBRECHAT_CODE_IMAGE_CHUNK_BYTES=',
    ],
    [
      'CODE_ENVIRONMENT_PAIRING_USER_MAX',
      'number',
      'Maximum self-service code-worker pairing requests per user during one rate-limit window. Default: 5.',
      '# CODE_ENVIRONMENT_PAIRING_USER_MAX=5',
    ],
    [
      'CODE_ENVIRONMENT_PAIRING_USER_WINDOW',
      'number',
      'Self-service code-worker pairing rate-limit window in minutes. Default: 60.',
      '# CODE_ENVIRONMENT_PAIRING_USER_WINDOW=60',
    ],
  ]}
/>

If a worker has a smaller stdout cap than configured, LibreChat narrows and remembers the image window for that Code Interpreter base URL after a failed read. Matching the two budgets avoids that discarded discovery request and reduces pressure on the Code Interpreter execution rate limit.

### Code Interpreter JWT Authentication

The current self-hosted [ClickHouse/code-interpreter](https://github.com/ClickHouse/code-interpreter) service verifies short-lived LibreChat bearer tokens outside local mode. Set `CODEAPI_AUTH_PROVIDER=librechat-jwt` to enable token minting, then give Code Interpreter the public key that matches LibreChat's private signer. See [Self-hosted JWT authentication](/docs/features/code_interpreter#self-hosted-jwt-authentication) for the paired service configuration and key-generation helper.

<OptionTable
  options={[
    [
      'CODEAPI_AUTH_PROVIDER',
      'string',
      'Set to librechat-jwt to mint per-user Code Interpreter bearer tokens. The compatibility value both also enables minting, but ClickHouse/code-interpreter expects librechat-jwt.',
      '# CODEAPI_AUTH_PROVIDER=librechat-jwt',
    ],
    [
      'CODEAPI_JWT_ENABLED',
      'boolean',
      'Explicitly enables Code Interpreter JWT minting when CODEAPI_AUTH_PROVIDER is not librechat-jwt or both. Default: false.',
      '# CODEAPI_JWT_ENABLED=true',
    ],
    [
      'CODEAPI_JWT_PRIVATE_KEY',
      'string',
      'Ed25519 or RSA private signing key in PEM format. Escaped \\n sequences are converted to newlines.',
      '# CODEAPI_JWT_PRIVATE_KEY="-----BEGIN PRIVATE KEY-----\\n..."',
    ],
    [
      'CODEAPI_JWT_PRIVATE_KEY_BASE64',
      'string',
      'Base64-encoded PEM private key. Used when CODEAPI_JWT_PRIVATE_KEY is unset.',
      '# CODEAPI_JWT_PRIVATE_KEY_BASE64=',
    ],
    [
      'CODEAPI_JWT_PRIVATE_JWK_JSON',
      'string',
      'Private signing key as JWK JSON. Used when both PEM settings are unset.',
      '# CODEAPI_JWT_PRIVATE_JWK_JSON={"kty":"OKP",...}',
    ],
    [
      'CODEAPI_JWT_ALGORITHM',
      'string',
      'Signing algorithm: EdDSA or RS256. Default: EdDSA.',
      '# CODEAPI_JWT_ALGORITHM=EdDSA',
    ],
    [
      'CODEAPI_JWT_KID',
      'string',
      'Signing-key ID included in the token header. Must identify the matching Code Interpreter verifier key. Default: lc-codeapi-2026-05.',
      '# CODEAPI_JWT_KID=lc-codeapi-2026-05',
    ],
    [
      'CODEAPI_JWT_ISSUER',
      'string',
      'Token issuer; must match Code Interpreter. Default: librechat.',
      '# CODEAPI_JWT_ISSUER=librechat',
    ],
    [
      'CODEAPI_JWT_AUDIENCE',
      'string',
      'Token audience; must match Code Interpreter. Default: codeapi.',
      '# CODEAPI_JWT_AUDIENCE=codeapi',
    ],
    [
      'CODEAPI_JWT_TTL_SECONDS',
      'number',
      'Bearer-token lifetime in seconds. Invalid or larger values resolve to the 300-second default and maximum.',
      '# CODEAPI_JWT_TTL_SECONDS=300',
    ],
    [
      'CODEAPI_JWT_MINT_CACHE_SECONDS',
      'number',
      'How long LibreChat can reuse a token for the same authenticated context. Default and maximum: 30 seconds.',
      '# CODEAPI_JWT_MINT_CACHE_SECONDS=30',
    ],
    [
      'CODEAPI_JWT_SINGLE_TENANT_ID',
      'string',
      'Fallback tenant ID when strict tenant isolation is disabled and no tenant context is available. Must match Code Interpreter. Default: legacy.',
      '# CODEAPI_JWT_SINGLE_TENANT_ID=legacy',
    ],
  ]}
/>

At least one private-key source is required when JWT minting is enabled. If more than one is set, LibreChat checks `CODEAPI_JWT_PRIVATE_KEY`, then `CODEAPI_JWT_PRIVATE_KEY_BASE64`, then `CODEAPI_JWT_PRIVATE_JWK_JSON`. `CODEAPI_JWT_KEY_ID` remains a compatibility alias for `CODEAPI_JWT_KID`.

For a multi-tenant deployment, enable `TENANT_ISOLATION_STRICT=true` in LibreChat and `CODEAPI_TENANT_ISOLATION_STRICT=true` in Code Interpreter. Requests without authenticated tenant context then fail instead of using `CODEAPI_JWT_SINGLE_TENANT_ID`.

### Stateful Code Interpreter Endpoint

[`stateful_code_sessions`](/docs/configuration/librechat_yaml/object_structure/agents#capabilities) is highly experimental and requires a separate Code Interpreter route. Configure the default route with `LIBRECHAT_CODE_BASEURL_STATEFUL`, or define named managed or attached backends under [`endpoints.agents.statefulCodeSessions.environments`](/docs/configuration/librechat_yaml/object_structure/agents#statefulcodesessions). The selected service must run the `stateful` profile; LibreChat sends `X-CodeAPI-Expected-Profile: stateful` with stateful requests.

Stateful requests never fall back to `LIBRECHAT_CODE_BASEURL`. If the selected named environment is unavailable, or neither a named default nor `LIBRECHAT_CODE_BASEURL_STATEFUL` is configured, LibreChat stops the Agent run with a configuration error. Stateless agents continue using `LIBRECHAT_CODE_BASEURL`, and the two execution profiles do not share a live workspace.

Each Agent can scope its stateful workspace to the signed-in user, the user and Agent together, or the user and conversation. See [Stateful Code Sessions](/docs/features/code_interpreter#stateful-code-sessions) for setup and persistence limitations.

Named attached environments can also expose a self-service pairing control plane with `pairing.allowPrincipalWorkers: true`. Authorized users manage those owner-bound workers under **Settings > Code environments**; pairing-only entries do not replace `LIBRECHAT_CODE_BASEURL_STATEFUL` and cannot serve as the deployment default.

## Artifacts

Artifacts leverage the CodeSandbox library for secure rendering of HTML/JS code. By default, the public CDN hosted by CodeSandbox is used.

Fortunately, for those with internal network requirements, you can [self-host the bundler](https://sandpack.codesandbox.io/docs/guides/hosting-the-bundler) that compiles the frontend code and specify a custom bundler URL for Sandpack.

For more info, including pre-made container images for self-hosting with metric requests removed, see: https://github.com/LibreChat-AI/codesandbox-client

<OptionTable
  options={[
    [
      'SANDPACK_BUNDLER_URL',
      'string',
      'Specifies a custom bundler URL for Sandpack, used by Artifacts',
      'SANDPACK_BUNDLER_URL=your-bundler-url',
    ],
  ]}
/>

## Search (Meilisearch)

Search is disabled by default. Enable it only after configuring Meilisearch with a unique master key:

<OptionTable
  options={[['SEARCH', 'boolean', 'Enables search in messages and conversations. Default: false.', 'SEARCH=true']]}
/>

> Note: If you're not using docker, it requires the installation of the free self-hosted Meilisearch or a paid remote plan

To disable anonymized telemetry analytics for MeiliSearch for absolute privacy, set to true:

<OptionTable
  options={[
    [
      'MEILI_NO_ANALYTICS',
      'boolean',
      'Disables anonymized telemetry analytics for MeiliSearch.',
      'MEILI_NO_ANALYTICS=true',
    ],
  ]}
/>

For the API server to connect to the search server. Replace '0.0.0.0' with 'meilisearch' if serving MeiliSearch with docker-compose.

<OptionTable
  options={[
    [
      'MEILI_HOST',
      'string',
      'The API server connection to the search server.',
      'MEILI_HOST=http://0.0.0.0:7700',
    ],
  ]}
/>

This master key must be at least 16 bytes of valid UTF-8. Generate a unique value and give the same key to LibreChat and the Meilisearch service. Search requires both `SEARCH=true` and a configured `MEILI_MASTER_KEY`.

<OptionTable
  options={[
    [
      'MEILI_MASTER_KEY',
      'string',
      'The master key for MeiliSearch.',
      'MEILI_MASTER_KEY=',
    ],
  ]}
/>

To prevent LibreChat from attempting a database indexing sync with Meilisearch, you can set the following environment variable to `true`. This is useful in a node cluster, or multi-node setup, where only one instance should be responsible for indexing.

<OptionTable
  options={[
    [
      'MEILI_NO_SYNC',
      'string',
      'Toggle for disabling Mellisearch index sync',
      'MEILI_NO_SYNC=true',
    ],
  ]}
/>

## RAG API

Configure Retrieval-Augmented Generation for document indexing and context-aware responses. See: **[RAG API Configuration](/docs/configuration/rag_api)**

<OptionTable
  options={[
    [
      'RAG_API_URL',
      'string',
      'URL of the RAG API service.',
      'RAG_API_URL=http://host.docker.internal:8000',
    ],
    [
      'RAG_OPENAI_API_KEY',
      'string',
      'OpenAI API key for RAG embeddings. Overrides OPENAI_API_KEY for RAG.',
      '# RAG_OPENAI_API_KEY=sk-your-openai-api-key',
    ],
    [
      'RAG_OPENAI_BASEURL',
      'string',
      'Custom OpenAI base URL for RAG embeddings.',
      '# RAG_OPENAI_BASEURL=',
    ],
    [
      'RAG_USE_FULL_CONTEXT',
      'boolean',
      'Fetch entire file context instead of top 4 results. Default: false.',
      '# RAG_USE_FULL_CONTEXT=true',
    ],
    [
      'EMBEDDINGS_PROVIDER',
      'string',
      'Embeddings provider: openai, azure, huggingface, huggingfacetei, or ollama. Default: openai.',
      '# EMBEDDINGS_PROVIDER=openai',
    ],
    [
      'EMBEDDINGS_MODEL',
      'string',
      'Embeddings model to use. Default depends on provider.',
      '# EMBEDDINGS_MODEL=text-embedding-3-small',
    ],
  ]}
/>

> **Note:** When using the default Docker setup, the `.env` file is shared between LibreChat and the RAG API. For complete configuration options, see the [RAG API documentation](/docs/configuration/rag_api).

## Speech to Text & Text to Speech

Configure Speech-to-Text (STT) and Text-to-Speech (TTS) services. See: **[Speech Settings](/docs/configuration/stt_tts)**

<OptionTable
  options={[
    [
      'STT_API_KEY',
      'string',
      'API key for Speech-to-Text service (e.g., OpenAI Whisper).',
      '# STT_API_KEY=',
    ],
    [
      'TTS_API_KEY',
      'string',
      'API key for Text-to-Speech service (e.g., OpenAI TTS).',
      '# TTS_API_KEY=',
    ],
  ]}
/>

> **Note:** STT and TTS are primarily configured through the `speech:` section in `librechat.yaml`. These environment variables are referenced in that configuration. See [Speech Settings](/docs/configuration/stt_tts) for full YAML configuration options.

## Shared Links

Configure shared conversation links functionality.

<OptionTable
  options={[
    [
      'ALLOW_SHARED_LINKS',
      'boolean',
      'Enable or disable shared conversation links. Default: true.',
      'ALLOW_SHARED_LINKS=true',
    ],
    [
      'ALLOW_SHARED_LINKS_PUBLIC',
      'boolean',
      'Allow shared links to be publicly accessible without authentication. Default: false.',
      'ALLOW_SHARED_LINKS_PUBLIC=false',
    ],
    [
      'SHARED_LINKS_SNAPSHOT_FILES',
      'boolean',
      'Snapshot files referenced by a shared chat so viewers can preview or download them through the shared link. Overrides interface.sharedLinks.snapshotFiles when set.',
      'SHARED_LINKS_SNAPSHOT_FILES=true',
    ],
  ]}
/>

`ALLOW_SHARED_LINKS` is the feature-wide switch. Role permissions now control who can create shared links, share them with authenticated users, or make them visible to everyone; see [`interface.sharedLinks`](/docs/configuration/librechat_yaml/object_structure/interface#sharedlinks). `ALLOW_SHARED_LINKS_PUBLIC` only controls whether publicly shared links can be viewed without authentication. `SHARED_LINKS_SNAPSHOT_FILES` is a global override for shared-link file snapshots and can disable snapshot serving for every link when set to `false`.

## Scheduled Chats

<OptionTable
  options={[
    [
      'SCHEDULES_SINGLE_PROCESS',
      'boolean',
      'Allows Scheduled Chats without Redis only when exactly one LibreChat process is running. Never enable this for multiple processes or replicas.',
      'SCHEDULES_SINGLE_PROCESS=true',
    ],
    [
      'SCHEDULES_DISABLED',
      'boolean',
      'Emergency global stop for automatic Scheduled Chat occurrences and Run now. Definitions remain stored. Default: false.',
      'SCHEDULES_DISABLED=true',
    ],
  ]}
/>

Scheduled Chats are experimental and disabled until [`interface.schedules`](/docs/configuration/librechat_yaml/object_structure/interface#schedules) is configured. Multi-replica deployments require `USE_REDIS_STREAMS=true`; a deployment without shared Redis streams fails schedule writes closed unless it explicitly declares a truly single-process topology with `SCHEDULES_SINGLE_PROCESS=true`. A scheduled Agent that can pause for Ask User or tool approval always requires `USE_REDIS_STREAMS=true` plus a durable shared checkpointer; the built-in default is MongoDB. See [Scheduled Chats](/docs/features/scheduled_chats) for setup and runtime behavior.

## Agent Event Runtime

<OptionTable
  options={[
    [
      'AGENT_TRIGGERS_SELF_URL',
      'string',
      'Compatibility fallback for endpoints.agents.eventDriven.selfUrl. Base URL used by the Agent event host to re-enter fire, continue, and steer admission.',
      '# AGENT_TRIGGERS_SELF_URL=http://127.0.0.1:3080',
    ],
    [
      'AGENT_EVENT_USER_MAX',
      'number',
      'Compatibility fallback for rateLimits.agentEvents.userMax. Maximum Agent Event requests per API-key principal in the configured window. Default: 40.',
      'AGENT_EVENT_USER_MAX=40',
    ],
    [
      'AGENT_EVENT_USER_WINDOW',
      'number',
      'Compatibility fallback for rateLimits.agentEvents.userWindowInMinutes. Agent Event rate-limit window in minutes. Default: 1.',
      'AGENT_EVENT_USER_WINDOW=1',
    ],
  ]}
/>

Prefer [`endpoints.agents.eventDriven.selfUrl`](/docs/configuration/librechat_yaml/object_structure/agents#eventdriven) and [`rateLimits.agentEvents`](/docs/configuration/librechat_yaml/object_structure/config#ratelimits) in `librechat.yaml`. `AGENT_TRIGGERS_SELF_URL` and the rate-limit variables remain compatibility fallbacks; an explicitly configured YAML value takes precedence.

Bound child continuations, detached Subagent parent continuations, and Event Actor detached Action completion are automatic. The retired `ENABLE_AGENT_EVENT_CHILD_TURNS`, `ENABLE_SUBAGENT_COMPLETION_WAKEUPS`, and `AGENT_TRIGGERS_DETACHED_ACTIONS_PRODUCER_ENABLED` variables are no longer read.

The in-memory generation store supports process-local Event Actor detached completion while the process remains alive. Redis generation streams add durable restart recovery and replica handoff. See [Generation Protocol Compatibility](/docs/configuration/redis#generation-protocol-compatibility) before a mixed-version deployment.

Leave `AGENT_TRIGGERS_SELF_URL` unset for the normal bound-listener path. Set it only when internal event admission must traverse another HTTP origin, such as a TLS front door. The value must be an HTTP or HTTPS URL without embedded credentials.

LibreChat exposes an authenticated Agent Events API; it does not expose an unauthenticated webhook. API-key identity, Remote Agents permissions, target access, idempotency, and the dedicated Agent Event rate limit protect ingress. MongoDB-backed ordering lanes, actor mailboxes, receipts, leases, retries, and dead letters support workers across replicas. See [Agent Event Delivery](/docs/features/agents#agent-event-delivery) and [Agents API - Agent Events](/docs/features/agents_api#agent-events) for behavior and examples.

## User System

This section contains the configuration for:

- [Automated Moderation](#moderation)
- [Balance/Token Usage](#balance)
- [Registration and Social Logins](#registration-and-login)
- [Email Password Reset](#password-reset)

### Admin Insights

<OptionTable
  options={[
    [
      'ENABLE_INSIGHTS',
      'boolean',
      'Enables the MongoDB-backed Insights dashboard for administrators with the required capabilities. Default: false.',
      'ENABLE_INSIGHTS=false',
    ],
  ]}
/>

When enabled, Insights remains restricted to accounts with the `ADMIN` role plus `access:admin` and `read:insights`. Queries are tenant-scoped and expose persisted activity metrics and recent conversation metadata. See [Admin Insights](/docs/features/insights) for metric definitions and access details.

### Agent Conversation Controls

<OptionTable
  options={[
    [
      'STEER_MAX_LENGTH',
      'number',
      'Maximum characters allowed in one mid-run Agent steering message. Default: 16000.',
      '# STEER_MAX_LENGTH=16000',
    ],
  ]}
/>

### Moderation

The Automated Moderation System uses a scoring mechanism to track user violations. As users commit actions like excessive logins, registrations, or messaging, they accumulate violation scores. Upon reaching a set threshold, the user and their IP are temporarily banned. This system ensures platform security by monitoring and penalizing rapid or suspicious activities.

see: **[Automated Moderation](/docs/configuration/mod_system)**

#### Basic Moderation Settings

<OptionTable
  options={[
    [
      'OPENAI_MODERATION',
      'boolean',
      'Whether or not to enable OpenAI moderation on the **OpenAI** and **Plugins** endpoints.',
      'OPENAI_MODERATION=false',
    ],
    ['OPENAI_MODERATION_API_KEY', 'string', 'Your OpenAI API key.', 'OPENAI_MODERATION_API_KEY='],
    [
      'OPENAI_MODERATION_REVERSE_PROXY',
      'string',
      'Note: Commented out by default, this is not working with all reverse proxys.',
      '# OPENAI_MODERATION_REVERSE_PROXY=',
    ],
  ]}
/>

#### Banning Settings

<OptionTable
  options={[
    [
      'BAN_VIOLATIONS',
      'boolean',
      'Whether or not to enable banning users for violations (they will still be logged).',
      'BAN_VIOLATIONS=true',
    ],
    [
      'BAN_DURATION',
      'integer',
      'How long the user and associated IP are banned for (in milliseconds).',
      'BAN_DURATION=1000 * 60 * 60 * 2',
    ],
    [
      'BAN_INTERVAL',
      'integer',
      'The user will be banned every time their score reaches/crosses over the interval threshold.',
      'BAN_INTERVAL=20',
    ],
    [
      'VIOLATION_SCORE_TTL',
      'integer',
      'How long a violation score lives without new violations (in milliseconds). Each new violation restarts the countdown, so scores decay after a quiet period instead of accumulating forever. Set to 0 to never expire scores (legacy behavior).',
      'VIOLATION_SCORE_TTL=1000 * 60 * 60',
    ],
  ]}
/>

#### Login and registration rate limiting

Prevents brute force attacks and spam registrations by limiting login attempts and new account registrations.

<OptionTable
  options={[
    [
      'LOGIN_MAX',
      'integer',
      'The max amount of logins allowed per IP per LOGIN_WINDOW.',
      'LOGIN_MAX=7',
    ],
    [
      'LOGIN_WINDOW',
      'integer',
      'In minutes, determines the window of time for LOGIN_MAX logins.',
      'LOGIN_WINDOW=5',
    ],
    [
      'REGISTER_MAX',
      'integer',
      'The max amount of registrations allowed per IP per REGISTER_WINDOW.',
      'REGISTER_MAX=5',
    ],
    [
      'REGISTER_WINDOW',
      'integer',
      'In minutes, determines the window of time for REGISTER_MAX registrations.',
      'REGISTER_WINDOW=60',
    ],
  ]}
/>

The login-attempt budget is shared by the local login API and top-level social or federated OAuth navigations from the same IP. A rejected API login receives the existing JSON `429` response. A rate-limited or banned `/oauth/*` browser navigation returns to `/login?redirect=false` with a localized error code instead of rendering a JSON document; `redirect=false` prevents an automatic OpenID redirect from immediately entering the limiter again.

#### Password reset and email verification rate limiting

LibreChat applies separate IP-based limits to requesting an email and submitting the token from that email. This prevents repeated token guesses without forcing deployments to use the same limit for email delivery and token validation.

<OptionTable
  options={[
    [
      'RESET_PASSWORD_MAX',
      'integer',
      'Maximum password-reset email requests per IP in RESET_PASSWORD_WINDOW. Default: 2.',
      '# RESET_PASSWORD_MAX=2',
    ],
    [
      'RESET_PASSWORD_WINDOW',
      'integer',
      'Password-reset email request window in minutes. Default: 2.',
      '# RESET_PASSWORD_WINDOW=2',
    ],
    [
      'RESET_PASSWORD_SUBMISSION_MAX',
      'integer',
      'Maximum password-reset token submissions per IP. Defaults to RESET_PASSWORD_MAX, then 2.',
      '# RESET_PASSWORD_SUBMISSION_MAX=2',
    ],
    [
      'RESET_PASSWORD_SUBMISSION_WINDOW',
      'integer',
      'Password-reset token submission window in minutes. Defaults to RESET_PASSWORD_WINDOW, then 2.',
      '# RESET_PASSWORD_SUBMISSION_WINDOW=2',
    ],
    [
      'VERIFY_EMAIL_MAX',
      'integer',
      'Maximum verification-email resend requests per IP in VERIFY_EMAIL_WINDOW. Default: 2.',
      '# VERIFY_EMAIL_MAX=2',
    ],
    [
      'VERIFY_EMAIL_WINDOW',
      'integer',
      'Verification-email resend window in minutes. Default: 2.',
      '# VERIFY_EMAIL_WINDOW=2',
    ],
    [
      'VERIFY_EMAIL_SUBMISSION_MAX',
      'integer',
      'Maximum email-verification token submissions per IP. Defaults to VERIFY_EMAIL_MAX, then 2.',
      '# VERIFY_EMAIL_SUBMISSION_MAX=2',
    ],
    [
      'VERIFY_EMAIL_SUBMISSION_WINDOW',
      'integer',
      'Email-verification token submission window in minutes. Defaults to VERIFY_EMAIL_WINDOW, then 2.',
      '# VERIFY_EMAIL_SUBMISSION_WINDOW=2',
    ],
  ]}
/>

#### Score for each violation

<OptionTable
  options={[
    ['LOGIN_VIOLATION_SCORE', 'integer', 'Score for login violations.', 'LOGIN_VIOLATION_SCORE=1'],
    [
      'REGISTRATION_VIOLATION_SCORE',
      'integer',
      'Score for registration violations.',
      'REGISTRATION_VIOLATION_SCORE=1',
    ],
    [
      'CONCURRENT_VIOLATION_SCORE',
      'integer',
      'Score for concurrent violations.',
      'CONCURRENT_VIOLATION_SCORE=1',
    ],
    [
      'MESSAGE_VIOLATION_SCORE',
      'integer',
      'Score for message violations.',
      'MESSAGE_VIOLATION_SCORE=1',
    ],
    [
      'NON_BROWSER_VIOLATION_SCORE',
      'integer',
      'Score for non-browser violations.',
      'NON_BROWSER_VIOLATION_SCORE=20',
    ],
    [
      'ILLEGAL_MODEL_REQ_SCORE',
      'integer',
      'Score for illegal model requests.',
      'ILLEGAL_MODEL_REQ_SCORE=5',
    ],
    [
      'IMPORT_VIOLATION_SCORE',
      'integer',
      'Score for import conversation violations.',
      'IMPORT_VIOLATION_SCORE=1',
    ],
    [
      'FORK_VIOLATION_SCORE',
      'integer',
      'Score for conversation fork violations.',
      'FORK_VIOLATION_SCORE=1',
    ],
    [
      'TTS_VIOLATION_SCORE',
      'integer',
      'Score for text-to-speech violations.',
      'TTS_VIOLATION_SCORE=0',
    ],
    [
      'STT_VIOLATION_SCORE',
      'integer',
      'Score for speech-to-text violations.',
      'STT_VIOLATION_SCORE=0',
    ],
    [
      'FILE_UPLOAD_VIOLATION_SCORE',
      'integer',
      'Score for file upload violations.',
      'FILE_UPLOAD_VIOLATION_SCORE=0',
    ],
    [
      'RESET_PASSWORD_VIOLATION_SCORE',
      'integer',
      'Score for password-reset email request violations. Default: 1.',
      '# RESET_PASSWORD_VIOLATION_SCORE=1',
    ],
    [
      'VERIFY_EMAIL_VIOLATION_SCORE',
      'integer',
      'Score for verification-email resend violations. Default: 1.',
      '# VERIFY_EMAIL_VIOLATION_SCORE=1',
    ],
    [
      'RESET_PASSWORD_SUBMISSION_VIOLATION_SCORE',
      'integer',
      'Score for password-reset token submission violations. Default: 1.',
      '# RESET_PASSWORD_SUBMISSION_VIOLATION_SCORE=1',
    ],
    [
      'VERIFY_EMAIL_SUBMISSION_VIOLATION_SCORE',
      'integer',
      'Score for email-verification token submission violations. Default: 1.',
      '# VERIFY_EMAIL_SUBMISSION_VIOLATION_SCORE=1',
    ],
    [
      'TOOL_CALL_VIOLATION_SCORE',
      'integer',
      'Score for tool call violations.',
      'TOOL_CALL_VIOLATION_SCORE=0',
    ],
    [
      'CONVO_ACCESS_VIOLATION_SCORE',
      'integer',
      'Score for conversation access violations.',
      'CONVO_ACCESS_VIOLATION_SCORE=0',
    ],
  ]}
/>

> Note: Non-browser access and Illegal model requests are almost always nefarious as it means a 3rd party is attempting to access the server through an automated script.

#### Message rate limiting (per user & IP)

<OptionTable
  options={[
    [
      'LIMIT_CONCURRENT_MESSAGES',
      'boolean',
      'Whether to limit the amount of messages a user can send per request.',
      'LIMIT_CONCURRENT_MESSAGES=true',
    ],
    [
      'CONCURRENT_MESSAGE_MAX',
      'integer',
      'The max amount of messages a user can send per request.',
      'CONCURRENT_MESSAGE_MAX=2',
    ],
  ]}
/>

#### Limiters

> Note: You can utilize both limiters, but default is to limit by IP only.

##### IP Limiter:

<OptionTable
  options={[
    [
      'LIMIT_MESSAGE_IP',
      'boolean',
      'Whether to limit the amount of messages an IP can send per `MESSAGE_IP_WINDOW`.',
      'LIMIT_MESSAGE_IP=true',
    ],
    [
      'MESSAGE_IP_MAX',
      'integer',
      'The max amount of messages an IP can send per `MESSAGE_IP_WINDOW`.',
      'MESSAGE_IP_MAX=40',
    ],
    [
      'MESSAGE_IP_WINDOW',
      'integer',
      'In minutes, determines the window of time for `MESSAGE_IP_MAX` messages.',
      'MESSAGE_IP_WINDOW=1',
    ],
  ]}
/>

##### User Limiter:

<OptionTable
  options={[
    [
      'LIMIT_MESSAGE_USER',
      'boolean',
      'Whether to limit the amount of messages an user can send per `MESSAGE_USER_WINDOW`.',
      'LIMIT_MESSAGE_USER=false',
    ],
    [
      'MESSAGE_USER_MAX',
      'integer',
      'The max amount of messages an user can send per `MESSAGE_USER_WINDOW`.',
      'MESSAGE_USER_MAX=40',
    ],
    [
      'MESSAGE_USER_WINDOW',
      'integer',
      'In minutes, determines the window of time for `MESSAGE_USER_MAX` messages.',
      'MESSAGE_USER_WINDOW=1',
    ],
  ]}
/>

Confirmed idempotent Agent-generation retries bypass ordinary per-user message admission so recovery can proceed, but they still pass through the shared IP limiter when `LIMIT_MESSAGE_IP` is enabled. Trusted Agent-trigger deliveries remain exempt from that browser-facing IP boundary.

##### Queued Attachment TTL Limiter:

The `/files/usage` endpoint renews a bounded TTL hold for attachments waiting in queued Agent messages. It has a separate per-user limiter so metadata renewals do not consume the upload quota.

<OptionTable
  options={[
    [
      'FILE_USAGE_USER_MAX',
      'integer',
      'Maximum queued-attachment TTL renewal requests per user and window. Default: 120.',
      '# FILE_USAGE_USER_MAX=120',
    ],
    [
      'FILE_USAGE_USER_WINDOW',
      'integer',
      'Window in minutes for FILE_USAGE_USER_MAX. Default: 15.',
      '# FILE_USAGE_USER_WINDOW=15',
    ],
  ]}
/>

#### Import conversation rate limiting

Limits how often users can import conversations to prevent abuse.

> Note: You can utilize both limiters, but default is to limit by IP only.

##### IP Limiter:

<OptionTable
  options={[
    [
      'LIMIT_IMPORT_IP',
      'boolean',
      'Whether to limit the amount of conversation imports an IP can perform per `IMPORT_IP_WINDOW`.',
      'LIMIT_IMPORT_IP=true',
    ],
    [
      'IMPORT_IP_MAX',
      'integer',
      'The max amount of conversation imports an IP can perform per `IMPORT_IP_WINDOW`.',
      'IMPORT_IP_MAX=100',
    ],
    [
      'IMPORT_IP_WINDOW',
      'integer',
      'In minutes, determines the window of time for `IMPORT_IP_MAX` imports.',
      'IMPORT_IP_WINDOW=1',
    ],
  ]}
/>

##### User Limiter:

<OptionTable
  options={[
    [
      'LIMIT_IMPORT_USER',
      'boolean',
      'Whether to limit the amount of conversation imports a user can perform per `IMPORT_USER_WINDOW`.',
      'LIMIT_IMPORT_USER=false',
    ],
    [
      'IMPORT_USER_MAX',
      'integer',
      'The max amount of conversation imports a user can perform per `IMPORT_USER_WINDOW`.',
      'IMPORT_USER_MAX=50',
    ],
    [
      'IMPORT_USER_WINDOW',
      'integer',
      'In minutes, determines the window of time for `IMPORT_USER_MAX` imports.',
      'IMPORT_USER_WINDOW=1',
    ],
  ]}
/>

#### Conversation forking rate limiting

Limits how often users can fork conversations to prevent abuse.

> Note: You can utilize both limiters, but default is to limit by IP only.

##### IP Limiter:

<OptionTable
  options={[
    [
      'LIMIT_FORK_IP',
      'boolean',
      'Whether to limit the amount of conversation forks an IP can create per `FORK_IP_WINDOW`.',
      'LIMIT_FORK_IP=true',
    ],
    [
      'FORK_IP_MAX',
      'integer',
      'The max amount of conversation forks an IP can create per `FORK_IP_WINDOW`.',
      'FORK_IP_MAX=30',
    ],
    [
      'FORK_IP_WINDOW',
      'integer',
      'In minutes, determines the window of time for `FORK_IP_MAX` forks.',
      'FORK_IP_WINDOW=1',
    ],
  ]}
/>

##### User Limiter:

<OptionTable
  options={[
    [
      'LIMIT_FORK_USER',
      'boolean',
      'Whether to limit the amount of conversation forks a user can create per `FORK_USER_WINDOW`.',
      'LIMIT_FORK_USER=false',
    ],
    [
      'FORK_USER_MAX',
      'integer',
      'The max amount of conversation forks a user can create per `FORK_USER_WINDOW`.',
      'FORK_USER_MAX=7',
    ],
    [
      'FORK_USER_WINDOW',
      'integer',
      'In minutes, determines the window of time for `FORK_USER_MAX` forks.',
      'FORK_USER_WINDOW=1',
    ],
  ]}
/>

#### File upload rate limiting

Limits how often users can upload files to prevent abuse.

> Note: These can also be configured via `librechat.yaml` in the `rateLimits.fileUploads` section.

##### IP Limiter:

<OptionTable
  options={[
    [
      'FILE_UPLOAD_IP_MAX',
      'integer',
      'Max file uploads per IP per `FILE_UPLOAD_IP_WINDOW`. Default: 100.',
      '# FILE_UPLOAD_IP_MAX=100',
    ],
    [
      'FILE_UPLOAD_IP_WINDOW',
      'integer',
      'In minutes, determines the window of time for `FILE_UPLOAD_IP_MAX`. Default: 15.',
      '# FILE_UPLOAD_IP_WINDOW=15',
    ],
  ]}
/>

##### User Limiter:

<OptionTable
  options={[
    [
      'FILE_UPLOAD_USER_MAX',
      'integer',
      'Max file uploads per user per `FILE_UPLOAD_USER_WINDOW`. Default: 50.',
      '# FILE_UPLOAD_USER_MAX=50',
    ],
    [
      'FILE_UPLOAD_USER_WINDOW',
      'integer',
      'In minutes, determines the window of time for `FILE_UPLOAD_USER_MAX`. Default: 15.',
      '# FILE_UPLOAD_USER_WINDOW=15',
    ],
  ]}
/>

#### TTS (Text-to-Speech) rate limiting

Limits how often users can use Text-to-Speech to prevent abuse.

> Note: These can also be configured via `librechat.yaml` in the `rateLimits.tts` section.

##### IP Limiter:

<OptionTable
  options={[
    [
      'TTS_IP_MAX',
      'integer',
      'Max TTS requests per IP per `TTS_IP_WINDOW`. Default: 100.',
      '# TTS_IP_MAX=100',
    ],
    [
      'TTS_IP_WINDOW',
      'integer',
      'In minutes, determines the window of time for `TTS_IP_MAX`. Default: 1.',
      '# TTS_IP_WINDOW=1',
    ],
  ]}
/>

##### User Limiter:

<OptionTable
  options={[
    [
      'TTS_USER_MAX',
      'integer',
      'Max TTS requests per user per `TTS_USER_WINDOW`. Default: 50.',
      '# TTS_USER_MAX=50',
    ],
    [
      'TTS_USER_WINDOW',
      'integer',
      'In minutes, determines the window of time for `TTS_USER_MAX`. Default: 1.',
      '# TTS_USER_WINDOW=1',
    ],
  ]}
/>

#### STT (Speech-to-Text) rate limiting

Limits how often users can use Speech-to-Text to prevent abuse.

> Note: These can also be configured via `librechat.yaml` in the `rateLimits.stt` section.

##### IP Limiter:

<OptionTable
  options={[
    [
      'STT_IP_MAX',
      'integer',
      'Max STT requests per IP per `STT_IP_WINDOW`. Default: 100.',
      '# STT_IP_MAX=100',
    ],
    [
      'STT_IP_WINDOW',
      'integer',
      'In minutes, determines the window of time for `STT_IP_MAX`. Default: 1.',
      '# STT_IP_WINDOW=1',
    ],
  ]}
/>

##### User Limiter:

<OptionTable
  options={[
    [
      'STT_USER_MAX',
      'integer',
      'Max STT requests per user per `STT_USER_WINDOW`. Default: 50.',
      '# STT_USER_MAX=50',
    ],
    [
      'STT_USER_WINDOW',
      'integer',
      'In minutes, determines the window of time for `STT_USER_MAX`. Default: 1.',
      '# STT_USER_WINDOW=1',
    ],
  ]}
/>

### Balance

The following feature allows for the management of user balances within the system's endpoints. You have the option to add balances manually, or you may choose to implement a system that accumulates balances automatically for users. If a specific initial balance is defined in the configuration, tokens will be credited to the user's balance automatically when they register.

see: **[Token Usage](/docs/configuration/token_usage)**

<OptionTable
  options={[
    [
      'CHECK_BALANCE',
      'boolean',
      'Enable token credit balances for the OpenAI/Plugins endpoints.',
      'CHECK_BALANCE=false',
    ],
    [
      'START_BALANCE',
      'integer',
      "If the value is set, tokens will be credited to the user's balance after registration.",
      'START_BALANCE=20000',
    ],
  ]}
/>

#### Managing Balances

- Run `npm run add-balance` to manually add balances.
  - You can also specify the email and token credit amount to add, e.g.: `npm run add-balance example@example.com 1000`
- Run `npm run set-balance` to manually set balances, similar to `add-balance`.
- Run `npm run list-balances` to list the balance of every user.

> **Note:** 1000 credits = $0.001 (1 mill USD)

### Registration and Login

see: **[Authentication System](/docs/configuration/authentication)**

<ThemeImage
  light="https://github.com/danny-avila/LibreChat/assets/32828263/4c51dc25-31d3-4c51-8c2a-0cdfb5a25033"
  dark="https://github.com/danny-avila/LibreChat/assets/32828263/3bc5371d-e51d-4e91-ac68-56db6e85bb2c"
  alt="User registration screen"
/>

<Callout type="info" title="Configuration File Clarification">
  All authentication settings in this section should be configured in your `.env` file, not in the
  `librechat.yaml` file or `docker-compose.override.yml`. The `docker-compose.override.yml` file is
  only used to mount volumes and set environment variables for Docker, while the `librechat.yaml`
  file is used for custom endpoints and other application settings.
</Callout>

- General Settings:

<OptionTable
  options={[
    [
      'ALLOW_EMAIL_LOGIN',
      'boolean',
      'Enable or disable ONLY email login.',
      'ALLOW_EMAIL_LOGIN=true',
    ],
    [
      'ALLOW_EMAIL_LOGIN_OVERRIDE',
      'boolean',
      'Permit direct API email login while ALLOW_EMAIL_LOGIN=false. Each use is logged. Default: false.',
      '# ALLOW_EMAIL_LOGIN_OVERRIDE=false',
    ],
    [
      'ALLOW_REGISTRATION',
      'boolean',
      'Enable or disable Email registration of new users.',
      'ALLOW_REGISTRATION=true',
    ],
    [
      'ALLOW_SOCIAL_LOGIN',
      'boolean',
      'Allow users to connect to LibreChat with various social networks.',
      'ALLOW_SOCIAL_LOGIN=false',
    ],
    [
      'ALLOW_SOCIAL_REGISTRATION',
      'boolean',
      'Enable or disable registration of new users using various social networks.',
      'ALLOW_SOCIAL_REGISTRATION=false',
    ],
    [
      'ALLOW_PASSWORD_RESET',
      'boolean',
      'Enable or disable the ability for users to reset their password by themselves',
      'ALLOW_PASSWORD_RESET=false',
    ],
    [
      'ALLOW_ACCOUNT_DELETION',
      'boolean',
      'Enable or disable the ability for users to delete their account by themselves. Enabled by default if omitted/commented out',
      'ALLOW_ACCOUNT_DELETION=true',
    ],
    [
      'ALLOW_UNVERIFIED_EMAIL_LOGIN',
      'boolean',
      'Set to true to allow users to log in without verifying their email address. If set to false, users will be required to verify their email before logging in.',
      'ALLOW_UNVERIFIED_EMAIL_LOGIN=true',
    ],
    [
      'MIN_PASSWORD_LENGTH',
      'number',
      'Minimum password length for user authentication. When using LDAP authentication, you may want to set this to 1 to bypass local password validation, as LDAP servers handle their own password policies.',
      'MIN_PASSWORD_LENGTH=8',
    ],
  ]}
/>

> **Quick Tip:** Even with registration disabled, add users directly to the database using `npm run create-user`.
> **Quick Tip:** With registration disabled, you can delete a user with `npm run delete-user email@domain.com`.

- Session and Refresh Token Settings:

<OptionTable
  options={[
    [
      'SESSION_EXPIRY',
      'integer (milliseconds)',
      'Session expiry time.',
      'SESSION_EXPIRY=1000 * 60 * 15',
    ],
    [
      'REFRESH_TOKEN_EXPIRY',
      'integer (milliseconds)',
      'Refresh token expiry time.',
      'REFRESH_TOKEN_EXPIRY=(1000 * 60 * 60 * 24) * 7',
    ],
    [
      'SESSION_COOKIE_SECURE',
      'boolean',
      'Overrides the Secure attribute for session/auth cookies. Leave unset to use the default NODE_ENV/DOMAIN_SERVER heuristic.',
      '# SESSION_COOKIE_SECURE=false',
    ],
  ]}
/>

- For more information: **[Refresh Token](https://github.com/danny-avila/LibreChat/pull/927)**

- JWT Settings:

Use unique values of at least 32 bytes. Generate permanent values for production with the [Credentials Generator](/toolkit/creds_generator).

<OptionTable
  options={[
    [
      'JWT_SECRET',
      'string (hex)',
      'JWT secret key.',
      'JWT_SECRET=',
    ],
    [
      'JWT_REFRESH_SECRET',
      'string (hex)',
      'JWT refresh secret key.',
      'JWT_REFRESH_SECRET=',
    ],
  ]}
/>

Blank JWT secrets use the same temporary-credential bootstrap described under [Credentials Configuration](#credentials-configuration). In production and horizontally scaled deployments, set permanent values and share them across replicas so issued sessions remain valid.

### Social Logins

For more details: [OAuth2-OIDC](/docs/configuration/authentication/OAuth2-OIDC)

#### Apple Authentication

For more information: **[Apple Authentication](/docs/configuration/authentication/OAuth2-OIDC/apple)**

<OptionTable
  options={[
    [
      'APPLE_CLIENT_ID',
      'string',
      'Your Apple Services ID (e.g., com.yourdomain.librechat.services).',
      'APPLE_CLIENT_ID=com.yourdomain.librechat.services',
    ],
    ['APPLE_TEAM_ID', 'string', 'Your Apple Developer Team ID.', 'APPLE_TEAM_ID=YOUR_TEAM_ID'],
    [
      'APPLE_KEY_ID',
      'string',
      'Your Apple Key ID from the downloaded key.',
      'APPLE_KEY_ID=YOUR_KEY_ID',
    ],
    [
      'APPLE_PRIVATE_KEY_PATH',
      'string',
      'Absolute path to your downloaded .p8 file.',
      'APPLE_PRIVATE_KEY_PATH=/path/to/AuthKey.p8',
    ],
    [
      'APPLE_CALLBACK_URL',
      'string',
      'The callback URL for Apple authentication.',
      'APPLE_CALLBACK_URL=/oauth/apple/callback',
    ],
  ]}
/>

#### Discord Authentication

For more information: **[Discord](/docs/configuration/authentication/OAuth2-OIDC/discord)**

<OptionTable
  options={[
    ['DISCORD_CLIENT_ID', 'string', 'Your Discord client ID.', 'DISCORD_CLIENT_ID='],
    ['DISCORD_CLIENT_SECRET', 'string', 'Your Discord client secret.', 'DISCORD_CLIENT_SECRET='],
    [
      'DISCORD_CALLBACK_URL',
      'string',
      'The callback URL for Discord authentication.',
      'DISCORD_CALLBACK_URL=/oauth/discord/callback',
    ],
  ]}
/>

#### Facebook Authentication

For more information: **[Facebook Authentication](/docs/configuration/authentication/OAuth2-OIDC/facebook)**

<OptionTable
  options={[
    ['FACEBOOK_CLIENT_ID', 'string', 'Your Facebook client ID.', 'FACEBOOK_CLIENT_ID='],
    ['FACEBOOK_CLIENT_SECRET', 'string', 'Your Facebook client secret.', 'FACEBOOK_CLIENT_SECRET='],
    [
      'FACEBOOK_CALLBACK_URL',
      'string',
      'The callback URL for Facebook authentication.',
      'FACEBOOK_CALLBACK_URL=/oauth/facebook/callback',
    ],
  ]}
/>

#### GitHub Authentication

For more information: **[GitHub Authentication](/docs/configuration/authentication/OAuth2-OIDC/github)**

<OptionTable
  options={[
    ['GITHUB_CLIENT_ID', 'string', 'Your GitHub client ID.', 'GITHUB_CLIENT_ID='],
    ['GITHUB_CLIENT_SECRET', 'string', 'Your GitHub client secret.', 'GITHUB_CLIENT_SECRET='],
    [
      'GITHUB_CALLBACK_URL',
      'string',
      'The callback URL for GitHub authentication.',
      'GITHUB_CALLBACK_URL=/oauth/github/callback',
    ],
    [
      'GITHUB_ENTERPRISE_BASE_URL',
      'string',
      'Optional: The base URL for your GitHub Enterprise instance.',
      'GITHUB_ENTERPRISE_BASE_URL=',
    ],
    [
      'GITHUB_ENTERPRISE_USER_AGENT',
      'string',
      'Optional: The user agent for GitHub Enterprise requests.',
      'GITHUB_ENTERPRISE_USER_AGENT=',
    ],
  ]}
/>

#### Google Authentication

For more information: **[Google Authentication](/docs/configuration/authentication/OAuth2-OIDC/google)**

<OptionTable
  options={[
    ['GOOGLE_CLIENT_ID', 'string', 'Your Google client ID.', 'GOOGLE_CLIENT_ID='],
    ['GOOGLE_CLIENT_SECRET', 'string', 'Your Google client secret.', 'GOOGLE_CLIENT_SECRET='],
    [
      'GOOGLE_CALLBACK_URL',
      'string',
      'The callback URL for Google authentication.',
      'GOOGLE_CALLBACK_URL=/oauth/google/callback',
    ],
  ]}
/>

#### OpenID Connect

For more information:

- [Auth0](/docs/configuration/authentication/OAuth2-OIDC/auth0)
- [AWS Cognito](/docs/configuration/authentication/OAuth2-OIDC/aws)
- [Azure Entra/AD](/docs/configuration/authentication/OAuth2-OIDC/azure)
- [Keycloak](/docs/configuration/authentication/OAuth2-OIDC/keycloak)

<OptionTable
  options={[
    ['OPENID_CLIENT_ID', 'string', 'Your OpenID client ID.', 'OPENID_CLIENT_ID='],
    ['OPENID_CLIENT_SECRET', 'string', 'Your OpenID client secret.', 'OPENID_CLIENT_SECRET='],
    ['OPENID_ISSUER', 'string', 'The OpenID issuer URL.', 'OPENID_ISSUER='],
    [
      'OPENID_SESSION_SECRET',
      'string',
      'The secret for OpenID session storage.',
      'OPENID_SESSION_SECRET=',
    ],
    ['OPENID_SCOPE', 'string', 'The OpenID scope.', 'OPENID_SCOPE="openid profile email"'],
    [
      'OPENID_CALLBACK_URL',
      'string',
      'The callback URL for OpenID authentication.',
      'OPENID_CALLBACK_URL=/oauth/openid/callback',
    ],
    [
      'OPENID_AUDIENCE',
      'string',
      'Audience value for OpenID JWT validation and authorization requests. Comma-separated values are accepted for JWT validation; authorization requests use the first non-empty value. Required for Auth0 when using OPENID_REUSE_TOKENS=true to receive JWT access tokens instead of opaque tokens.',
      'OPENID_AUDIENCE=https://api.librechat.com',
    ],
    [
      'OPENID_REQUIRED_ROLE',
      'string',
      'The required role(s) for validation. Supports a single role or multiple comma-separated roles. When multiple roles are specified, the user needs ANY of the specified roles (OR logic).',
      'OPENID_REQUIRED_ROLE=admin or OPENID_REQUIRED_ROLE=role1,role2,admin',
    ],
    [
      'OPENID_REQUIRED_ROLE_TOKEN_KIND',
      'string',
      'The token kind for required role validation.',
      'OPENID_REQUIRED_ROLE_TOKEN_KIND=',
    ],
    [
      'OPENID_REQUIRED_ROLE_PARAMETER_PATH',
      'string',
      'The parameter path for required role validation.',
      'OPENID_REQUIRED_ROLE_PARAMETER_PATH=',
    ],
    [
      'OPENID_ADMIN_ROLE',
      'string',
      'The role the user should have in order to be an admin in LibreChat.',
      'OPENID_ADMIN_ROLE=',
    ],
    [
      'OPENID_ADMIN_ROLE_TOKEN_KIND',
      'string',
      'The source of the information for admin role verification. Possible values are: access, id or userinfo.',
      'OPENID_ADMIN_ROLE_TOKEN_KIND=',
    ],
    [
      'OPENID_ADMIN_ROLE_PARAMETER_PATH',
      'string',
      'The parameter path for required role validation.',
      'OPENID_ADMIN_ROLE_PARAMETER_PATH=',
    ],
    [
      'OPENID_ROLE_SYNC_ENABLED',
      'boolean',
      'Enable generic OpenID role sync for non-admin roles. ADMIN cannot be assigned by role sync; use OPENID_ADMIN_ROLE for admin elevation.',
      'OPENID_ROLE_SYNC_ENABLED=false',
    ],
    [
      'OPENID_ROLE_SYNC_API_ENABLED',
      'boolean',
      'Enable API-based role sync helpers. Requires OPENID_ROLE_SYNC_ENABLED=true.',
      'OPENID_ROLE_SYNC_API_ENABLED=false',
    ],
    [
      'OPENID_ROLE_SYNC_SOURCE',
      'string',
      'Token source for the role claim. Must be one of: access, id, userinfo. Default: id.',
      'OPENID_ROLE_SYNC_SOURCE=id',
    ],
    [
      'OPENID_ROLE_SYNC_CLAIM',
      'string',
      'Claim path that contains the provider roles or groups. Required when role sync is enabled.',
      'OPENID_ROLE_SYNC_CLAIM=',
    ],
    [
      'OPENID_ROLE_SYNC_ROLE_PRIORITY',
      'string',
      'Comma-separated LibreChat roles ordered from most important to least important. The first matching role is assigned.',
      'OPENID_ROLE_SYNC_ROLE_PRIORITY=Support,User',
    ],
    [
      'OPENID_ROLE_SYNC_FALLBACK_ROLE',
      'string',
      'LibreChat role assigned when no priority role matches. The fallback is authoritative when configured. Remote Agents API authentication treats an unresolved Entra group-overage list as empty, so this fallback applies there as well.',
      'OPENID_ROLE_SYNC_FALLBACK_ROLE=USER',
    ],
    [
      'OPENID_BUTTON_LABEL',
      'string',
      'The label for the OpenID login button.',
      'OPENID_BUTTON_LABEL=',
    ],
    [
      'OPENID_IMAGE_URL',
      'string',
      'The URL of the OpenID login button image.',
      'OPENID_IMAGE_URL=',
    ],
    [
      'OPENID_USE_END_SESSION_ENDPOINT',
      'string',
      'Whether to use the Issuer End Session Endpoint as a Logout Redirect',
      'OPENID_USE_END_SESSION_ENDPOINT=TRUE',
    ],
    [
      'OPENID_MAX_LOGOUT_URL_LENGTH',
      'number',
      'Maximum logout URL length before using logout_hint instead of id_token_hint. Default: 2000.',
      '# OPENID_MAX_LOGOUT_URL_LENGTH=2000',
    ],
    [
      'OPENID_AUTO_REDIRECT',
      'boolean',
      'Whether to automatically redirect to the OpenID provider.',
      'OPENID_AUTO_REDIRECT=true',
    ],
    [
      'OPENID_USE_PKCE',
      'boolean',
      'Use PKCE (Proof Key for Code Exchange) for OpenID authentication. For public clients without a client secret, leave OPENID_CLIENT_SECRET empty and set this to true.',
      '# OPENID_USE_PKCE=true',
    ],
    [
      'OPENID_POST_LOGOUT_REDIRECT_URI',
      'string',
      'Redirect URI after OpenID logout. Defaults to ${DOMAIN_CLIENT}/login.',
      '# OPENID_POST_LOGOUT_REDIRECT_URI=',
    ],
    [
      'OPENID_CLOCK_TOLERANCE',
      'number',
      'Clock tolerance in seconds for token validation. Default: 300.',
      '# OPENID_CLOCK_TOLERANCE=300',
    ],
    [
      'OPENID_GENERATE_NONCE',
      'boolean',
      'Force the OpenID client to generate a nonce parameter. Required by some identity providers like AWS Cognito (especially with federation) and Authentik.',
      'OPENID_GENERATE_NONCE=true',
    ],
    [
      'DEBUG_OPENID_REQUESTS',
      'boolean',
      'Enable detailed logging of OpenID request headers. When disabled (default), only request URLs are logged at debug level. When enabled, request headers are also logged (with sensitive data masked) for deeper debugging of authentication issues.',
      'DEBUG_OPENID_REQUESTS=false',
    ],
    [
      'OPENID_USERNAME_CLAIM',
      'string',
      "The user info property from the OpenID provider to store as the user's username.",
      'OPENID_USERNAME_CLAIM=',
    ],
    [
      'OPENID_NAME_CLAIM',
      'string',
      "The user info property from the OpenID provider to store as the user's display name.",
      'OPENID_NAME_CLAIM=',
    ],
    [
      'OPENID_EMAIL_CLAIM',
      'string',
      'The user info claim to use as the email/identifier for user matching (e.g., "upn" for Entra ID). When not set, defaults to: email → preferred_username → upn.',
      'OPENID_EMAIL_CLAIM=',
    ],
  ]}
/>

<Callout type="warning" title="OpenID role sync">
  `OPENID_ROLE_SYNC_CLAIM` is required when role sync is enabled.
  `OPENID_ROLE_SYNC_API_ENABLED=true` also requires `OPENID_ROLE_SYNC_ENABLED=true`. Generic role
  sync cannot assign `ADMIN`; use `OPENID_ADMIN_ROLE` for admin elevation.
</Callout>

##### OpenID Connect Token Reuse

LibreChat supports reusing access and refresh tokens issued by your OpenID Connect provider (like Azure Entra ID or Auth0) to manage user authentication state. When this feature is active, the refresh token passed to the user as a cookie is issued by your OpenID provider instead of LibreChat.

<OptionTable
  options={[
    [
      'OPENID_REUSE_TOKENS',
      'boolean',
      'Enable reuse of OpenID provider tokens for session management.',
      'OPENID_REUSE_TOKENS=false',
    ],
    [
      'OPENID_SCOPE',
      'string',
      'Space-separated list of OpenID scopes. Must include offline_access for token reuse.',
      'OPENID_SCOPE=api://librechat/.default openid profile email offline_access',
    ],
    [
      'OPENID_AUDIENCE',
      'string',
      'Audience value for OpenID JWT validation and authorization requests. Comma-separated values are accepted for JWT validation; authorization requests use the first non-empty value. Required for Auth0 when OPENID_REUSE_TOKENS=true. See the note in the main OpenID section above.',
      'OPENID_AUDIENCE=https://api.librechat.com',
    ],
    [
      'OPENID_REUSE_MAX_SESSION_AGE_MS',
      'number',
      'Maximum age a reused OpenID session token is served before LibreChat forces an IdP refresh. Default: 900000 ms / 15 minutes.',
      'OPENID_REUSE_MAX_SESSION_AGE_MS=900000',
    ],
    [
      'OPENID_REFRESH_BRIDGE_GRACE_MS',
      'number',
      'Short recovery window for a rotated refresh token while LibreChat publishes the refreshed OpenID session. Default: 60000 ms / 1 minute.',
      'OPENID_REFRESH_BRIDGE_GRACE_MS=60000',
    ],
    [
      'OPENID_JWKS_URL_CACHE_ENABLED',
      'boolean',
      'Enable caching of signing key verification results.',
      'OPENID_JWKS_URL_CACHE_ENABLED=true',
    ],
    [
      'OPENID_JWKS_URL_CACHE_TIME',
      'number',
      'Cache duration in milliseconds (default: 600000 ms / 10 minutes).',
      'OPENID_JWKS_URL_CACHE_TIME=600000',
    ],
    [
      'OPENID_ON_BEHALF_FLOW_FOR_USERINFO_REQUIRED',
      'boolean',
      'Enable on-behalf-of flow for user info.',
      'OPENID_ON_BEHALF_FLOW_FOR_USERINFO_REQUIRED=true',
    ],
    [
      'OPENID_ON_BEHALF_FLOW_USERINFO_SCOPE',
      'string',
      'Scope for user info in on-behalf-of flow.',
      'OPENID_ON_BEHALF_FLOW_USERINFO_SCOPE=user.read',
    ],
    [
      'OPENID_USE_END_SESSION_ENDPOINT',
      'boolean',
      'Enable use of the end session endpoint for logout.',
      'OPENID_USE_END_SESSION_ENDPOINT=true',
    ],
    [
      'OPENID_MAX_LOGOUT_URL_LENGTH',
      'number',
      'Maximum logout URL length in characters before switching to logout_hint. Useful to prevent URI too long errors when id_token_hint exceeds server limits. Default: 2000.',
      'OPENID_MAX_LOGOUT_URL_LENGTH=2000',
    ],
  ]}
/>

`OPENID_REUSE_MAX_SESSION_AGE_MS` and `OPENID_REFRESH_BRIDGE_GRACE_MS` accept arithmetic expressions like `SESSION_EXPIRY`. Increase the session age toward the IdP access-token lifetime when your provider revokes the previous access token on refresh, so downstream consumers such as MCP servers can finish using a still-valid bearer token. Increase the bridge grace period only when slow session persistence or cross-replica publication needs more than the default minute to publish a rotated token.

<Callout type="note" title="Note">
  For detailed configuration steps and prerequisites, see [Re-use OpenID Tokens for Login
  Session](/docs/configuration/authentication/OAuth2-OIDC/token-reuse).
</Callout>

##### Microsoft Graph API / Entra ID Integration

When using Azure Entra ID (formerly Azure AD) as your OpenID provider, you can enable additional Microsoft Graph API features for enhanced people and group search capabilities within the permissions and sharing system.

<OptionTable
  options={[
    [
      'USE_ENTRA_ID_FOR_PEOPLE_SEARCH',
      'boolean',
      'Enable Entra ID people search integration in permissions/sharing system. When enabled, the people picker will search both local database and Entra ID.',
      'USE_ENTRA_ID_FOR_PEOPLE_SEARCH=false',
    ],
    [
      'ENTRA_ID_INCLUDE_OWNERS_AS_MEMBERS',
      'boolean',
      'When enabled, Entra ID group owners will be considered as members of the group.',
      'ENTRA_ID_INCLUDE_OWNERS_AS_MEMBERS=false',
    ],
    [
      'OPENID_GRAPH_SCOPES',
      'string',
      'Microsoft Graph API scopes needed for people/group search. Default scopes provide access to user profiles and group memberships.',
      'OPENID_GRAPH_SCOPES=User.Read,People.Read,GroupMember.Read.All,User.ReadBasic.All',
    ],
    [
      'GRAPH_API_SCOPES',
      'string',
      'Space-separated Microsoft Graph scopes requested by the OBO exchange for {{LIBRECHAT_GRAPH_ACCESS_TOKEN}} placeholders in YAML-defined MCP servers. Default: https://graph.microsoft.com/.default.',
      '# GRAPH_API_SCOPES=https://graph.microsoft.com/.default',
    ],
  ]}
/>

`GRAPH_API_SCOPES` is separate from `OPENID_GRAPH_SCOPES`: the former controls Graph tokens resolved into MCP configuration, while the latter controls Entra ID people and group search.

<Callout type="warning" title="Important Prerequisites">
  - You must have Azure Entra ID configured as your OpenID provider - **OpenID token reuse MUST be
  enabled** (`OPENID_REUSE_TOKENS=true`) - this feature will not work without it - Your Azure app
  registration must have the appropriate Microsoft Graph API permissions - For group search
  functionality, admin consent may be required for certain Graph API scopes
</Callout>

##### SharePoint Integration

LibreChat supports direct integration with SharePoint Online and OneDrive for Business, allowing users to select and attach files from their SharePoint libraries directly within conversations. This enterprise feature leverages the existing Azure Entra ID authentication.

<OptionTable
  options={[
    [
      'ENABLE_SHAREPOINT_FILEPICKER',
      'boolean',
      'Enable SharePoint file picker in chat and agent panels. When enabled, adds "From SharePoint" option in file attachment menu.',
      'ENABLE_SHAREPOINT_FILEPICKER=true',
    ],
    [
      'SHAREPOINT_BASE_URL',
      'string',
      'SharePoint tenant base URL. Required when SharePoint integration is enabled.',
      'SHAREPOINT_BASE_URL=https://yourtenant.sharepoint.com',
    ],
    [
      'SHAREPOINT_PICKER_SHAREPOINT_SCOPE',
      'string',
      'SharePoint-specific OAuth scope for the file picker. Used for authentication when opening the SharePoint file picker interface.',
      'SHAREPOINT_PICKER_SHAREPOINT_SCOPE=https://yourtenant.sharepoint.com/AllSites.Read',
    ],
    [
      'SHAREPOINT_PICKER_GRAPH_SCOPE',
      'string',
      'Microsoft Graph API scope for file downloads. Used for downloading files from SharePoint after selection.',
      'SHAREPOINT_PICKER_GRAPH_SCOPE=Files.Read.All',
    ],
  ]}
/>

<Callout type="error" title="Critical Requirements">
**All of the following must be configured for SharePoint integration to work:**
- Azure Entra ID authentication must be fully configured
- **`OPENID_REUSE_TOKENS=true`** is mandatory (uses on-behalf-of token flow)
- `OPENID_SCOPE` must include your LibreChat app API scope, for example `api://<client-id>/access_as_user`
- `OPENID_ON_BEHALF_FLOW_FOR_USERINFO_REQUIRED=true` is required when using that app-audience scope with Azure Entra ID
- Your Azure app registration must have SharePoint and Graph API permissions
- Your Azure app registration must expose the LibreChat API scope used in `OPENID_SCOPE`
- All four SharePoint environment variables must be set
- HTTPS is required in production environments
</Callout>

<Callout type="info" title="Feature Capabilities">
  When enabled, users can: - Access files from SharePoint document libraries and OneDrive for
  Business - Select multiple files at once (default max: 10 files) - See real-time download progress
  - Files are downloaded and attached to the conversation like regular uploads
</Callout>

For detailed SharePoint configuration instructions, see: [SharePoint Integration Guide](/docs/configuration/sharepoint)

#### SAML

For more information:

- [Auth0](/docs/configuration/authentication/SAML/auth0)

<Callout type="warning" title="Mutual Exclusion of OpenID and SAML">
If OpenID is enabled, SAML authentication will be automatically disabled.

Only one authentication method can be active at a time.

</Callout>

<OptionTable
  options={[
    [
      'SAML_ENTRY_POINT',
      'string',
      'The SAML identity provider (IdP) entry point URL.',
      'SAML_ENTRY_POINT=',
    ],
    ['SAML_ISSUER', 'string', 'The SAML service provider (SP) entity ID.', 'SAML_ISSUER='],
    [
      'SAML_CERT',
      'string',
      'The SAML signing certificate, provided as a file path or a one-line PEM string.',
      'SAML_CERT=',
    ],
    [
      'SAML_CALLBACK_URL',
      'string',
      'The callback URL for SAML authentication.',
      'SAML_CALLBACK_URL=/oauth/saml/callback',
    ],
    [
      'SAML_SESSION_SECRET',
      'string',
      'The secret for SAML session storage.',
      'SAML_SESSION_SECRET=',
    ],
    [
      'SAML_NAME_ID_FORMAT',
      'string',
      'Stable NameID format requested from the IdP. Persistent identifiers are recommended; transient identifiers are rejected.',
      '# SAML_NAME_ID_FORMAT=urn:oasis:names:tc:SAML:2.0:nameid-format:persistent',
    ],
    [
      'SAML_IDP_ISSUER',
      'string',
      'Expected IdP entity ID. When set, assertions with a missing or different issuer are rejected.',
      'SAML_IDP_ISSUER=',
    ],
    [
      'SAML_EMAIL_CLAIM',
      'string',
      '<Optional>: The attribute in the SAML assertion containing the user email. (default: email)',
      'SAML_EMAIL_CLAIM=',
    ],
    [
      'SAML_USERNAME_CLAIM',
      'string',
      '<Optional>: The attribute in the SAML assertion containing the username. (default: username)',
      'SAML_USERNAME_CLAIM=',
    ],
    [
      'SAML_GIVEN_NAME_CLAIM',
      'string',
      '<Optional>: The attribute in the SAML assertion containing the given name. (default: given_name)',
      'SAML_GIVEN_NAME_CLAIM=',
    ],
    [
      'SAML_FAMILY_NAME_CLAIM',
      'string',
      '<Optional>: The attribute in the SAML assertion containing the family name. (default: family_name)',
      'SAML_FAMILY_NAME_CLAIM=',
    ],
    [
      'SAML_PICTURE_CLAIM',
      'string',
      '<Optional>: The attribute in the SAML assertion containing the profile picture URL. (default: picture)',
      'SAML_PICTURE_CLAIM=',
    ],
    [
      'SAML_NAME_CLAIM',
      'string',
      '<Optional>: The attribute in the SAML assertion containing the full name.',
      'SAML_NAME_CLAIM=',
    ],
    [
      'SAML_BUTTON_LABEL',
      'string',
      '<Optional>: The label for the SAML login button.',
      'SAML_BUTTON_LABEL=',
    ],
    [
      'SAML_IMAGE_URL',
      'string',
      '<Optional>: The URL of the SAML login button image.',
      'SAML_IMAGE_URL=',
    ],
    [
      'SAML_USE_AUTHN_RESPONSE_SIGNED',
      'boolean',
      '<Optional>: If "true", signs the entire SAML Response. Otherwise, only the Assertion is signed (default).',
      'SAML_USE_AUTHN_RESPONSE_SIGNED=',
    ],
  ]}
/>

#### LDAP/AD Authentication

For more information: **[LDAP/AD Authentication](/docs/configuration/authentication/ldap)**

<OptionTable
  options={[
    ['LDAP_URL', 'string', 'LDAP server URL.', 'LDAP_URL=ldap://localhost:389'],
    ['LDAP_BIND_DN', 'string', 'Bind DN', 'LDAP_BIND_DN=cn=root'],
    ['LDAP_BIND_CREDENTIALS', 'string', 'Password for bindDN', 'LDAP_BIND_CREDENTIALS=password'],
    [
      'LDAP_USER_SEARCH_BASE',
      'string',
      'LDAP user search base',
      'LDAP_USER_SEARCH_BASE=o=users,o=example.com',
    ],
    ['LDAP_SEARCH_FILTER', 'string', 'LDAP search filter', 'LDAP_SEARCH_FILTER=mail={{username}}'],
    [
      'LDAP_CA_CERT_PATH',
      'string',
      'CA certificate path.',
      'LDAP_CA_CERT_PATH=/path/to/root_ca_cert.crt',
    ],
    [
      'LDAP_TLS_REJECT_UNAUTHORIZED',
      'string',
      'LDAP TLS verification',
      'LDAP_TLS_REJECT_UNAUTHORIZED=true',
    ],
    [
      'LDAP_STARTTLS',
      'string',
      'Enable LDAP StartTLS for upgrading the connection to TLS. Set to true to enable this feature.',
      'LDAP_STARTTLS=true',
    ],
    [
      'LDAP_LOGIN_USES_USERNAME',
      'boolean',
      'Use username instead of email for LDAP login.',
      '# LDAP_LOGIN_USES_USERNAME=true',
    ],
    [
      'LDAP_ID',
      'string',
      'LDAP attribute for unique user ID. Default: uid or sAMAccountName, mail.',
      '# LDAP_ID=uid',
    ],
    [
      'LDAP_USERNAME',
      'string',
      'LDAP attribute for username. Default: givenName or mail.',
      '# LDAP_USERNAME=givenName',
    ],
    [
      'LDAP_EMAIL',
      'string',
      'LDAP attribute for email. Default: mail.',
      '# LDAP_EMAIL=userPrincipalName',
    ],
    [
      'LDAP_FULL_NAME',
      'string',
      'LDAP attribute(s) for full name. Can be comma-separated. Default: givenName + surname.',
      '# LDAP_FULL_NAME=givenName,surname',
    ],
  ]}
/>

### Password Reset

Email is used for account verification and password reset. LibreChat supports both Mailgun API and traditional SMTP services. See: **[Email setup](/docs/configuration/authentication/email)**

**Important Note**: You must configure either Mailgun (recommended for servers that block SMTP) or SMTP for email to work.

> **Warning**: Failing to set valid values for either Mailgun or SMTP will result in LibreChat using the unsecured password reset!

#### Mailgun Configuration (Recommended)

Mailgun is particularly useful for deployments on servers that block SMTP ports. When both `MAILGUN_API_KEY` and `MAILGUN_DOMAIN` are set, LibreChat will use Mailgun instead of SMTP.

<OptionTable
  options={[
    [
      'MAILGUN_API_KEY',
      'string',
      'Your Mailgun API key (required for Mailgun).',
      'MAILGUN_API_KEY=',
    ],
    [
      'MAILGUN_DOMAIN',
      'string',
      'Your Mailgun domain (required for Mailgun).',
      'MAILGUN_DOMAIN=mg.yourdomain.com',
    ],
    [
      'MAILGUN_HOST',
      'string',
      'Custom Mailgun API host (optional). Use https://api.eu.mailgun.net for EU region.',
      'MAILGUN_HOST=https://api.mailgun.net',
    ],
    ['EMAIL_FROM', 'string', 'From email address. Required.', 'EMAIL_FROM=noreply@librechat.ai'],
    [
      'EMAIL_FROM_NAME',
      'string',
      'From name (defaults to APP_TITLE if not set).',
      'EMAIL_FROM_NAME=',
    ],
  ]}
/>

#### SMTP Configuration

If Mailgun is not configured, LibreChat will fall back to SMTP settings.

> **Warning**: If using `EMAIL_SERVICE`, **do NOT** set the extended connection parameters:
> HOST, PORT, ENCRYPTION, ENCRYPTION_HOSTNAME, ALLOW_SELFSIGNED.

See: **[nodemailer well-known-services](https://nodemailer.com/smtp/well-known-services)**

<OptionTable
  options={[
    ['EMAIL_SERVICE', 'string', 'Email service (e.g., Gmail, Outlook).', 'EMAIL_SERVICE='],
    ['EMAIL_HOST', 'string', 'Mail server host.', 'EMAIL_HOST='],
    ['EMAIL_PORT', 'number', 'Mail server port.', 'EMAIL_PORT=25'],
    ['EMAIL_ENCRYPTION', 'string', 'Encryption method (starttls, tls, etc.).', 'EMAIL_ENCRYPTION='],
    [
      'EMAIL_ENCRYPTION_HOSTNAME',
      'string',
      'Hostname for encryption.',
      'EMAIL_ENCRYPTION_HOSTNAME=',
    ],
    [
      'EMAIL_ALLOW_SELFSIGNED',
      'boolean',
      'Allow self-signed certificates.',
      'EMAIL_ALLOW_SELFSIGNED=',
    ],
    ['EMAIL_USERNAME', 'string', 'Username for authentication.', 'EMAIL_USERNAME='],
    ['EMAIL_PASSWORD', 'string', 'Password for authentication.', 'EMAIL_PASSWORD='],
    ['EMAIL_FROM_NAME', 'string', 'From name.', 'EMAIL_FROM_NAME='],
    ['EMAIL_FROM', 'string', 'From email address. Required.', 'EMAIL_FROM=noreply@librechat.ai'],
  ]}
/>

### Firebase CDN

See: **[Firebase CDN Configuration](/docs/configuration/cdn/firebase)**

<Callout type="warning" title="Important">
  - If you are using Firebase as your file storage strategy, set `fileStrategy` or `fileStrategies`
  to `firebase` in your `librechat.yaml` configuration file. For more information on configuring the
  `librechat.yaml` file, please refer to the YAML Configuration Guide: [Custom Endpoints &
  Configuration](/docs/configuration/librechat_yaml)
</Callout>

<OptionTable
  options={[
    ['FIREBASE_API_KEY', 'string', 'The API key for your Firebase project.', 'FIREBASE_API_KEY='],
    [
      'FIREBASE_AUTH_DOMAIN',
      'string',
      'The Firebase Auth domain for your project.',
      'FIREBASE_AUTH_DOMAIN=',
    ],
    ['FIREBASE_PROJECT_ID', 'string', 'The ID of your Firebase project.', 'FIREBASE_PROJECT_ID='],
    [
      'FIREBASE_STORAGE_BUCKET',
      'string',
      'The Firebase Storage bucket for your project.',
      'FIREBASE_STORAGE_BUCKET=',
    ],
    [
      'FIREBASE_MESSAGING_SENDER_ID',
      'string',
      'The Firebase Cloud Messaging sender ID.',
      'FIREBASE_MESSAGING_SENDER_ID=',
    ],
    ['FIREBASE_APP_ID', 'string', 'The Firebase App ID for your project.', 'FIREBASE_APP_ID='],
  ]}
/>

### Amazon S3 and CloudFront

See: **[Amazon S3 Configuration](/docs/configuration/cdn/s3)** and **[CloudFront with S3](/docs/configuration/cdn/cloudfront)**

<Callout type="warning" title="Important">
  If you are using S3 as your file storage strategy, set `fileStrategy` or `fileStrategies` in your
  `librechat.yaml` configuration file. If you use CloudFront, S3 is still required as the storage
  origin.
</Callout>

<OptionTable
  options={[
    [
      'AWS_ACCESS_KEY_ID',
      'string',
      'Your IAM user access key ID. Optional if using IRSA.',
      'AWS_ACCESS_KEY_ID=your_access_key_id',
    ],
    [
      'AWS_SECRET_ACCESS_KEY',
      'string',
      'Your IAM user secret access key. Optional if using IRSA.',
      'AWS_SECRET_ACCESS_KEY=your_secret_access_key',
    ],
    [
      'AWS_REGION',
      'string',
      'The AWS region where your S3 bucket is located.',
      'AWS_REGION=us-east-1',
    ],
    [
      'AWS_BUCKET_NAME',
      'string',
      'The name of the S3 bucket for file storage.',
      'AWS_BUCKET_NAME=your_bucket_name',
    ],
    [
      'AWS_ENDPOINT_URL',
      'string',
      'Custom AWS endpoint URL (optional). For S3-compatible services. Include the URL scheme, such as https://a7g8.da.idrivee2-32.com.',
      '# AWS_ENDPOINT_URL=https://your_endpoint_url',
    ],
    [
      'AWS_FORCE_PATH_STYLE',
      'boolean',
      'Set to true for S3-compatible providers that require path-style URLs (e.g. MinIO, Hetzner, Backblaze B2). Not needed for AWS S3. Default: false.',
      '# AWS_FORCE_PATH_STYLE=false',
    ],
    [
      'CLOUDFRONT_KEY_PAIR_ID',
      'string',
      'CloudFront public key pair ID. Required for signed cookies and signed CloudFront download URLs.',
      '# CLOUDFRONT_KEY_PAIR_ID=K1234567890ABC',
    ],
    [
      'CLOUDFRONT_PRIVATE_KEY',
      'string',
      'CloudFront private key PEM. Required for signed cookies and signed CloudFront download URLs. Preserve PEM newlines when injecting this secret.',
      '# CLOUDFRONT_PRIVATE_KEY="-----BEGIN RSA PRIVATE KEY-----\\n...\\n-----END RSA PRIVATE KEY-----"',
    ],
  ]}
/>

> **Note:** For Kubernetes deployments (e.g., on EKS), you can use IRSA (IAM Roles for Service Accounts) instead of providing explicit credentials. In that case, only `AWS_REGION` and `AWS_BUCKET_NAME` are required.

### Azure Blob Storage CDN

See: **[Azure Blob Storage CDN Configuration](/docs/configuration/cdn/azure)**

<Callout type="warning" title="Important">
  If you are using Azure Blob Storage as your file storage strategy, set `fileStrategy` or
  `fileStrategies` to `azure_blob` in your `librechat.yaml` configuration file.
</Callout>

<OptionTable
  options={[
    [
      'AZURE_STORAGE_CONNECTION_STRING',
      'string',
      'Azure Blob Storage connection string. Use this OR AZURE_STORAGE_ACCOUNT_NAME for Managed Identity.',
      'AZURE_STORAGE_CONNECTION_STRING=DefaultEndpointsProtocol=https;AccountName=...',
    ],
    [
      'AZURE_STORAGE_ACCOUNT_NAME',
      'string',
      'Azure Storage account name. Use for Managed Identity authentication (do not set connection string).',
      '# AZURE_STORAGE_ACCOUNT_NAME=yourAccountName',
    ],
    [
      'AZURE_STORAGE_PUBLIC_ACCESS',
      'boolean',
      'Enable public access for blobs. Default: false.',
      'AZURE_STORAGE_PUBLIC_ACCESS=false',
    ],
    [
      'AZURE_CONTAINER_NAME',
      'string',
      'Container name for file storage. Default: files.',
      'AZURE_CONTAINER_NAME=files',
    ],
  ]}
/>

> **Note:** Use either `AZURE_STORAGE_CONNECTION_STRING` (Option A) or `AZURE_STORAGE_ACCOUNT_NAME` with Managed Identity (Option B), not both.

### UI

#### Help and FAQ Button

<OptionTable
  options={[
    [
      'HELP_AND_FAQ_URL',
      'string',
      'Help and FAQ URL. If empty or commented, the button is enabled. To disable the Help and FAQ button, set to "/".',
      'HELP_AND_FAQ_URL=https://librechat.ai',
    ],
  ]}
/>

**Behaviour:**

Sets the [Cache-Control](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cache-Control) headers for static files. These configurations only trigger when the `NODE_ENV` is set to `production`.

Properly setting cache headers is crucial for optimizing the performance and efficiency of your web application. By controlling how long browsers and CDNs store copies of your static files, you can significantly reduce server load, decrease page load times, and improve the overall user experience.

- Uncomment `STATIC_CACHE_MAX_AGE` to change the `max-age` for static files. By default this is set to 4 weeks.
- Uncomment `STATIC_CACHE_S_MAX_AGE` to change the `s-maxage` for static files. By default this is set to 1 week.
  - This is for the _shared cache_, which is used by CDNs and proxies.

#### App Title and Footer

<OptionTable
  options={[
    ['APP_TITLE', 'string', 'App title.', 'APP_TITLE=LibreChat'],
    ['CUSTOM_FOOTER', 'string', 'Custom footer.', '# CUSTOM_FOOTER="My custom footer"'],
    [
      'TEMP_CHAT_RETENTION_HOURS',
      'number',
      '**Deprecated:** Use `interface.temporaryChatRetention` in librechat.yaml instead. Hours to retain temporary chats. Default: 720 (30 days).',
      '# TEMP_CHAT_RETENTION_HOURS=168',
    ],
  ]}
/>

**Behaviour:**

- Uncomment `CUSTOM_FOOTER` to add a custom footer.
- Uncomment and leave `CUSTOM_FOOTER` empty to remove the footer.
- You can now add one or more links in the CUSTOM_FOOTER value using the following format: `[Anchor text](URL)`. Each link should be delineated with a pipe (`|`).

> **Markdown example:** `CUSTOM_FOOTER=[Link 1](http://example1.com) | [Link 2](http://example2.com)`

#### Birthday Hat

<OptionTable
  options={[
    ['SHOW_BIRTHDAY_ICON', 'boolean', 'Show the birthday hat icon.', '# SHOW_BIRTHDAY_ICON=true'],
  ]}
/>

**Behaviour:**

- The birthday hat icon will show automatically on February 11th (LibreChat's birthday).
- Set `SHOW_BIRTHDAY_ICON` to `false` to disable the birthday hat.
- Set `SHOW_BIRTHDAY_ICON` to `true` to enable the birthday hat all the time.

### Analytics

#### Google Tag Manager

LibreChat supports Google Tag Manager for analytics. You will need a Google Tag Manager ID to enable it in LibreChat. Follow [this guide](https://support.google.com/tagmanager/answer/9442095?sjid=10155093630524971297-EU) to generate a Google Tag Manager ID and configure Google Analytics. Then set the `ANALYTICS_GTM_ID` environment variable to your Google Tag Manager ID.

**Note:** If `ANALYTICS_GTM_ID` is not set, Google Tag Manager will not be enabled. If it is set incorrectly, you will see failing requests to `gtm.js`

<OptionTable
  options={[['ANALYTICS_GTM_ID', 'string', 'Google Tag Manager ID.', 'ANALYTICS_GTM_ID=']]}
/>

#### Conversation Import

Configure limits for conversation file imports to prevent memory issues.

<OptionTable
  options={[
    [
      'CONVERSATION_IMPORT_MAX_FILE_SIZE_BYTES',
      'number',
      'Maximum file size in bytes for conversation imports. Default: 0 (no limit enforced). Example: 262144000 (250 MiB).',
      '# CONVERSATION_IMPORT_MAX_FILE_SIZE_BYTES=262144000',
    ],
  ]}
/>

#### Inline File Previews

Control how large generated files can be before LibreChat skips inline preview extraction and leaves them download-only.

<OptionTable
  options={[
    [
      'FILE_PREVIEW_MAX_EXTRACT_BYTES',
      'number',
      'Maximum source file size in bytes for code-execution artifact inline previews, including DOCX, XLSX, CSV, PPTX, POTX, text, and PDF-like files. Default: 2097152 (2 MiB). Rendered HTML previews are still capped separately, so very rich files may skip preview even below this value.',
      '# FILE_PREVIEW_MAX_EXTRACT_BYTES=2097152',
    ],
  ]}
/>

### MCP (Model Context Protocol)

Configure Model Context Protocol settings for enhanced server management and OAuth support.

#### MCP Server Configuration

<OptionTable
  options={[
    [
      'MCP_OAUTH_ON_AUTH_ERROR',
      'boolean',
      'Treat 401/403 responses as OAuth requirement when no oauth metadata found.',
      'MCP_OAUTH_ON_AUTH_ERROR=true',
    ],
    [
      'MCP_OAUTH_DETECTION_TIMEOUT',
      'number',
      'Timeout for OAuth detection requests in milliseconds.',
      'MCP_OAUTH_DETECTION_TIMEOUT=5000',
    ],
    [
      'MCP_OAUTH_HANDLING_TIMEOUT',
      'number',
      'How long LibreChat waits for a user to complete an MCP OAuth flow before timing out. Default: 600000 ms (10 minutes).',
      'MCP_OAUTH_HANDLING_TIMEOUT=600000',
    ],
    [
      'MCP_OAUTH_FLOW_TTL',
      'number',
      'How long MCP OAuth flow state is retained. LibreChat clamps this above MCP_OAUTH_HANDLING_TIMEOUT so callbacks near the deadline can still complete. Default: 900000 ms (15 minutes).',
      'MCP_OAUTH_FLOW_TTL=900000',
    ],
    [
      'MCP_CONNECTION_CHECK_TTL',
      'number',
      'Cache connection status checks for this many milliseconds to avoid expensive verification.',
      'MCP_CONNECTION_CHECK_TTL=30000',
    ],
    [
      'MCP_TOOLS_LIST_MAX_PAGES',
      'number',
      'Maximum number of tools/list pages to request when an MCP server paginates its tool list (cursor pagination). Bounds the pagination loop so a misbehaving server cannot stall tool discovery. Clamped to a minimum of 1. Default: 50.',
      'MCP_TOOLS_LIST_MAX_PAGES=50',
    ],
    [
      'MCP_SKIP_CODE_CHALLENGE_CHECK',
      'boolean',
      'Skip code challenge method validation. When set to true, forces S256 code challenge even if not advertised in .well-known/openid-configuration',
      'MCP_SKIP_CODE_CHALLENGE_CHECK=false',
    ],
    [
      'MCP_STREAMABLE_HTTP_MAX_RESPONSE_BYTES',
      'number',
      'Maximum bytes allowed in a non-GET streamable HTTP MCP response before rejecting it. Set to 0 to disable. Default: 16777216 (16 MiB).',
      '# MCP_STREAMABLE_HTTP_MAX_RESPONSE_BYTES=16777216',
    ],
    [
      'MCP_STREAMABLE_HTTP_MAX_LINE_BYTES',
      'number',
      'Maximum bytes allowed in one SSE line for non-GET streamable HTTP MCP responses. Set to 0 to disable. Default: 5242880 (5 MiB).',
      '# MCP_STREAMABLE_HTTP_MAX_LINE_BYTES=5242880',
    ],
  ]}
/>

### Other

#### Redis

Redis provides significant performance improvements and enables horizontal scaling capabilities for LibreChat.

**Note:** Redis support is experimental, and you may encounter some problems when using it.

**Important:** If using Redis, you should flush the cache after changing any LibreChat settings.

For detailed configuration and examples, see: **[Redis Configuration Guide](/docs/configuration/redis)**

<OptionTable
  options={[
    [
      'USE_REDIS',
      'boolean',
      'Enable Redis for caching and session storage. When true, REDIS_URI must be provided.',
      'USE_REDIS=true',
    ],
    [
      'USE_REDIS_STREAMS',
      'boolean',
      'Enable Redis for resumable LLM streams. Defaults to USE_REDIS value if not set. Set to false to use in-memory storage for streams.',
      '# USE_REDIS_STREAMS=true',
    ],
    [
      'STREAM_DELTA_COALESCE_MS',
      'integer',
      'Batch Redis stream delta publications within this many milliseconds. Unset or 0 disables batching; 25 is recommended and values are capped at 1000.',
      '# STREAM_DELTA_COALESCE_MS=25',
    ],
    [
      'REDIS_URI',
      'string',
      'Redis connection URI. For single instance: `redis://host:port`. For cluster: comma-separated URIs.',
      'REDIS_URI=redis://127.0.0.1:6379',
    ],
    [
      'USE_REDIS_CLUSTER',
      'boolean',
      'Enable Redis cluster mode when using a single URI',
      '# USE_REDIS_CLUSTER="true"',
    ],
    [
      'REDIS_CLUSTER_SAFE_DELETE',
      'boolean',
      'Delete Redis cache keys individually to avoid CROSSSLOT errors on single-endpoint managed Redis services that shard keys internally.',
      '# REDIS_CLUSTER_SAFE_DELETE=true',
    ],
    [
      'REDIS_USERNAME',
      'string',
      'Redis username for authentication. Overrides username in URI if both provided.',
      '# REDIS_USERNAME=your_redis_username',
    ],
    [
      'REDIS_PASSWORD',
      'string',
      'Redis password for authentication. Overrides password in URI if both provided.',
      '# REDIS_PASSWORD=your_redis_password',
    ],
    [
      'REDIS_CA',
      'string',
      'Path to CA certificate for TLS verification when using rediss:// protocol.',
      '# REDIS_CA=/path/to/ca-cert.pem',
    ],
    [
      'REDIS_KEY_PREFIX',
      'string',
      'Static prefix for all Redis keys to prevent cross-deployment contamination.',
      '# REDIS_KEY_PREFIX=librechat-prod-v2',
    ],
    [
      'REDIS_KEY_PREFIX_VAR',
      'string',
      'Environment variable name containing dynamic prefix (e.g., K_REVISION for Cloud Run). Cannot be used with REDIS_KEY_PREFIX.',
      '# REDIS_KEY_PREFIX_VAR=K_REVISION',
    ],
    [
      'REDIS_MAX_LISTENERS',
      'number',
      'Maximum event listeners per Redis client. Prevents memory leaks. Default: 40.',
      '# REDIS_MAX_LISTENERS=40',
    ],
    [
      'REDIS_READONLY_RECOVERY_INTERVAL',
      'number',
      'Minimum milliseconds between forced Keyv reconnect attempts after READONLY replies during standalone or Sentinel failover. Default: 5000.',
      '# REDIS_READONLY_RECOVERY_INTERVAL=5000',
    ],
    [
      'REDIS_PING_INTERVAL',
      'number',
      'Ping interval in seconds to maintain connections. Default: 0 (disabled). Only set if experiencing timeouts.',
      '# REDIS_PING_INTERVAL=300',
    ],
    [
      'FORCED_IN_MEMORY_CACHE_NAMESPACES',
      'string',
      'Comma-separated cache keys to force in-memory storage even when Redis is enabled.',
      '# FORCED_IN_MEMORY_CACHE_NAMESPACES=ROLES,MESSAGES',
    ],
    [
      'AUTH_USER_CACHE_MODE',
      'string',
      'Set exactly to `on` to cache authenticated user documents during request bursts. Requires Redis and a Redis-backed AUTH_USER_DOC namespace. Default: off.',
      '# AUTH_USER_CACHE_MODE=off',
    ],
    [
      'USER_PRINCIPALS_CACHE_TTL_MS',
      'number',
      'TTL in milliseconds for cached group memberships used in ACL checks. Set to 0 to disable. Default: 300000.',
      '# USER_PRINCIPALS_CACHE_TTL_MS=300000',
    ],
    [
      'USER_PRINCIPALS_LOCK_TTL_MS',
      'number',
      'Redis lock TTL in milliseconds for cross-container principal-cache builds. Set to 0 to disable build locking. Default: 5000.',
      '# USER_PRINCIPALS_LOCK_TTL_MS=5000',
    ],
    [
      'USER_PRINCIPALS_LOCK_WAIT_MS',
      'number',
      'Maximum time to wait for another container to fill the principal cache before reading the database directly. Defaults to USER_PRINCIPALS_LOCK_TTL_MS.',
      '# USER_PRINCIPALS_LOCK_WAIT_MS=5000',
    ],
    [
      'REDIS_USE_ALTERNATIVE_DNS_LOOKUP',
      'boolean',
      'Enable alternate dnsLookup for TLS connections with AWS Elasticache. Required for Elasticache clusters with TLS.',
      '# REDIS_USE_ALTERNATIVE_DNS_LOOKUP=true',
    ],
  ]}
/>

Notes:

- When `USE_REDIS=true`, you must provide `REDIS_URI` or the application will throw an error.
- Current LibreChat clients negotiate generation protocol v2 automatically. The retired `GENERATION_PROTOCOL_VERSION` variable is no longer read. See [Generation Protocol Compatibility](/docs/configuration/redis#generation-protocol-compatibility) before mixing release versions or rolling back.
- Enable `STREAM_DELTA_COALESCE_MS` only after every replica supports batch frames. Older subscribers drop coalesced frames. See [Stream Delta Coalescing](/docs/configuration/redis#stream-delta-coalescing).
- For Redis Cluster mode, provide multiple URIs: `redis://node1:7001,redis://node2:7002,redis://node3:7003` (cluster mode is auto-detected).
- For single-endpoint managed Redis services that shard keys internally, keep `USE_REDIS_CLUSTER=false` and set `REDIS_CLUSTER_SAFE_DELETE=true` if cache clears fail with `CROSSSLOT` errors.
- `REDIS_READONLY_RECOVERY_INTERVAL` debounces Keyv reconnect attempts after a failover leaves an open socket attached to a demoted read-only replica. Redis Cluster clients use their native topology handling instead.
- Use `rediss://` protocol for TLS connections and set `REDIS_CA` if your CA is not publicly trusted.
- `REDIS_KEY_PREFIX_VAR` and `REDIS_KEY_PREFIX` are mutually exclusive.
- **AWS Elasticache with TLS**: Elasticache may need to use an alternate dnsLookup for TLS connections. Set `REDIS_USE_ALTERNATIVE_DNS_LOOKUP=true` if using Elasticache with TLS. See [ioredis documentation](https://www.npmjs.com/package/ioredis) for more details.

#### Leader Election

Configure distributed leader election for multi-instance deployments with Redis. Leader election ensures only one instance performs certain operations like scheduled tasks.

<OptionTable
  options={[
    [
      'LEADER_LEASE_DURATION',
      'number',
      'Duration in seconds that the leader lease is valid before it expires. Default: 25.',
      'LEADER_LEASE_DURATION=25',
    ],
    [
      'LEADER_RENEW_INTERVAL',
      'number',
      'Interval in seconds at which the leader renews its lease. Default: 10.',
      'LEADER_RENEW_INTERVAL=10',
    ],
    [
      'LEADER_RENEW_ATTEMPTS',
      'number',
      'Maximum number of retry attempts when renewing the lease fails. Default: 3.',
      'LEADER_RENEW_ATTEMPTS=3',
    ],
    [
      'LEADER_RENEW_RETRY_DELAY',
      'number',
      'Delay in seconds between retry attempts when renewing the lease. Default: 0.5.',
      'LEADER_RENEW_RETRY_DELAY=0.5',
    ],
  ]}
/>

Notes:

- Leader election requires Redis to be enabled (`USE_REDIS=true`).
- These settings are only relevant for multi-instance deployments.
- The leader lease must be renewed before expiration to maintain leadership.
- If lease renewal fails after max attempts, the instance will relinquish leadership.
