Skip to content

Commit e4e2b38

Browse files
committed
z0 - fix description of zerops.yaml extends feature
1 parent 3aa6f77 commit e4e2b38

4 files changed

Lines changed: 258 additions & 33 deletions

File tree

‎apps/docs/content/guides/zerops-yaml-advanced.mdx‎

Lines changed: 17 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -113,21 +113,30 @@ zerops:
113113
run: { envVariables: { NODE_ENV: production } }
114114
```
115115

116-
Supports single parent (`extends: base`) or multiple parents (`extends: [base, logging]`) -- later parents override earlier ones:
116+
The child is a deep copy of the resolved parent with its own keys applied on top. The merge is **recursive, key by key**:
117+
118+
- **Nested objects** (`build`, `run`, `deploy`, `healthCheck`, `readinessCheck`, `routing`, ...): only the keys the child specifies are overwritten, everything else is inherited. `run: { start: x }` in the child keeps the parent's `run.envVariables`, `run.ports`, etc.
119+
- **Maps** (`envVariables`): merged. Child keys are added, same-named keys take the child value, remaining parent keys stay. `KEY: null` removes an inherited variable (`KEY: ""` is a regular empty value); `envVariables: null` drops the whole inherited map.
120+
- **Lists** (`buildCommands`, `prepareCommands`, `initCommands`, `deployFiles`, `ports`, `startCommands`, `crontab`, `cache` as a list): **replaced as a whole**, never appended. Repeat the full list in the child. `[]` clears it.
121+
- **Chains** resolve transitively (`prod` extends `staging` extends `base`) in any file order, up to 25 levels deep. A setup cannot extend itself.
122+
- Must reference another `setup` name in the same file.
123+
- **Multiple parents** (`extends: [base, logging]`): resolved exactly as if `logging` extended `base` and the child extended `logging`. Later parents win over earlier ones (including their own ancestry), the child's own keys win over all parents. Same map-merge / list-replace rules apply at every step.
117124

118125
```yaml
119126
zerops:
120127
- setup: base
121-
build: { buildCommands: [npm run build], deployFiles: ./dist }
122-
- setup: logging
123-
run: { envVariables: { LOG_LEVEL: info } }
128+
build: { buildCommands: [npm ci, npm run build], deployFiles: ./dist }
129+
run: { start: npm start, envVariables: { LOG_LEVEL: info, NODE_ENV: development } }
124130
- setup: prod
125-
extends: [base, logging]
126-
run: { envVariables: { NODE_ENV: production } }
131+
extends: base
132+
build: { buildCommands: [npm ci, npm run build -- --mode=production] } # list replaced, deployFiles inherited
133+
run: { envVariables: { NODE_ENV: production, LOG_LEVEL: null } } # merged: NODE_ENV=production, LOG_LEVEL removed; start inherited
134+
- setup: logging
135+
run: { envVariables: { LOG_LEVEL: debug, LOG_FORMAT: json } }
136+
- setup: prod-debug
137+
extends: [prod, logging] # everything from prod, then LOG_LEVEL=debug and LOG_FORMAT=json from logging; NODE_ENV=production inherited via prod
127138
```
128139

129-
Configuration is **merged at the section level** -- child values override parent values within each section (build, run, deploy), but unspecified sections inherit from parent. Must reference another `setup` name in the same file.
130-
131140
## Base Images
132141

133142
Available runtimes and versions are listed in **Service Stacks (live)** -- injected by `zerops_knowledge` and workflow responses. Some key rules:

‎apps/docs/content/zerops-yaml/specification.mdx‎

Lines changed: 69 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -109,9 +109,75 @@ zerops:
109109

110110
When using `extends`:
111111
- The `extends` value must refer to another service's `setup` value in the same file
112-
- The child service inherits all configuration from the base service
113-
- Configuration is merged at the section level (`build`, `run`, `deploy`)
114-
- You can override specific sections by redefining them
112+
- The child service starts as a full copy of the base service, then its own keys are applied on top
113+
- Merging is recursive, key by key. Redefining `run` in the child does not replace the whole `run` section, only the keys you specify inside it. The same applies to nested objects such as `healthCheck` or `readinessCheck`
114+
- Maps such as `envVariables` are merged: the child's keys are added to the base's keys, and a key defined in both takes the child's value. Setting a key to `null` removes the inherited variable (an empty string `""` is a regular value), and `envVariables: null` drops the whole inherited map
115+
- Lists such as `buildCommands`, `initCommands`, `deployFiles`, `ports` or `startCommands` are replaced as a whole, never appended. If you need to change a list, define the full list in the child
116+
- A base service can itself extend another service. Chains are resolved regardless of the order of services in the file. A service cannot extend itself
117+
- `extends` also accepts a list, for example `extends: [base, logging]`. The child is then resolved exactly as if `logging` extended `base` and the child extended `logging`: later services in the list override earlier ones, and the child's own keys override all of them
118+
119+
The following example shows how maps and lists behave differently:
120+
121+
```yaml
122+
zerops:
123+
- setup: base
124+
build:
125+
base: nodejs@22
126+
buildCommands:
127+
- npm ci
128+
- npm run build
129+
deployFiles: ./dist
130+
run:
131+
base: nodejs@22
132+
start: npm start
133+
envVariables:
134+
LOG_LEVEL: info
135+
NODE_ENV: development
136+
137+
- setup: prod
138+
extends: base
139+
build:
140+
buildCommands:
141+
- npm ci
142+
- npm run build -- --mode=production
143+
run:
144+
envVariables:
145+
NODE_ENV: production
146+
LOG_LEVEL: null
147+
148+
- setup: dev
149+
extends: base
150+
run:
151+
envVariables:
152+
DEBUG: "1"
153+
```
154+
155+
The resolved `prod` service is:
156+
157+
```yaml
158+
setup: prod
159+
build:
160+
base: nodejs@22 # inherited
161+
buildCommands: # list replaced as a whole
162+
- npm ci
163+
- npm run build -- --mode=production
164+
deployFiles: ./dist # inherited
165+
run:
166+
base: nodejs@22 # inherited
167+
start: npm start # inherited
168+
envVariables: # map merged key by key, LOG_LEVEL removed by null
169+
NODE_ENV: production
170+
```
171+
172+
And `dev` keeps everything from `base` and adds `DEBUG`:
173+
174+
```yaml
175+
run:
176+
envVariables:
177+
LOG_LEVEL: info
178+
NODE_ENV: development
179+
DEBUG: "1"
180+
```
115181

116182
:::tip
117183
Create a base service with common configuration and extend it for environment-specific services to keep your `zerops.yaml` file DRY (Don't Repeat Yourself).

‎apps/docs/static/llms-full.txt‎

Lines changed: 86 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -17075,21 +17075,30 @@ zerops:
1707517075
run: { envVariables: { NODE_ENV: production } }
1707617076
```
1707717077

