# Set variables

To set variables, determine which [type of variable](https://fixed.docs.upsun.com/development/variables.md#variable-types) to use.
Remember to take into account the order of precedence.
All of the variables can also be [overridden via script](#set-variables-via-script).

## Set variables in your app

Set variables [in code](https://fixed.docs.upsun.com/create-apps/image-properties/variables.md) using the `.platform.app.yaml` file.
These values are the same across all environments and present in the Git repository,
which makes them a poor fit for API keys and other such secrets.

They're better fits for uses such as configuration for consistent builds across every environment,
including setting [PHP configuration values](https://fixed.docs.upsun.com/development/variables.md#php-specific-variables).

Application variables are available at both build time and runtime.

## Create project variables

Add secrets for all environments in project variables
using [the Console](https://fixed.docs.upsun.com/administration/web/configure-project.md#variables) or the [CLI](https://fixed.docs.upsun.com/administration/cli.md).

For example, you may need to vary API credentials between production and other environments.
To do so, set the non-production credentials as a project variable
and then override these credentials for the production environment by setting a [variable specific to that environment](#create-environment-specific-variables).

To specify other options, use the [flags for variable options](#variable-options).
To add a project variable, follow these steps:

 - Select the project where you want to create a variable.
 - Click Settings **Settings**.
 - Under **Project settings**, click **Variables**.
 - Click **+ Create variable**.
 - Enter a name for the variable.
 - Enter the variable value.
 - Ensure you have selected the right [other options](#variable-options).
 - Click **Create variable**.

When naming variables, be sure to take [variable prefixes](https://fixed.docs.upsun.com/development/variables.md#variable-prefixes) into account.
In particular, to expose a variable as its own environment variable,
[use the prefix `env:`](https://fixed.docs.upsun.com/development/variables.md#top-level-environment-variables).

### Variable options

Variables have several Boolean options you can set in the Console or the CLI:

| Option    | CLI flag            | Default | Description                                                                                                                                            |
|-----------|---------------------|---------|--------------------------------------------------------------------------------------------------------------------------------------------------------|
| JSON      | `--json`            | `false` | Whether the variable is a JSON-serialized value (`true`) or a string (`false`).                                                                        |
| Sensitive | `--sensitive`       | `false` | If set to `true`, the variable's value is hidden in the Console and in CLI responses for added security. It's still readable within the app container. |
| Runtime   | `--visible-runtime` | `true`  | Whether the variable is available at runtime.                                                                                                          |
| Build     | `--visible-build`   | `true`  | Whether the variable is available at build time.                                                                                                       |

So if you want the `foo` variable to be visible at build time but hidden during runtime,
you can set it by running the following command:

```bash
platform variable:create --level project --name foo --value bar --visible-build true --visible-runtime false
```

You can also change the variable options after you create them (except for sensitive values, which can't be set to non-sensitive).
For example, to make the `foo` variable visible at runtime and hidden during the build, run the following command:

```bash
platform variable:update foo --visible-build false --visible-runtime true
```

Note that for changes to project variables to have effect,
you need to [redeploy](https://fixed.docs.upsun.com/development/troubleshoot.md#force-a-redeploy) your environments.

## Create environment-specific variables

Set variables for specific environments using [the Console](https://fixed.docs.upsun.com/administration/web/configure-environment.md#variables) or the CLI.
Variables can be inherited or overridden from parent environments and project variables.
See [more on overriding values](https://fixed.docs.upsun.com/development/variables.md#overrides).

To specify the environment for the variable, use the ``-e`` flag to specify its name.
To specify other options, use the [flags for variable options](#environment-variable-options).
To add a project variable, follow these steps:

 - Select the project where you want to create a variable.
 - Click Settings **Settings**.
 - Under **Environments**, click the environment where you want to create a variable.
 - Click **Variables**.
 - Click **+ Create variable**.
 - Enter a name for the variable.
 - Enter the variable value.
 - Ensure you have selected the right [other options](#environment-variable-options).
 - Click **Create variable**.

When naming variables, be sure to take [variable prefixes](https://fixed.docs.upsun.com/development/variables.md#variable-prefixes) into account.
In particular, to expose a variable as its own environment variable,
[use the prefix `env:`](https://fixed.docs.upsun.com/development/variables.md#top-level-environment-variables).

### Environment variable options

Environment variables share all of the [options available for project variables](#variable-options).
Environment variables have one additional option:

| Option      | CLI flag        | Default | Description                                              |
|-------------|-----------------|---------|----------------------------------------------------------|
| Inheritable | `--inheritable` | `true`  | Whether the variable is inherited by child environments. |

This option is useful for setting production-only values such as credentials.
For example, to set a PayPal secret value for only the `main` branch and have it not be readable elsewhere,
run the following command:

```bash
platform variable:create -e main --name paypal_id --inheritable false --sensitive true
```

Other environments don't inherit it and get either a project variable of the same name if it exists or no value at all.

Note that changing an environment variable causes that environment to be redeployed so the new value is available.
But child environments are *not* redeployed.
To make the new value accessible to those environments, [trigger a redeploy](https://fixed.docs.upsun.com/development/troubleshoot.md#force-a-redeploy).

### Example environment variable

Environment variables are a good place to store values that apply only on Upsun Fixed and not on your local development environment.
This includes API credentials for third-party services, mode settings, and which server (development vs. production) to use.

One example would be to define a Node.js application's build on a production branch (`NODE_ENV=production`),
but use development mode (`NODE_ENV=development`) for each of your preview environments.
Assuming you have a `main` environment for production and a `staging` environment with more child environments for development,
run the following commands:

```bash
platform variable:create -l environment -e main --prefix env: --name NODE_ENV --value production --visible-build true --inheritable false
platform variable:create -l environment -e staging --prefix env: --name NODE_ENV --value development --visible-build true --inheritable true
```

Now `NODE_ENV` is `production` on the default branch but `development` on `staging` and each of its child environments.
Note that build visible environment variables change the application's build configuration ID:
value updates trigger a rebuild of the application in the same way that a commit would.

## Set variables via script

You can also provide a `.environment` file as in [your app root](https://fixed.docs.upsun.com/create-apps/app-reference/single-runtime-image.md#root-directory).
This file runs as a script in dash when the container starts and on all SSH logins.
It can be used to set any environment variables directly, such as the PATH variable.

For example, the following `.environment` file allows any executable installed in the `vendor/bin` directory
(such as executables installed using Composer)
to be run regardless of the current directory:

```bash  {location=".environment"}
export PATH=/app/vendor/bin:$PATH
```

You can also dynamically define environment variables based on the current environment.
For example, you might want to get the [defined route](https://fixed.docs.upsun.com/define-routes.md) with the id `api` for the current environment.
To define it as the `URL` environment variable, you might add something like:

```bash  {location=".environment"}
URL=$(echo $PLATFORM_ROUTES | base64 --decode | jq -r 'to_entries[] | select (.value.id == "api") | .key')
```

Note that the file is sourced after all other environment variables above are defined and so they're available to the script.
This also means the `.environment` script has the last word on environment variable values and can override anything it wants to.

### Testing `.environment` scripts

You may find that a command that works during an SSH session provides a `bad substitution` error when placed in a `.environment` file.
Remember, `.environment` is sourced using dash, not bash.
When testing your `.environment` logic, be sure to first enter a `dash` session in your terminal or within the SSH session.

When testing, you might print to stdout (using an `echo` or `printf` command) to check what's happening.
The following example looks for a `deploy/environment.tracker.txt` file.
It displays a different message if it's found or not, which helps you track what variables are being set.

```bash  {location=".environment"}
if [ -f "deploy/environment.tracker.txt" ]; then
    echo "File found."
    export DEPLOY='Friday'
else
    echo "File not found."
    export DEPLOY='Never on a Friday'
fi
```

While sanity checks like this are useful during troubleshooting, you shouldn't include such commands in your final code.
Because the `.environment` file is run at the start of an SSH session, the message is printed at the start of the session.

Even when your SSH command executes successfully, you might later attempt to download data from one of your mounts,
such as by using the CLI command `platform mount:download`.
When you do, you see this error:

```bash
protocol version mismatch -- is your shell clean?
(see the rsync man page for an explanation)
rsync error: protocol incompatibility (code 2) at .../rsync/compat.c(61) [receiver=2.6.9]

[ProcessFailedException]
The command failed with the exit code: 2
```

This failure comes because `mount:download` and `rsync` don't expect output when the SSH connection is made.
To solve the issue, remove the printed output from your `.environment` file.

## Map variables

If your app needs different names for environment variable than those set by Upsun Fixed, which is common for database connections,
map the Upsun Fixed's variable names to those required by the application.
Do this in the app with the help of the [Config Reader library](https://fixed.docs.upsun.com/development/variables/use-variables.md#access-variables-in-your-app) or via a shell script.

For example, the following [`.environment` script](#set-variables-via-script) exports variables that are visible to the application.
It uses the `jq` library, which is included in all app containers for this purpose.

```bash  {location=".environment"}
export APP_DATABASE_HOST="$(echo $PLATFORM_RELATIONSHIPS | base64 --decode | jq -r '.database[0].host')"
export APP_DATABASE_USER="$(echo $PLATFORM_RELATIONSHIPS | base64 --decode | jq -r '.database[0].username')"
```

This sets environment variables with names your app needs and the values from `PLATFORM_RELATIONSHIPS`.

## When to use `.env` files {#use-env-files}

Upsun does not read `.env files`, as conventionally they are not committed to Git. You can use these for local
development, but they will not be sourced on any Upsun environment. Typically, you can add `.env` to your .gitignore
file so that its contents can vary for different developers.

Read more about [the use cases for `.env` files](https://upsun.com/blog/what-is-env-file/).

