---
title: "What Is a .env File? Environment Variables on a Server"
description: "What a .env file is, why bot tokens and API keys belong in environment variables, and how to set them and read them in Python, Node.js, Go or Java."
url: https://fps.ms/docs/containers/environment-variables
---
# Environment variables and .env files

A `.env` file is a plain text file that holds an app's settings and secrets, one `NAME=value` per line, outside the code. The app reads each line as an environment variable: a named value that the operating system hands to a program when it starts. On FPS.ms you do not need the file. You add the variables on your server's **Environment** tab, and the server gives them to your app every time it starts.

## What is an environment variable?

An environment variable is a name with a value, like `BOT_TOKEN=MTE4...`. Your code asks for the value by its name while it runs. Use them for:

- **Secrets:** bot tokens, API keys and database passwords. They stay out of your code, so they never end up on GitHub or in a screenshot.
- **Settings:** a log level, a channel ID or a feature switch. You change them without touching your code.
- **One codebase, many places:** your laptop and your server can run the same code with different values.

## What a .env file looks like

```env title=".env"
# Settings for cobalt-bot
BOT_TOKEN=MTE4NzQ2Mjk1.example.not-a-real-token
GUILD_ID=1187462950000000000
LOG_LEVEL=info
GREETING="Hello from Cobalt Works"
```

The format rules:

- One `NAME=value` per line, with no spaces around the `=`.
- Names use capital letters, numbers and underscores, like `API_KEY`.
- A line that starts with `#` is a comment.
- Put quotes around a value that contains spaces.

!!! danger "Never push .env to GitHub" "Add `.env` to your `.gitignore` file before your first commit. Bots scan public repositories for tokens and use a leaked Discord token within minutes. If it happened anyway, reset the token right away."

### What is .env.example?

`.env.example` is a copy of `.env` with the names but without the secret values. You commit it to your repository, so anyone who runs your app (and FPS.ms, see below) can see which variables it needs:

```env title=".env.example"
BOT_TOKEN=
GUILD_ID=
LOG_LEVEL=info
```

## Add environment variables on FPS.ms