17078-
Supports single parent (`extends: base`) or multiple parents (`extends: [base, logging]`) -- later parents override earlier ones:
17078+
The child is a deep copy of the resolved parent with its own keys applied on top. The merge is **recursive, key by key**:
17079+
17080+
- **Nested objects** (`build`, `run`, `deploy`, `healthCheck`, `readinessCheck`, `routing`, ...): only the keys the child specifies are overwritten, everything else is inherited. `run: { start: x }` in the child keeps the parent's `run.envVariables`, `run.ports`, etc.
17081+
- **Maps** (`envVariables`): merged. Child keys are added, same-named keys take the child value, remaining parent keys stay. `KEY: null` removes an inherited variable (`KEY: ""` is a regular empty value); `envVariables: null` drops the whole inherited map.
17082+
- **Lists** (`buildCommands`, `prepareCommands`, `initCommands`, `deployFiles`, `ports`, `startCommands`, `crontab`, `cache` as a list): **replaced as a whole**, never appended. Repeat the full list in the child. `[]` clears it.
17083+
- **Chains** resolve transitively (`prod` extends `staging` extends `base`) in any file order, up to 25 levels deep. A setup cannot extend itself.
17084+
- Must reference another `setup` name in the same file.
17085+
- **Multiple parents** (`extends: [base, logging]`): resolved exactly as if `logging` extended `base` and the child extended `logging`. Later parents win over earlier ones (including their own ancestry), the child's own keys win over all parents. Same map-merge / list-replace rules apply at every step.
1707917086

