@alzulejos/laranja-docs 0.2.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,52 @@
1
+ ---
2
+ title: How it works
3
+ description: How laranja turns your code into a running app on AWS.
4
+ order: 4
5
+ ---
6
+
7
+ # How it works
8
+
9
+ You write your app; laranja deploys it to your own AWS account. Two things are
10
+ worth knowing about how it does that.
11
+
12
+ ## It reads your code — it never runs it
13
+
14
+ laranja discovers your infrastructure by **reading** your source: your HTTP app
15
+ and its routes, your `@Cron` / `cron()` jobs and their schedules, your
16
+ `@Queue` / `queue()` consumers, and the env vars you wrap with `env()`. It does
17
+ this without executing your code, so planning a deploy is always safe — nothing
18
+ of yours runs just to figure out what to deploy.
19
+
20
+ That's also why a few things must be written so laranja can see them: schedules
21
+ use literal builders like `rate(5, "minutes")`, and `env("…")` takes a string
22
+ literal.
23
+
24
+ ## It deploys into your AWS account
25
+
26
+ laranja turns what it found into AWS resources — a Lambda for your app, an
27
+ EventBridge rule per cron, an SQS queue per consumer — and deploys them with
28
+ **your** credentials into **your** account. See
29
+ [what gets deployed](../reference/what-gets-deployed.md) for the full mapping.
30
+
31
+ - The AWS CDK toolkit is embedded, so there's nothing extra to install.
32
+ - The first deploy to a new account/region runs a one-time **bootstrap**.
33
+ - [`plan`](../reference/commands.md#plan) previews what a deploy would change
34
+ (created/changed/unchanged); [`destroy`](../reference/commands.md#destroy)
35
+ tears the stack down.
36
+ - Outputs (your HTTPS URL, queue URLs) are printed when the deploy finishes.
37
+
38
+ ## The template is built on the server — your code stays local
39
+
40
+ [`plan`](../reference/commands.md#plan) and [`deploy`](../reference/commands.md#deploy)
41
+ synthesize the deployment template on the **laranja server**. laranja scans and
42
+ bundles your code locally, then sends only a **description** of your
43
+ infrastructure (the internal model plus the asset hashes of your bundles) — your
44
+ source code and bundles never leave your machine. The returned template is then
45
+ applied to AWS with your **own** credentials. This is why these commands need a
46
+ `LARANJA_API_KEY` and a `projectId` (run [`laranja init`](../reference/commands.md#init)
47
+ once to set both up).
48
+
49
+ ## Related
50
+
51
+ - [What gets deployed](../reference/what-gets-deployed.md)
52
+ - [Stages & environments](../guides/stages-and-environments.md)
@@ -0,0 +1,58 @@
1
+ ---
2
+ title: Installation
3
+ description: Prerequisites and how to add laranja to a project.
4
+ order: 2
5
+ ---
6
+
7
+ # Installation
8
+
9
+ ## Prerequisites
10
+
11
+ - **Node.js 20 or newer.** Deployed Lambdas run on the Node.js 20 runtime, and
12
+ the CLI targets the same.
13
+ - **A laranja account + API key.** laranja synthesizes your deployment template on
14
+ its server, so `plan`, `deploy`, and `eject` need an API key (created in the
15
+ dashboard) and a project to link to. You connect both by running
16
+ [`laranja init`](./quickstart.md#3-sign-in-and-configure) — see the Quickstart.
17
+ - **An AWS account** plus credentials on the standard AWS chain — any of:
18
+ - `aws configure` (a shared credentials file),
19
+ - AWS SSO (`aws sso login`),
20
+ - environment variables (`AWS_ACCESS_KEY_ID` / `AWS_SECRET_ACCESS_KEY` / `AWS_SESSION_TOKEN`),
21
+ - a named profile (set [`profile`](../reference/config-file.md) in config).
22
+ - **A region**, from `region` in your config or the `AWS_REGION` /
23
+ `AWS_DEFAULT_REGION` environment variable.
24
+
25
+ You do **not** need to install the AWS CDK or the AWS CLI separately — the CDK
26
+ toolkit is embedded in laranja.
27
+
28
+ ## Install
29
+
30
+ Add the CLI as a dev dependency:
31
+
32
+ ```bash
33
+ npm install -D @alzulejos/laranja
34
+ ```
35
+
36
+ If you use decorators or function markers for jobs and queues, also install:
37
+
38
+ ```bash
39
+ npm install @alzulejos/laranja-decorators
40
+ ```
41
+
42
+ > `@alzulejos/laranja-decorators` is a regular dependency (not dev-only) because your
43
+ > application imports `@Cron`, `@Queue`, `rate`, etc. at runtime.
44
+
45
+ ## First-time AWS setup (bootstrap)
46
+
47
+ The first time you deploy to a given account + region, laranja runs a one-time
48
+ **bootstrap** that creates a small set of shared resources in _your_ account (an
49
+ S3 asset bucket and a few IAM roles). `laranja deploy` detects this and prompts
50
+ you before doing it — see [deploy](../reference/commands.md#deploy).
51
+
52
+ ## Verify
53
+
54
+ ```bash
55
+ npx laranja --help
56
+ ```
57
+
58
+ You're ready for the **[Quickstart](./quickstart.md)**.
@@ -0,0 +1,97 @@
1
+ ---
2
+ title: Introduction
3
+ description: What laranja is, the problem it solves, and the principles behind it.
4
+ order: 1
5
+ ---
6
+
7
+ # Introduction
8
+
9
+ laranja is a **code-first deploy tool** for Node.js apps. You write your
10
+ application — an Express app, some scheduled jobs, some queue consumers — and
11
+ laranja deploys it to **your own AWS account**. There is no infrastructure
12
+ project to maintain, no YAML to write, and no cloud console to click through.
13
+
14
+ > laranja supports **Express** and **NestJS** — and because your app is reduced to
15
+ > a framework-neutral description internally, more frameworks can follow without
16
+ > changing how you write your code.
17
+
18
+ ## The problem
19
+
20
+ Shipping a small Node service to AWS usually means choosing between:
21
+
22
+ - **A platform** (managed hosting) — fast, but you don't own the infrastructure
23
+ and you pay a markup to run in someone else's account.
24
+ - **Infrastructure-as-code** (CDK / Terraform / CloudFormation) — you own
25
+ everything, but now you maintain a second codebase that drifts from the app it
26
+ describes.
27
+
28
+ laranja takes a third path: **your application code _is_ the source of truth for
29
+ the infrastructure.** A route is an HTTP endpoint. A `@Cron` method is a
30
+ scheduled function. A `@Queue` method is an SQS consumer. laranja reads those
31
+ facts out of your code and provisions exactly what they imply.
32
+
33
+ ## How it feels
34
+
35
+ ```ts
36
+ // src/app.ts — mark your HTTP app, code-first
37
+ import express from "express";
38
+ import { http } from "@alzulejos/laranja-decorators";
39
+
40
+ const app = express();
41
+ app.get("/health", (_req, res) => res.json({ ok: true }));
42
+
43
+ export default http(app);
44
+ ```
45
+
46
+ Jobs and queues come in two styles — plain **functions** or **classes** with
47
+ decorators. Use whichever you prefer:
48
+
49
+ ```ts tab="Function"
50
+ // src/jobs.ts
51
+ import { cron, rate } from "@alzulejos/laranja-decorators";
52
+
53
+ export async function refreshCache() { /* ... */ }
54
+ cron(rate(5, "minutes"), refreshCache);
55
+ ```
56
+
57
+ ```ts tab="Class"
58
+ // src/jobs.ts
59
+ import { Cron, rate } from "@alzulejos/laranja-decorators";
60
+
61
+ export class Jobs {
62
+ @Cron(rate(5, "minutes"))
63
+ async refreshCache() { /* ... */ }
64
+ }
65
+ ```
66
+
67
+ ```bash
68
+ npx laranja deploy
69
+ ```
70
+
71
+ You get a live HTTPS URL, an EventBridge schedule, and an SQS queue with a
72
+ consumer — all in your own account, named deterministically.
73
+
74
+ ## Principles
75
+
76
+ - **Code is the source of truth.** Infrastructure is _derived_ from the app, not
77
+ declared alongside it. There's nothing to keep in sync.
78
+ - **Your account, your resources.** laranja deploys with your AWS credentials
79
+ into your account. You own every resource and can inspect it in the console.
80
+ - **Deterministic, no magic names.** Resources are named `‹app›-‹fn›-‹stage›` —
81
+ predictable and greppable, with no random suffixes.
82
+ - **Provider-neutral by design.** AWS is the first target, but laranja is built
83
+ so other clouds can follow without changing your app code.
84
+ - **An escape hatch when you need it.** Outgrow the abstraction? `laranja eject`
85
+ hands you a real, owned CDK project (see [eject](../reference/commands.md#eject)).
86
+
87
+ ## What's in scope (v1)
88
+
89
+ | Capability | How you declare it |
90
+ |---|---|
91
+ | HTTP API | An Express or NestJS app, marked with the [`http()`](../reference/decorators-and-markers.md#http) marker. |
92
+ | Scheduled jobs | [`@Cron`](../reference/decorators-and-markers.md#cron) (class) or [`cron()`](../reference/decorators-and-markers.md#cron-marker) (function) |
93
+ | Queue consumers | [`@Queue`](../reference/decorators-and-markers.md#queue) (class) or [`queue()`](../reference/decorators-and-markers.md#queue-marker) (function) |
94
+ | Per-environment deploys | [Stages](../guides/stages-and-environments.md) (`--stage`) |
95
+ | Env vars | [`env`](../guides/environment-variables.md) in config |
96
+
97
+ Next: **[Installation](./installation.md)**.
@@ -0,0 +1,164 @@
1
+ ---
2
+ title: Quickstart
3
+ description: From an empty folder to a live HTTPS endpoint in a few minutes.
4
+ order: 3
5
+ ---
6
+
7
+ # Quickstart
8
+
9
+ This walks you from zero to a deployed app with an HTTP endpoint, a scheduled
10
+ job, and a queue consumer.
11
+
12
+ ## 1. Create a project
13
+
14
+ ```bash
15
+ mkdir my-api && cd my-api
16
+ npm init -y
17
+ npm install express
18
+ npm install -D @alzulejos/laranja typescript
19
+ npm install @alzulejos/laranja-decorators
20
+ ```
21
+
22
+ > laranja supports **Express** and **NestJS**. For Nest, see the
23
+ > [HTTP apps guide](../guides/http-apps.md#nestjs).
24
+
25
+ ## 2. Write your app
26
+
27
+ Mark your app with [`http()`](../reference/decorators-and-markers.md#http) and
28
+ export it. laranja finds it by reading your code — so there's nothing to wire up
29
+ in config:
30
+
31
+ ```ts
32
+ // src/app.ts
33
+ import express from "express";
34
+ import { http } from "@alzulejos/laranja-decorators";
35
+
36
+ const app = express();
37
+ app.get("/", (_req, res) => res.json({ ok: true, stage: process.env.STAGE }));
38
+ app.get("/users/:id", (req, res) => res.json({ id: req.params.id }));
39
+
40
+ export default http(app);
41
+ ```
42
+
43
+ Add a scheduled job and a queue consumer (optional). There are two styles — pick
44
+ whichever fits your codebase.
45
+
46
+ ```ts tab="Function"
47
+ // src/jobs.ts
48
+ import { cron, queue, rate } from "@alzulejos/laranja-decorators";
49
+
50
+ export async function refreshCache() {
51
+ console.log("refreshing cache…");
52
+ }
53
+ cron(rate(5, "minutes"), refreshCache);
54
+
55
+ export async function sendEmail(body: unknown) {
56
+ console.log("sending", body);
57
+ }
58
+ queue({ name: "emails", batchSize: 10 }, sendEmail);
59
+ ```
60
+
61
+ ```ts tab="Class"
62
+ // src/jobs.ts
63
+ import { Cron, Queue, rate } from "@alzulejos/laranja-decorators";
64
+
65
+ export class Jobs {
66
+ @Cron(rate(5, "minutes"))
67
+ async refreshCache() {}
68
+
69
+ @Queue({ name: "emails", batchSize: 10 })
70
+ async sendEmail(body: unknown) {}
71
+ }
72
+ ```
73
+
74
+ ## 3. Sign in and configure
75
+
76
+ Run the scaffolder. It prompts for your **laranja API key** (from the dashboard),
77
+ validates it, stores it in `~/.laranja/auth.json`, and lets you pick or create a
78
+ **dashboard project** — filling in `name` and `projectId` for you:
79
+
80
+ ```bash
81
+ npx laranja init
82
+ ```
83
+
84
+ The generated `laranja.config.ts` looks like this (edit `region`, `env`, and
85
+ `compute` to taste):
86
+
87
+ ```ts
88
+ // laranja.config.ts
89
+ import type { LaranjaConfig } from "@alzulejos/laranja-decorators";
90
+
91
+ const config: LaranjaConfig = {
92
+ name: "my-api",
93
+ // From your laranja dashboard — identifies this project on the server.
94
+ projectId: "proj_…",
95
+ region: "us-east-1",
96
+ env: { LOG_LEVEL: "info" },
97
+ // Default compute for every function (the HTTP proxy + each cron/queue).
98
+ compute: { memory: 256, timeout: 30 },
99
+ };
100
+
101
+ export default config;
102
+ ```
103
+
104
+ Because the app is marked with `http()` in code, the config stays minimal — the
105
+ HTTP app is declared there, not in config. See the
106
+ **[config reference](../reference/config-file.md)**.
107
+
108
+ ## 4. Preview the plan
109
+
110
+ `plan` shows what a deploy would do: it synthesizes your template on the server,
111
+ diffs it against what's deployed in your AWS account, and tags each resource
112
+ **created / changed / unchanged**. It's **read-only** — nothing is applied, and it
113
+ never counts against your deploy limit.
114
+
115
+ ```bash
116
+ npx laranja plan
117
+ ```
118
+
119
+ ```
120
+ Plan for "my-api-dev"
121
+
122
+ + http HTTP 2 routes → proxy Lambda + Function URL
123
+ + daily Cron Lambda + EventBridge rule
124
+ + emails Queue SQS + consumer Lambda
125
+
126
+ 8 AWS resources +8 created =0 unchanged
127
+ ```
128
+
129
+ On this first run nothing is deployed yet, so everything shows as `+` created.
130
+
131
+ ## 5. Deploy
132
+
133
+ ```bash
134
+ npx laranja deploy
135
+ ```
136
+
137
+ The first deploy to a new account/region prompts you to **bootstrap** (a
138
+ one-time setup in your account). When it finishes you'll see your live URL:
139
+
140
+ ```
141
+ 🌐 http https://abc123.lambda-url.us-east-1.on.aws/
142
+ ```
143
+
144
+ Hit it:
145
+
146
+ ```bash
147
+ curl https://abc123.lambda-url.us-east-1.on.aws/
148
+ # {"ok":true,"stage":"dev"}
149
+ ```
150
+
151
+ ## 6. Iterate
152
+
153
+ ```bash
154
+ npx laranja logs # tail CloudWatch logs (pick a function)
155
+ npx laranja plan # see what a deploy would change
156
+ npx laranja deploy # ship again
157
+ npx laranja destroy # tear it all down
158
+ ```
159
+
160
+ ## Next steps
161
+
162
+ - Ship to multiple environments: **[Stages & environments](../guides/stages-and-environments.md)**.
163
+ - Understand what was created: **[What gets deployed](../reference/what-gets-deployed.md)**.
164
+ - Go deeper on jobs and queues: **[Cron jobs](../guides/cron-jobs.md)**, **[Queues](../guides/queues.md)**.
@@ -0,0 +1,129 @@
1
+ ---
2
+ title: Cron jobs
3
+ description: Run functions on a schedule with @Cron or cron().
4
+ order: 2
5
+ ---
6
+
7
+ # Cron jobs
8
+
9
+ A cron job is a function that runs on a schedule. Each one becomes
10
+ [its own Lambda plus an EventBridge rule](../reference/what-gets-deployed.md#cron--lambda--eventbridge-rule).
11
+
12
+ ## Class style — `@Cron`
13
+
14
+ Decorate a method with [`@Cron`](../reference/decorators-and-markers.md#cron) and
15
+ give it a [schedule](./schedules.md):
16
+
17
+ ```ts
18
+ import { Cron, rate, every } from "@alzulejos/laranja-decorators";
19
+
20
+ export class Jobs {
21
+ @Cron(rate(5, "minutes"))
22
+ async refreshCache() {
23
+ // …
24
+ }
25
+
26
+ @Cron(every("day"))
27
+ async nightlyCleanup() {
28
+ // …
29
+ }
30
+
31
+ @Cron({ schedule: "cron(0 12 * * ? *)", id: "daily-report" })
32
+ async sendReport() {
33
+ // …
34
+ }
35
+ }
36
+ ```
37
+
38
+ The handler's logical id defaults to `‹Class›-‹method›`; pass `id` to set a
39
+ stable, explicit name (which also drives the Lambda's name).
40
+
41
+ ## Function style — `cron()`
42
+
43
+ If you don't use classes, register a standalone exported function with
44
+ [`cron()`](../reference/decorators-and-markers.md#cron-marker):
45
+
46
+ ```ts
47
+ import { cron, rate } from "@alzulejos/laranja-decorators";
48
+
49
+ export async function refreshCache() {
50
+ // …
51
+ }
52
+
53
+ cron(rate(5, "minutes"), refreshCache);
54
+ ```
55
+
56
+ The function's name becomes the resource id unless you pass an explicit `id`:
57
+
58
+ ```ts
59
+ cron({ schedule: every("hour"), id: "hourly-sync" }, refreshCache);
60
+ ```
61
+
62
+ ## NestJS
63
+
64
+ In a Nest app, `@Cron` goes on a normal provider — with injected dependencies —
65
+ and you can keep the schedule syntax you already use (a
66
+ [node-cron string or `CronExpression`](./schedules.md#node-cron-expressions-nestjsschedule-compatibility)).
67
+ Swapping the import from `@nestjs/schedule` is usually the only change:
68
+
69
+ ```ts
70
+ // tasks.service.ts
71
+ import { Injectable } from "@nestjs/common";
72
+ import { Cron, CronExpression } from "@alzulejos/laranja-decorators"; // ← was @nestjs/schedule
73
+
74
+ @Injectable()
75
+ export class TasksService {
76
+ constructor(private readonly reports: ReportsService) {} // real DI
77
+
78
+ @Cron(CronExpression.EVERY_30_MINUTES)
79
+ async sweep() {
80
+ await this.reports.rebuild(); // `this.reports` is injected
81
+ }
82
+ }
83
+ ```
84
+
85
+ Because the method runs on a real provider, laranja resolves it through your
86
+ app's dependency-injection container instead of `new`-ing the class. Point it at
87
+ your module **once** with the [`workers()`](../reference/decorators-and-markers.md#workers)
88
+ marker:
89
+
90
+ ```ts
91
+ // src/main.ts (or a dedicated file)
92
+ import { workers } from "@alzulejos/laranja-decorators";
93
+ import { AppModule } from "./app.module";
94
+
95
+ export default workers(AppModule); // build a DI context from this module
96
+ ```
97
+
98
+ Pass `AppModule` for the whole graph, or a leaner module you compose if you want
99
+ a smaller cold start. Like the Nest [HTTP path](./http-apps.md#nestjs), laranja
100
+ packages your **compiled** `dist/` output — run `nest build` before deploying so
101
+ the DI metadata exists.
102
+
103
+ ## Schedules
104
+
105
+ Schedules are written with the portable `rate()` / `every()` builders, or as a
106
+ raw expression string. See the **[Schedules reference](./schedules.md)** for the
107
+ full set of options.
108
+
109
+ ```ts
110
+ @Cron(rate(30, "minutes")) // every 30 minutes
111
+ @Cron(every("hour")) // every hour (shorthand for rate(1, "hour"))
112
+ @Cron({ schedule: "cron(0 9 * * ? *)" }) // raw AWS cron: 09:00 UTC daily
113
+ ```
114
+
115
+ ## Runtime behavior
116
+
117
+ - Each cron runs in its **own Lambda**, isolated from your HTTP app and other
118
+ jobs.
119
+ - Memory and timeout come from [`compute`](../reference/config-file.md#compute)
120
+ (default `{ memory: 256, timeout: 30 }`) and can be overridden per cron id in
121
+ [`resources`](../reference/config-file.md#resources).
122
+ - All [config `env`](./environment-variables.md) and `STAGE` are
123
+ available via `process.env`.
124
+
125
+ ## Related
126
+
127
+ - [Schedules](./schedules.md)
128
+ - [`@Cron` / `cron()` reference](../reference/decorators-and-markers.md#cron)
129
+ - [Queues](./queues.md)
@@ -0,0 +1,108 @@
1
+ ---
2
+ title: Environment variables
3
+ description: Declare env vars in config or in code, and supply their values per stage.
4
+ order: 5
5
+ ---
6
+
7
+ # Environment variables
8
+
9
+ Every Lambda laranja deploys receives a set of environment variables, available
10
+ through `process.env` as usual. There are two ways to declare them.
11
+
12
+ ## Static values in config
13
+
14
+ Put plain, commit-safe values in the `env` map in your config. They're injected
15
+ into **every** function (HTTP proxy, cron, and queue consumers):
16
+
17
+ ```ts
18
+ // laranja.config.ts
19
+ const config: LaranjaConfig = {
20
+ name: "my-api",
21
+ env: {
22
+ LOG_LEVEL: "info",
23
+ API_BASE_URL: "https://api.example.com",
24
+ },
25
+ };
26
+ ```
27
+
28
+ ```ts
29
+ // anywhere in your app
30
+ const level = process.env.LOG_LEVEL; // "info"
31
+ ```
32
+
33
+ Use this for non-sensitive configuration that's the same everywhere: log levels,
34
+ public URLs, feature flags.
35
+
36
+ ## Values from your environment — `env()`
37
+
38
+ When a value should come from your shell or CI instead of your repo, wrap the
39
+ variable name with the `env()` helper where you read it:
40
+
41
+ ```ts
42
+ import { env } from "@alzulejos/laranja-decorators";
43
+
44
+ const dbUrl = env("DATABASE_URL"); // same as process.env.DATABASE_URL at runtime
45
+ ```
46
+
47
+ laranja finds every `env("…")` in your code and makes sure that variable is set
48
+ on **every** deployed function — no more filling them in by hand in the AWS
49
+ console. At deploy time it reads each value from your own environment and sends
50
+ it straight to the function; the value is never written into your repo.
51
+
52
+ The name must be a **string literal** — `env("DATABASE_URL")`, not
53
+ `env(someVariable)` — so laranja can discover it just by reading your code.
54
+
55
+ ### Supplying the values
56
+
57
+ Set the variables in the shell or CI job you deploy from:
58
+
59
+ ```bash
60
+ DATABASE_URL=postgres://… laranja deploy --stage prod
61
+ ```
62
+
63
+ - **Missing a value?** By default laranja deploys anyway and warns you which ones
64
+ were empty — a typo never blocks a deploy. Pass `--strict` to fail the deploy
65
+ instead.
66
+ - **Re-deploying without re-supplying a value?** The previously deployed value is
67
+ kept, so you don't have to pass every variable on every deploy.
68
+
69
+ ## The `STAGE` variable
70
+
71
+ laranja always injects `STAGE`, set to the active [stage](./stages-and-environments.md)
72
+ (`"dev"` by default, or whatever `--stage` resolved to). You don't declare it:
73
+
74
+ ```ts
75
+ app.get("/", (_req, res) => res.json({ stage: process.env.STAGE }));
76
+ ```
77
+
78
+ If you also define `STAGE` in `env`, your value wins.
79
+
80
+ ## Per-stage values
81
+
82
+ Because [`--stage`](./stages-and-environments.md) selects the
83
+ environment at deploy time, the common pattern is one pipeline per stage, each
84
+ supplying its own values:
85
+
86
+ - **Shared, non-sensitive defaults** → the `env` map in config.
87
+ - **Per-environment values** → declare them with `env()` and provide them from
88
+ each pipeline's environment.
89
+
90
+ ```bash
91
+ # dev pipeline
92
+ LOG_LEVEL=debug laranja deploy --stage dev
93
+ # prod pipeline
94
+ LOG_LEVEL=warn laranja deploy --stage prod
95
+ ```
96
+
97
+ ## Secrets
98
+
99
+ `env()` keeps values out of your repo, but they still land in the Lambda's plain
100
+ environment — readable by anyone with access to the function's configuration. For
101
+ true secrets (API keys, DB passwords), that's not enough. First-class secrets
102
+ support is on the roadmap; until then, read them at runtime from a secret store
103
+ (e.g. AWS SSM Parameter Store / Secrets Manager) inside your handler.
104
+
105
+ ## Related
106
+
107
+ - [Config file](../reference/config-file.md)
108
+ - [Stages & environments](./stages-and-environments.md)