1. Go to [panel.fps.ms](https://panel.fps.ms) and click **Manage** on your server.
2. Click **Environment**. If you do not see it in the top bar, click **More** first.

![The More menu open on a server page, with Environment highlighted](https://assets.docs.fps.ms/containers/environment-variables/01-open-environment-from-more-97172914.webp)

3. Click **Add variable**.

![The Environment variables card with no variables yet and the Add variable button highlighted](https://assets.docs.fps.ms/containers/environment-variables/02-click-add-variable-52f4d306.webp)

4. Type the **Name**, for example `BOT_TOKEN`, and paste the **Value**. Click **Add**.

![The Add variable dialog with BOT_TOKEN as the name and a token as the value](https://assets.docs.fps.ms/containers/environment-variables/03-fill-in-name-and-value-d12e3a54.webp)

5. The variable appears in the list. Its value shows as `***`: once saved, a value is never shown again, not even to you.

![The Environment variables list with BOT_TOKEN and a hidden value, and a message saying to restart the server](https://assets.docs.fps.ms/containers/environment-variables/04-variable-saved-value-hidden-ebbb6eda.webp)

6. Click **Console** and restart your server. Changes apply after a restart.

To change a value, click the pencil icon and type the new value. To remove a variable, click the bin icon. Restart after both.

## Fill them in from .env.example

When your server has no variables yet and your app has a `.env.example` file in its main folder, the **Environment** tab lists the names from that file for you.

![The Environment tab showing the names BOT_TOKEN, GUILD_ID and LOG_LEVEL from .env.example, each with an empty field, and a Save 0 variables button](https://assets.docs.fps.ms/containers/environment-variables/05-fill-in-from-env-example-3d7a6ae9.webp)

1. Type a value next to each name you need. A value from `.env.example`, like `info`, shows in grey as a hint. Type it if you want to keep it.
2. Empty fields are skipped.
3. Click the **Save** button, which counts the variables you filled in, and restart your server.

This also works for an app you [deploy from GitHub](https://fps.ms/docs/containers/deploy-from-github.md): commit `.env.example`, and the names show up after the first deploy.

## Read a variable in your code

You read a variable the same way whether it comes from the **Environment** tab or from your computer.

### Python

```python title="app.py"
import os

# Stops with a KeyError when BOT_TOKEN is missing.
token = os.environ["BOT_TOKEN"]

# Uses "info" when LOG_LEVEL is missing.
log_level = os.getenv("LOG_LEVEL", "info")
```

You do not need `python-dotenv` for variables from the **Environment** tab. If you also use a `.env` file on your computer, `load_dotenv()` never overwrites a variable that is already set, so on FPS.ms the value from the **Environment** tab wins.

### Node.js and Bun

```js title="index.js"
const token = process.env.BOT_TOKEN;
const logLevel = process.env.LOG_LEVEL ?? 'info';

if (!token) throw new Error('BOT_TOKEN is not set');
```

Node.js does not need the `dotenv` package for these either. Like `load_dotenv()`, `dotenv` does not overwrite variables that are already set.

### Other runtimes

| Runtime | Read `BOT_TOKEN` |
|-|-|
| Go | `os.Getenv("BOT_TOKEN")` |
| Java and Kotlin | `System.getenv("BOT_TOKEN")` |
| Rust | `std::env::var("BOT_TOKEN")` |
| .NET (C#) | `Environment.GetEnvironmentVariable("BOT_TOKEN")` |
| Dart | `Platform.environment['BOT_TOKEN']` (from `dart:io`) |
| Lua | `os.getenv("BOT_TOKEN")` |

## Rules and limits

| | Free plan | Paid plan |
|-|-|-|
| Variables per server | 8 | 100 |
| Size of one value | 32 KB | 32 KB |
| All names and values together | 64 KB | 64 KB |

- **Names** use capital letters, numbers and underscores, and cannot start with a number. Names are case-sensitive: `BOT_TOKEN` and `Bot_Token` are different.
- **Reserved names** are set by FPS.ms and cannot be added: `PATH`, `HOME`, `USER`, `TZ`, `SERVER_PORT`, `SERVER_MEMORY`, `SERVER_IP`, `NODE_OPTIONS`, `NODE_PATH`, `PYTHONPATH`, `JAVA_TOOL_OPTIONS`, every name that starts with `LD_` or `P_SERVER_`, and the names GitHub deploys use (`COMMIT_SHA`, `BRANCH`, `RELEASE_DIR` and a few more).
- **Startup settings** like `REQUIREMENTS_FILE` on Python are changed on the **Startup** tab, not here.

## Environment tab or .env file?

Both work. The **Environment** tab is the safer place for secrets:

| | Environment tab | `.env` file in Files |
|-|-|-|
| Value visible after saving | No, never | Yes, to everyone with file access |
| Can end up on GitHub | No | Yes, if you commit it by mistake |
| Extra package in your code | No | `python-dotenv` or `dotenv` |
| Available during GitHub deploy builds | Yes | Only if the build reads the file |
| Limit on a free server | 8 variables | None |

When the same name is in both, the value from the **Environment** tab wins.

## Common problems

- **`KeyError: 'BOT_TOKEN'` or `undefined`:** check the name for typos and capitals, then restart. Variables only reach your app after a restart.
- **"This name is reserved by the platform and cannot be set here":** pick another name, for example `APP_TZ` instead of `TZ`.
- **"This name is already a startup variable":** change it on the **Startup** tab instead.
- **"Free servers can have up to 8 environment variables":** put the less secret settings in a `.env` file, or upgrade the server.
- **No Environment tab, or "This server can't use environment variables":** your server runs on an older node. Use a `.env` file for now.

## Next steps

- [Deploy from GitHub](https://fps.ms/docs/containers/deploy-from-github.md)
- [Store a Discord bot token](https://fps.ms/docs/discord-bots/using-environment-variables.md) or [a Telegram bot token](https://fps.ms/docs/telegram-bots/using-environment-variables.md)
- [Fix an app that will not start](https://fps.ms/docs/containers/troubleshooting.md)

---

[FPS.ms](https://fps.ms/index.html.md) · [All pages](https://fps.ms/llms.txt) · [Documentation](https://fps.ms/docs/llms.txt)