1708017087
```yaml
1708117088
zerops:
1708217089
- setup: base
17083-
build: { buildCommands: [npm run build], deployFiles: ./dist }
17084-
- setup: logging
17085-
run: { envVariables: { LOG_LEVEL: info } }
17090+
build: { buildCommands: [npm ci, npm run build], deployFiles: ./dist }
17091+
run: { start: npm start, envVariables: { LOG_LEVEL: info, NODE_ENV: development } }
1708617092
- setup: prod
17087-
extends: [base, logging]
17088-
run: { envVariables: { NODE_ENV: production } }
17093+
extends: base
17094+
build: { buildCommands: [npm ci, npm run build -- --mode=production] } # list replaced, deployFiles inherited
17095+
run: { envVariables: { NODE_ENV: production, LOG_LEVEL: null } } # merged: NODE_ENV=production, LOG_LEVEL removed; start inherited
17096+
- setup: logging
17097+
run: { envVariables: { LOG_LEVEL: debug, LOG_FORMAT: json } }
17098+
- setup: prod-debug
17099+
extends: [prod, logging] # everything from prod, then LOG_LEVEL=debug and LOG_FORMAT=json from logging; NODE_ENV=production inherited via prod
1708917100
```
1709017101

17091-
Configuration is **merged at the section level** -- child values override parent values within each section (build, run, deploy), but unspecified sections inherit from parent. Must reference another `setup` name in the same file.
17092-
1709317102
## Base Images
1709417103

1709517104
Available runtimes and versions are listed in **Service Stacks (live)** -- injected by `zerops_knowledge` and workflow responses. Some key rules:
@@ -44499,9 +44508,75 @@ zerops:
4449944508

4450044509
When using `extends`:
4450144510
- The `extends` value must refer to another service's `setup` value in the same file
44502-
- The child service inherits all configuration from the base service
44503-
- Configuration is merged at the section level (`build`, `run`, `deploy`)
44504-
- You can override specific sections by redefining them
44511+
- The child service starts as a full copy of the base service, then its own keys are applied on top
44512+
- Merging is recursive, key by key. Redefining `run` in the child does not replace the whole `run` section, only the keys you specify inside it. The same applies to nested objects such as `healthCheck` or `readinessCheck`
44513+
- Maps such as `envVariables` are merged: the child's keys are added to the base's keys, and a key defined in both takes the child's value. Setting a key to `null` removes the inherited variable (an empty string `""` is a regular value), and `envVariables: null` drops the whole inherited map
44514+
- Lists such as `buildCommands`, `initCommands`, `deployFiles`, `ports` or `startCommands` are replaced as a whole, never appended. If you need to change a list, define the full list in the child
44515+
- A base service can itself extend another service. Chains are resolved regardless of the order of services in the file. A service cannot extend itself
44516+
- `extends` also accepts a list, for example `extends: [base, logging]`. The child is then resolved exactly as if `logging` extended `base` and the child extended `logging`: later services in the list override earlier ones, and the child's own keys override all of them
44517+
44518+
The following example shows how maps and lists behave differently:
44519+
44520+
```yaml
44521+
zerops:
44522+
- setup: base
44523+
build:
44524+
base: nodejs@22
44525+
buildCommands:
44526+
- npm ci
44527+
- npm run build
44528+
deployFiles: ./dist
44529+
run:
44530+
base: nodejs@22
44531+
start: npm start
44532+
envVariables:
44533+
LOG_LEVEL: info
44534+
NODE_ENV: development
44535+
44536+
- setup: prod
44537+
extends: base
44538+
build:
44539+
buildCommands:
44540+
- npm ci
44541+
- npm run build -- --mode=production
44542+
run:
44543+
envVariables:
44544+
NODE_ENV: production
44545+
LOG_LEVEL: null
44546+
44547+
- setup: dev
44548+
extends: base
44549+
run:
44550+
envVariables:
44551+
DEBUG: "1"
44552+
```
44553+
44554+
The resolved `prod` service is:
44555+
44556+
```yaml
44557+
setup: prod
44558+
build:
44559+
base: nodejs@22 # inherited
44560+
buildCommands: # list replaced as a whole
44561+
- npm ci
44562+
- npm run build -- --mode=production
44563+
deployFiles: ./dist # inherited
44564+
run:
44565+
base: nodejs@22 # inherited
44566+
start: npm start # inherited
44567+
envVariables: # map merged key by key, LOG_LEVEL removed by null
44568+
NODE_ENV: production
44569+
```
44570+
44571+
And `dev` keeps everything from `base` and adds `DEBUG`:
44572+
44573+
```yaml
44574+
run:
44575+
envVariables:
44576+
LOG_LEVEL: info
44577+
NODE_ENV: development
44578+
DEBUG: "1"
44579+
```
4450544580

