> Documentation index: [Saleor](/llms.txt) · [This section](/setup/llms.txt)
> Source: https://docs.saleor.io/setup/configuration

# Environment Variables

Saleor follows the [12-factor](https://12factor.net/) approach, so you can configure Saleor using environment variables.

Below is a list of available environment variables and their default values.

<a id="setting-environment-variables"></a>

## Setting environment variables

While most production environments offer a way to configure the environment, you will likely want to set them on your local development machine first.

**Windows (Command Prompt)**

To set the variable temporarily, until the terminal window is closed:

```shell
set SECRET_KEY "<mysecretkey>"
```

To permanently set the variable:

```shell
setx SECRET_KEY "<mysecretkey>"
```

**Windows (PowerShell)**

To set the variable temporarily, until the terminal window is closed:

```shell
$Env:SECRET_KEY = "<mysecretkey>"
```

To permanently set the variable:

```shell
setx SECRET_KEY "<mysecretkey>"
```

**Linux/MacOS**

To set the variable temporarily, until the terminal window is closed:

```shell
export SECRET_KEY="<mysecretkey>"
```

To permanently set the variable, use [direnv](https://direnv.net/).

**Docker**

Use the `--env` flag to pass environment variables to Docker containers:

```shell
docker run --env SECRET_KEY="<mysecretkey>" saleor
```

<a id="general-configuration"></a>

## General configuration

<a id="allowed_client_hosts"></a>

### `ALLOWED_CLIENT_HOSTS`

A list of strings representing host/domain names of client applications (storefront or dashboard) that use this Saleor instance as a backend. Values in this list should be URLs in [RFC 1808](https://tools.ietf.org/html/rfc1808) format.

Some operations, such as registering a new account or resetting the password, involve sending an email from the backend with a link that users need to click to confirm the action. The backend doesn't know the structure of frontend applications' routing, and the path to the view where users can proceed with the operation needs to be passed as arguments in GraphQL mutations. These paths are validated against URLs configured in the `ALLOWED_CLIENT_HOSTS` setting.

`ALLOWED_CLIENT_HOSTS` is required in production mode (with `DEBUG=False`). In local development (`DEBUG=True`), when it's not set, the paths are validated against `localhost, 127.0.0.1`.

Multiple values should be separated with a comma.

<a id="allowed_graphql_origins"></a>

### `ALLOWED_GRAPHQL_ORIGINS`

Controls the value of [`Access-Control-Allow-Origin`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Origin) response header. Defaults to `*`.

<a id="allowed_hosts"></a>

### `ALLOWED_HOSTS`

This variable controls [Django's allowed hosts](https://docs.djangoproject.com/en/3.0/ref/settings/#allowed-hosts) setting. It defaults to `localhost`.

Multiple values should be separated with a comma.

<a id="cache_url"></a>

### `CACHE_URL`

The URL of a cache database. It defaults to local process memory.

Valkey is recommended.

**Example**: `redis://redis.example.com:6379/0`

<a id="celery_broker_url"></a>

### `CELERY_BROKER_URL`

Default task broker URL. You can read more about configuring this at [Celery Documentation.](https://docs.celeryproject.org/en/stable/userguide/configuration.html#broker-url)

<a id="checkout_ttl_before_releasing_funds"></a>

### `CHECKOUT_TTL_BEFORE_RELEASING_FUNDS`

Defines the TTL of checkout before it is marked as abandoned, and assigned funds will be released. The value should be a time expression like `5m`, `5 minutes`, `5d`, `5 days`, `1w`, or `1 week`. Defaults to `6 hours`.

<a id="database_url"></a>

### `DATABASE_URL`

The connection URL to a PostgreSQL database. Defaults to `postgres://saleor:saleor@localhost:5432/saleor`.

Format: `postgres://<username>:<password>@<hostname>:<port>/<database-name>`

<a id="debug"></a>

### `DEBUG`

Controls [Django's debug mode](https://docs.djangoproject.com/en/3.0/ref/settings/#s-debug). It defaults to `True`.

<a id="default_country"></a>

### `DEFAULT_COUNTRY`

Indicates the default country of your store. Depending on what setup you require, this variable also controls the default VAT, shipping country, etc. Defaults to `US`.

<a id="default_currency"></a>

### `DEFAULT_CURRENCY`

Indicates a default currency which is a basis for all prices entered and stored in your store. Defaults to `USD`.

<a id="default_from_email"></a>

### `DEFAULT_FROM_EMAIL`

Indicates a default email address to use for all outgoing mail.

<a id="enable_debug_toolbar"></a>

### `ENABLE_DEBUG_TOOLBAR`

Controls whether to run [Django Debug Toolbar](https://django-debug-toolbar.readthedocs.io/en/latest/). Defaults to `False`.

To use the toolbar, you must also enable the `PLAYGROUND_ENABLED` setting. Then, the toolbar will be rendered when accessing the `/graphql/` URL. Note that using the toolbar is recommended only locally and should be disabled in production, as it affects the performance and may potentially reveal sensitive or private information.

<a id="email_url"></a>

### `EMAIL_URL`

The URL of the email gateway. Defaults to printing everything to the console.

Some examples:

| Description | URL |
| --- | --- |
| Amazon SES | `smtp://username:password@email-smtp.us-east-1.amazonaws.com:587/?tls=True` |
| Gmail | `smtp://my.gmail.username@gmail.com:my-password@smtp.gmail.com:465/?ssl=True` |
| Mailgun | `smtp://username:password@smtp.mailgun.org:465/?ssl=True` |
| Mailjet | `smtp://username:password@in-v3.mailjet.com:587/?tls=True` |
| OVH | `smtp://username@example.com:my-password@pro1.mail.ovh.net:587/?tls=True` |
| SendGrid | `smtp://apikey:your.api.key@smtp.sendgrid.com:465/?ssl=True` |
| A SMTP server unencrypted | `smtp://username@example.com:my-password@smtp.example.com:25/` |

**Example:** `smtp://user:password@smtp.example.com:465/?ssl=True`

caution

If your password contains special characters, it has to be percentencoded. [Read more](https://github.com/migonzalvar/dj-email-url?tab=readme-ov-file#supported-backends)

<a id="user_email_url"></a>

### `USER_EMAIL_URL`

The URL used by [`UserEmails`](/developer/app-store/legacy-plugins/user-emails.md).

Some examples:

| Description | URL |
| --- | --- |
| Amazon SES | `smtp://username:password@email-smtp.us-east-1.amazonaws.com:587/?tls=True` |
| Gmail | `smtp://my.gmail.username@gmail.com:my-password@smtp.gmail.com:465/?ssl=True` |
| Mailgun | `smtp://username:password@smtp.mailgun.org:465/?ssl=True` |
| Mailjet | `smtp://username:password@in-v3.mailjet.com:587/?tls=True` |
| OVH | `smtp://username@example.com:my-password@pro1.mail.ovh.net:587/?tls=True` |
| SendGrid | `smtp://apikey:your.api.key@smtp.sendgrid.com:465/?ssl=True` |
| A SMTP server unencrypted | `smtp://username@example.com:my-password@smtp.example.com:25/` |

**Example:** `smtp://user:password@smtp.example.com:465/?ssl=True`

caution

If your password contains special characters, it has to be percentencoded. [Read more](https://github.com/migonzalvar/dj-email-url?tab=readme-ov-file#supported-backends)

<a id="federated_query_max_entities"></a>

### `FEDERATED_QUERY_MAX_ENTITIES`

Sets upper limit on how many entities may be requested by Apollo Federation's gateway for a single GraphQL query. Defaults to `100`. Set to `0` to remove this limit.

<a id="graphql_query_max_complexity"></a>

### `GRAPHQL_QUERY_MAX_COMPLEXITY`

Controls maximum allowed complexity (cost) of a GraphQL query. If the query's complexity exceeds this limit, it will not be executed, and GraphQL API will return an error instead.

Set `0` to remove this limit.

<a id="internal_ips"></a>

### `INTERNAL_IPS`

Controls [Django's internal IPs setting](https://docs.djangoproject.com/en/3.0/ref/settings/#s-internal-ips). Defaults to `127.0.0.1`.

Multiple values should be separated with a comma.

<a id="http_ip_filter_enabled"></a>

### `HTTP_IP_FILTER_ENABLED`

_Added in v3.16_

A boolean setting that controls whether or not to enable IP filtering in HTTP(S) network calls (webhooks, OIDC, etc.).

When set to `True` (default) it will reject private and loopback IP address ranges (see also [`HTTP_IP_FILTER_ALLOW_LOOPBACK_IPS`](#http_ip_filter_allow_loopback_ips)).

It defaults to `True`, and is recommended to be enabled on environments where staff users are untrusted, and thus could lead to [SSRF attacks](https://cwe.mitre.org/data/definitions/918.html).

<a id="http_ip_filter_allow_loopback_ips"></a>

### `HTTP_IP_FILTER_ALLOW_LOOPBACK_IPS`

_Added in v3.16_

When set to `False` (default), the HTTP IP filter will reject loopback IP addresses (127.0.0.0 to 127.255.255.255 range).

<a id="jwt_ttl_access"></a>

### `JWT_TTL_ACCESS`

The time until JWT access tokens expire. The value should be a time expression like `5m`, `5 minutes`, `5d`, `5 days`, `1w`, or `1 week`. Defaults to `5 minutes`.

<a id="jwt_ttl_refresh"></a>

### `JWT_TTL_REFRESH`

The time until JWT refresh tokens expire. The value should be a time expression like `5m`, `5 minutes`, `5d`, `5 days`, `1w`, or `1 week`. Defaults to `30 days`.

<a id="jwt_ttl_request_email_change"></a>

### `JWT_TTL_REQUEST_EMAIL_CHANGE`

The time until email change request tokens expire. The value should be a time expression like `5m`, `5 minutes`, `5d`, `5 days`, `1w`, or `1 week`. Defaults to `1 hour`.

<a id="rsa_private_key"></a>

### `RSA_PRIVATE_KEY`

The RSA private key in PEM format is used for signing Saleor's JWT tokens. This is unnecessary in the DEBUG mode as Saleor will generate a temporary private key. It is required in production environments.

<a id="rsa_private_password"></a>

### `RSA_PRIVATE_PASSWORD`

The password is required for loading `RSA_PRIVATE_KEY`. Default set to `None`.

<a id="media_url"></a>

### `MEDIA_URL`

Controls [Django's `MEDIA_URL`](https://docs.djangoproject.com/en/3.0/ref/settings/#media-url) setting. Defaults to `/media/`.

<a id="public_url"></a>

### `PUBLIC_URL`

Specifies the base URL at which Saleor is hosted, such as `https://api.example.com/`. This setting takes precedence over both [`ENABLE_SSL`](#enable_ssl) and `Shop.domain` (set using the GraphQL API) when generating URLs. Ensure to provide the complete URL, including the protocol: `http://` or `https://`.

<a id="playground_enabled"></a>

### `PLAYGROUND_ENABLED`

Controls whether to run [Playground](https://github.com/prisma-labs/graphql-playground) - the interactive GraphQL explorer - when accessing the `/graphql/` URL exposed by Saleor. Defaults to `True`.

<a id="secret_key"></a>

### `SECRET_KEY`

Controls [Django's secret key](https://docs.djangoproject.com/en/3.0/ref/settings/#s-secret-key) setting.

<a id="static_url"></a>

### `STATIC_URL`

Controls the production assets mount path. Defaults to `/static/`.

<a id="breaker_board_enabled"></a>

### `BREAKER_BOARD_ENABLED`

Enables the [circuit breaker](/developer/extending/webhooks/synchronous-events/circuit-breakers.md) feature for sync webhooks.

<a id="breaker_board_sync_events"></a>

### `BREAKER_BOARD_SYNC_EVENTS`

List of comma separated, lowercase sync webhook events, which should be monitored by the breaker board. For example: `"checkout_calculate_taxes, shipping_list_methods_for_checkout"`.

<a id="breaker_board_dry_run_sync_events"></a>

### `BREAKER_BOARD_DRY_RUN_SYNC_EVENTS`

Sets the circuit breaker to dry run mode, in which events will be monitored but no blockage of webhooks will occur when the failure threshold is exceeded. Breaker events will still be logged, which is useful for testing the breaker without affecting the webhooks behavior.

<a id="upload_additional_allowed_mime_types"></a>

### `UPLOAD_ADDITIONAL_ALLOWED_MIME_TYPES`

Can be used if you are uploading other file formats than the [file types supported by default](https://github.com/saleor/saleor/blob/6af65ae16636437fece574304871705387d22f0d/saleor/settings.py#L1155-L1191). It takes a JSON input with the following format:

```yaml
{
  # <mime-type>: [<file extension>, ...]
  "image/png": [".png"],
}
```

For example, if you want to allow zip files, then do:

```shell
export UPLOAD_ADDITIONAL_ALLOWED_MIME_TYPES='{"application/zip": [".zip"]}'
```

Learn more in the ["Restricted File Uploads" page](/security.md#restricted-file-uploads).

Important note about existing MIME types

If a MIME type is **[already defined in the source code](https://github.com/saleor/saleor/blob/6af65ae16636437fece574304871705387d22f0d/saleor/settings.py#L1155-L1191)**, you must provide the complete list of file extensions for that MIME type. The provided list will **replace** the existing one (it will not be merged automatically.)

For example, `image/jpeg` is defined internally as:

```python
{
    "image/jpeg": [".jpg", ".jpeg", ".jpe", ".jfif"]
}
```

If you want to add another extension for `image/jpeg`, you must include **all existing extensions**, plus the new one:

```shell
export UPLOAD_ADDITIONAL_ALLOWED_MIME_TYPES='{
  "image/jpeg": [".jpg", ".jpeg", ".jpe", ".jfif", ".newext"]
}'
```

Failing to include the full list will cause previously supported extensions to be rejected.

<a id="editorjs--html-cleaning"></a>

## EditorJS & HTML Cleaning

If you use custom HTML or custom URL schemes inside EditorJS (product descriptions, collections, categories, etc.), then, the following settings may need to be tweaked:

<a id="editor_js_allowed_attributes"></a>

### `EDITOR_JS_ALLOWED_ATTRIBUTES`

A list of HTML attributes to allow for given HTML elements only relevant if you use custom HTML attributes, like `<div is="something">`, it takes a JSON input like so:

```yaml
# {<html-element>: [<attribute-to-allow, ...]}
# Example: allows <a my-attr-to-allow="something">:
{ "a": ["my-attr-to-allow"] }
```

<a id="editor_js_allowed_attribute_values"></a>

### `EDITOR_JS_ALLOWED_ATTRIBUTE_VALUES`

The same as above except it takes a list of **values** allowed inside a given attribute within a given HTML element. This is useful if you want to be stricter or if the attribute you need to allow may contain dangerous values that we need to prevent malicious users from using.

info

-   If you use this setting, you don't need to allow the attribute in `EDITOR_JS_ALLOWED_ATTRIBUTES`, that's redundant and could (potentially) cause issues.
-   The allowed attribute values must **match exactly**, for example if you allow `my-value` but your HTML is `<a my-attr="foo my-value">` then it will not work (instead, you would need to allow `foo my-value`).

```yaml
# Example, if we want to allow the following:
#   - <a my-attr="my-value">
#   - <a my-attr="a value with spaces">
# Then:
{ "a": { "my-attr": ["my-value", "a value with spaces"] } }
```

<a id="editor_js_link_rel"></a>

### `EDITOR_JS_LINK_REL`

Controls which values to put in the `rel` attribute for links (`<a href=... rel="XXX">`).

Default value:

-   Saleor `< 3.23.0` - `ref` is by default blank (for backward compatibility).
-   Saleor `>= 3.23.0` - `ref` is set to `noopener noreferrer`.

We recommended setting the following:

```shell
export EDITOR_JS_ALLOWED_ATTRIBUTES='noopener noreferrer'
```

Possible values:

-   [noopener](https://html.spec.whatwg.org/multipage/links.html#link-type-noopener): This prevents a particular type of XSS attack, and should usually be turned on for untrusted HTML.
-   [noreferrer](https://html.spec.whatwg.org/multipage/links.html#link-type-noreferrer): This prevents the browser from sending the source URL to the website that is linked to.
-   [nofollow](https://html.spec.whatwg.org/multipage/links.html#link-type-nofollow): This prevents search engines from using this link for ranking, which disincentivizes spammers.

Learn more: [https://nh3.readthedocs.io/en/latest/#nh3.Cleaner](https://nh3.readthedocs.io/en/latest/#nh3.Cleaner)

<a id="unsafe_editor_js_allowed_url_schemes"></a>

### `UNSAFE_EDITOR_JS_ALLOWED_URL_SCHEMES`

Takes a list of allowed URL schemes. By default we allow only `http(s)://`, `tel:`, and `mailto:` - if you use other URL schemes (e.g., `intent://`), then you must add it to `UNSAFE_EDITOR_JS_ALLOWED_URL_SCHEMES`.

Example:

```shell
# Allows 'intent://' and 'ftp://'
# Note: http(s), tel, and mailto are still allowed, you do not need to pass them here.
export UNSAFE_EDITOR_JS_ALLOWED_URL_SCHEMES='intent,ftp'
```

danger

This has been removed in Saleor v3.23.0, see [Upgrading From 3.22 To 3.23](/upgrade-guides/core/3-22-to-3-23.md) for more information.

This environment variable is dangerous to use and is only here to help for backward compatibility. By setting this environment variable you may be exposing yourself to XSS attacks, if you really need to set it, consider using client-side cleaners like [DOMPurify](https://github.com/cure53/DOMPurify) or [isomorphic-dompurify](https://github.com/kkomelin/isomorphic-dompurify).

Consider opening a feature request instead ([https://github.com/saleor/saleor/issues](https://github.com/saleor/saleor/issues)) so we can add support out of the box for the protocols that you need.

<a id="editor_js_lists_max_depth"></a>

### `EDITOR_JS_LISTS_MAX_DEPTH`

Limits the list depth for nested list (new list format from EditorJS) - defaults to 10, meaning you can have indentation 10 levels in lists (typically a person only uses max 3 levels).

For example this list has 3 levels:

-   Level 1
    -   Level 2
        -   Level 3

You likely do not need to increase this value, but if you do need to, then the syntax is the following:

```shell
# Allowing 20 levels
export EDITOR_JS_LISTS_MAX_DEPTH=20
```

<a id="currency-exchange"></a>

## Currency exchange

Saleor can automatically convert amounts between currencies. To use this feature, you will need an [Open Exchange Rates account](https://openexchangerates.org/).

<a id="openexchangerates_api_key"></a>

### `OPENEXCHANGERATES_API_KEY`

Your store's Open Exchange Rates "App ID".

<a id="updating-domain-configuration"></a>

## Updating domain configuration

When deploying Saleor under a specific domain, such as `api.example.com`, it's essential to ensure that Saleor is properly configured to generate URLs. This can be achieved using the [`PUBLIC_URL`](#public_url) environment variable. Once configured, Saleor will effectively generate URLs tailored to its domain, ensuring smooth bidirectional communication.

<a id="deprecated-settings"></a>

## Deprecated settings

<a id="enable_ssl"></a>

### `ENABLE_SSL`

Used while generating URLs. Set to `True` if Saleor is deployed behind HTTPS. Defaults to `False`. Replaced by [`PUBLIC_URL`](#public_url).
