# Environment config

It is common to have multiple environments. For this project, we will have:

* **Local** to run on our machine for development.
* **CI** for automated tests.
* **Staging** to check if everything is working in the cloud. This can also be used to show a feature to someone before pushing it live.
* **Production** where we host our app.

{% hint style="info" %}
Try to keep all environments as similar as possible to each other.
{% endhint %}

### Config folder

Let's create a folder that contains the configurations for each environment. We will also have a `shared.ts`file for things common to all environment and `index.ts` to return the correct object.

```
.
└── config
    ├── ci.ts
    ├── index.ts
    ├── local.ts
    ├── production.ts
    ├── shared.ts
    └── staging.ts
```

{% tabs %}
{% tab title="index.ts" %}

```typescript
import { SharedConfig } from "./shared";
import { local } from "./local";
import { ci } from "./ci";
import { staging } from "./staging";
import { production } from "./production";

export interface Config extends SharedConfig {
  env: "local" | "ci" | "staging" | "production";
}

export const config: Config = { local, ci, staging, production }[
  process.env.CONFIG_ENV || "local"
];
```

{% endtab %}

{% tab title="shared.ts" %}

```typescript
export interface SharedConfig {
  logLevel: string;
}

export const sharedConfig = {
  logLevel: process.env.LOG_LEVEL || "info" // we will come back to logs later
};
```

{% endtab %}

{% tab title="local.ts" %}

```typescript
import { sharedConfig } from "./shared";
import { Config } from "./index";

export const local: Config = {
  ...sharedConfig,
  env: "local"
};
```

{% endtab %}

{% tab title="ci.ts" %}

```typescript
import { sharedConfig } from "./shared";
import { Config } from "./index";

export const ci: Config = {
  ...sharedConfig,
  env: "ci"
};
```

{% endtab %}

{% tab title="staging.ts" %}

```typescript
import { sharedConfig } from "./shared";
import { Config } from "./index";

export const staging: Config = {
  ...sharedConfig,
  env: "staging"
};
```

{% endtab %}

{% tab title="production.ts" %}

```typescript
import { sharedConfig } from "./shared";
import { Config } from "./index";

export const production: Config = {
  ...sharedConfig,
  env: "production"
};
```

{% endtab %}
{% endtabs %}

For now, there isn't much difference between our files. It will grow as we start adding features.

> Note that we use `CONFIG_ENV` instead of `NODE_ENV`. This is because some libraries and node itself behave differently when you set `NODE_ENV=production`. We want our environment to be as close as possible to each other.

Let's try this out:

{% code title="index.ts" %}

```typescript
import { config } from './config';

console.log(config);
```

{% endcode %}

```
$ cd packages/api
```

```
$ CONFIG_ENV=staging LOG_LEVEL=error ts-node src/index.ts
{ logLevel: 'error', env: 'staging' }
```

```
$ CONFIG_ENV=ci LOG_LEVEL=debug ts-node src/index.ts
{ logLevel: 'debug', env: 'ci' }
```

{% hint style="danger" %}
Never commit secrets to git. Always use environment variable.
{% endhint %}

### Making it work on Windows

We want each member of the team to be able to work in the environment they are the most comfortable. Most developers in the industry are using MacOS but this doesn't mean we should ignore other operating system.

The [cross-env](https://github.com/kentcdodds/cross-env) library allows us to run the same command on Unix and Windows.

```
$ cd packages/api
```

```
$ yarn add cross-env
```

This should now work everywhere:

```
$ cross-env CONFIG_ENV=ci LOG_LEVEL=debug ts-node src/index.ts
```

### DotEnv file

As our app growths, we will have to set more and more environment variables.\
To keep this clean, we will store them in a `.env` file.

{% code title="packages/api/.env" %}

```
CONFIG_ENV=local
LOG_LEVEL=debug
```

{% endcode %}

```
$ cd packages/api
```

```
$ yarn add dotenv
```

{% code title="index.ts" %}

```typescript
require('dotenv').config();
import { config } from './config';

console.log(config);
```

{% endcode %}

```
$ ts-node src/index.ts
{ logLevel: 'debug', env: 'local' }
```

{% hint style="warning" %}
Don't forget to add `.env` to `.gitignore` as it will contain secrets.
{% endhint %}

{% hint style="info" %}
[`environment`](https://github.com/florianherrengt/book-code/tree/environment) branch available on GitHub.
{% endhint %}


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://tutorial.specian.co.uk/backend/environment-config.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