4450644581
:::tip
4450744582
Create a base service with common configuration and extend it for environment-specific services to keep your `zerops.yaml` file DRY (Don't Repeat Yourself).

‎apps/docs/static/llms-small.txt‎

Lines changed: 86 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -16766,21 +16766,30 @@ zerops:
1676616766
run: { envVariables: { NODE_ENV: production } }
1676716767
```
1676816768

16769-
Supports single parent (`extends: base`) or multiple parents (`extends: [base, logging]`) -- later parents override earlier ones:
16769+
The child is a deep copy of the resolved parent with its own keys applied on top. The merge is **recursive, key by key**:
16770+
16771+
- **Nested objects** (`build`, `run`, `deploy`, `healthCheck`, `readinessCheck`, `routing`, ...): only the keys the child specifies are overwritten, everything else is inherited. `run: { start: x }` in the child keeps the parent's `run.envVariables`, `run.ports`, etc.
16772+
- **Maps** (`envVariables`): merged. Child keys are added, same-named keys take the child value, remaining parent keys stay. `KEY: null` removes an inherited variable (`KEY: ""` is a regular empty value); `envVariables: null` drops the whole inherited map.
16773+
- **Lists** (`buildCommands`, `prepareCommands`, `initCommands`, `deployFiles`, `ports`, `startCommands`, `crontab`, `cache` as a list): **replaced as a whole**, never appended. Repeat the full list in the child. `[]` clears it.
16774+
- **Chains** resolve transitively (`prod` extends `staging` extends `base`) in any file order, up to 25 levels deep. A setup cannot extend itself.
16775+
- Must reference another `setup` name in the same file.
16776+
- **Multiple parents** (`extends: [base, logging]`): resolved exactly as if `logging` extended `base` and the child extended `logging`. Later parents win over earlier ones (including their own ancestry), the child's own keys win over all parents. Same map-merge / list-replace rules apply at every step.
1677016777

1677116778
```yaml
1677216779
zerops:
1677316780
- setup: base
16774-
build: { buildCommands: [npm run build], deployFiles: ./dist }
16775-
- setup: logging
16776-
run: { envVariables: { LOG_LEVEL: info } }
16781+
build: { buildCommands: [npm ci, npm run build], deployFiles: ./dist }
16782+
run: { start: npm start, envVariables: { LOG_LEVEL: info, NODE_ENV: development } }
1677716783
- setup: prod
16778-
extends: [base, logging]
16779-
run: { envVariables: { NODE_ENV: production } }
16784+
extends: base
16785+
build: { buildCommands: [npm ci, npm run build -- --mode=production] } # list replaced, deployFiles inherited
16786+
run: { envVariables: { NODE_ENV: production, LOG_LEVEL: null } } # merged: NODE_ENV=production, LOG_LEVEL removed; start inherited
16787+
- setup: logging
16788+
run: { envVariables: { LOG_LEVEL: debug, LOG_FORMAT: json } }
16789+
- setup: prod-debug
16790+
extends: [prod, logging] # everything from prod, then LOG_LEVEL=debug and LOG_FORMAT=json from logging; NODE_ENV=production inherited via prod
1678016791
```
1678116792

16782-
Configuration is **merged at the section level** -- child values override parent values within each section (build, run, deploy), but unspecified sections inherit from parent. Must reference another `setup` name in the same file.
16783-
1678416793
## Base Images
1678516794

1678616795
Available runtimes and versions are listed in **Service Stacks (live)** -- injected by `zerops_knowledge` and workflow responses. Some key rules:
@@ -37509,9 +37518,75 @@ zerops:
3750937518

3751037519
When using `extends`:
3751137520
- The `extends` value must refer to another service's `setup` value in the same file
37512-
- The child service inherits all configuration from the base service
37513-
- Configuration is merged at the section level (`build`, `run`, `deploy`)
37514-
- You can override specific sections by redefining them
37521+
- The child service starts as a full copy of the base service, then its own keys are applied on top
37522+
- Merging is recursive, key by key. Redefining `run` in the child does not replace the whole `run` section, only the keys you specify inside it. The same applies to nested objects such as `healthCheck` or `readinessCheck`
37523+
- Maps such as `envVariables` are merged: the child's keys are added to the base's keys, and a key defined in both takes the child's value. Setting a key to `null` removes the inherited variable (an empty string `""` is a regular value), and `envVariables: null` drops the whole inherited map
37524+
- Lists such as `buildCommands`, `initCommands`, `deployFiles`, `ports` or `startCommands` are replaced as a whole, never appended. If you need to change a list, define the full list in the child
37525+
- A base service can itself extend another service. Chains are resolved regardless of the order of services in the file. A service cannot extend itself
37526+
- `extends` also accepts a list, for example `extends: [base, logging]`. The child is then resolved exactly as if `logging` extended `base` and the child extended `logging`: later services in the list override earlier ones, and the child's own keys override all of them
37527+
37528+
The following example shows how maps and lists behave differently:
37529+
37530+
```yaml
37531+
zerops:
37532+
- setup: base
37533+
build:
37534+
base: nodejs@22
37535+
buildCommands:
37536+
- npm ci
37537+
- npm run build
37538+
deployFiles: ./dist
37539+
run:
37540+
base: nodejs@22
37541+
start: npm start
37542+
envVariables:
37543+
LOG_LEVEL: info
37544+
NODE_ENV: development
37545+
37546+
- setup: prod
37547+
extends: base
37548+
build:
37549+
buildCommands:
37550+
- npm ci
37551+
- npm run build -- --mode=production
37552+
run:
37553+
envVariables:
37554+
NODE_ENV: production
37555+
LOG_LEVEL: null
37556+
37557+
- setup: dev
37558+
extends: base
37559+
run:
37560+
envVariables:
37561+
DEBUG: "1"
37562+
```
37563+
37564+
The resolved `prod` service is:
37565+
37566+
```yaml
37567+
setup: prod
37568+
build:
37569+
base: nodejs@22 # inherited
37570+
buildCommands: # list replaced as a whole
37571+
- npm ci
37572+
- npm run build -- --mode=production
37573+
deployFiles: ./dist # inherited
37574+
run:
37575+
base: nodejs@22 # inherited
37576+
start: npm start # inherited
37577+
envVariables: # map merged key by key, LOG_LEVEL removed by null
37578+
NODE_ENV: production
37579+
```
37580+
37581+
And `dev` keeps everything from `base` and adds `DEBUG`:
37582+
37583+
```yaml
37584+
run:
37585+
envVariables:
37586+
LOG_LEVEL: info
37587+
NODE_ENV: development
37588+
DEBUG: "1"
37589+
```
3751537590

3751637591
:::tip
3751737592
Create a base service with common configuration and extend it for environment-specific services to keep your `zerops.yaml` file DRY (Don't Repeat Yourself).

0 commit comments

Comments
 (0)