Environment Variables
About 2085 wordsAbout 7 min
Cloud Native Build supports declaring the build environment and defining environment variables used during the build process.
Cloud Native Build comes with some default environment variables for direct use.
Feature Overview
Environment variables support the following features:
| Feature | Description |
|---|---|
| Declare Environment Variables | Declare environment variables via env |
| Import Environment Variables | Import secret vault files via imports |
| Export Environment Variables | Export task results as environment variables |
| Use Environment Variables | Reference environment variables in scripts and config |
Declaring Environment Variables
Declare environment variables via env:
- Environment variables declared in
Pipelineare effective for the entire pipeline. - Environment variables declared in
Jobare only effective for the current task.
In the example below, docker.image declares the build environment as node:22, Pipeline-level env declares two environment variables, and Job-level declares a variable effective only for that task:
main:
push:
- docker:
image: node:22
env:
PIPELINE_ENV_1: pipeline environment variable 1
PIPELINE_ENV_2: pipeline environment variable 2
stages:
- name: Output build environment information
script: node -v
- name: Output pipeline environment variables
script:
- echo $PIPELINE_ENV_1
- echo $PIPELINE_ENV_2
- name: Output job environment variables
env:
JOB_ENV: job environment variable
script: echo $JOB_ENVImporting Environment Variables
Use imports to import a secrets file, injecting sensitive information as environment variables for use by subsequent tasks.
Priority Rules
When there's a conflict between env and imports keys, env takes precedence.
Example
The example below imports the secrets file envs.yml, where TEST_DOCKER_DOMAIN, TEST_DOCKER_USER, TEST_DOCKER_PWD are available for subsequent tasks:
main:
push:
- services:
- docker
imports: https://cnb.cool/<your-repo-slug>/-/blob/main/xxx/envs.yml
stages:
- name: docker info
script: docker info
- name: docker login
script: docker login $TEST_DOCKER_DOMAIN -u $TEST_DOCKER_USER -p $TEST_DOCKER_PWDenvs.yml content example:
# Docker registry domain
TEST_DOCKER_DOMAIN: registry.example.com
# Docker username
TEST_DOCKER_USER: your_docker_username
# Docker password
TEST_DOCKER_PWD: your_docker_passwordExporting Environment Variables
After a Job completes, there is a result object. You can use exports to export its properties as environment variables, with a lifecycle of the current Pipeline.
Syntax Format
exports:
from-key: to-keyParameter Description:
| Parameter | Description |
|---|---|
| from-key | Property name from Job result to export |
| to-key | Variable name to map to in environment variables |
from-keysupports environment variables and deep property access (similar tolodash.get).
Result Setting Methods
The following three methods can set result:
| Method | Description |
|---|---|
| Script task execution results | Output after script execution completes |
| Parse custom variables from output | Output variables through special format |
| Built-in task results | Result objects returned by built-in tasks |
Script Task Execution Results
After a script task executes, the Job result contains the following properties:
| Property | Description |
|---|---|
| code | Return code |
| stdout | Standard output |
| stderr | Standard error |
| info | Mixed stdout and stderr, in chronological order |
Output Tips
You can use printf "%s" "hello\nworld" to output variables, which removes trailing newlines from standard output while preserving escape characters like \n.
Example:
main:
push:
- stages:
- name: set env
script: echo -n $(date "+%Y-%m-%d %H:%M")
exports:
code: CUSTOM_ENV_DATE_CODE
info: CUSTOM_ENV_DATE_INFO
- name: echo env
script:
- echo $CUSTOM_ENV_DATE_CODE
- echo $CUSTOM_ENV_DATE_INFOProperties with Conditional Logic:
When conditional logic such as if, ifModify, ifNewBranch is present, the following additional property is available:
| Property | Description |
|---|---|
| skip | Skip reason if task is skipped; empty string otherwise |
The skip property only appears when conditional logic (if, ifModify, ifNewBranch) evaluates to skip the task.
- name: use if
if: exit -1
exports:
skip: REASON
- name: tell last
# $REASON value is the string "if"
script: echo $REASONParsing Custom Variables from Output
CI recognizes ##[set-output key=value] formatted content line by line from the standard output stream and automatically parses it into the result object.
Variable Value Encoding
If the variable value contains newline \n, you can encode the variable value with base64 or escape:
| Encoding Method | Description |
|---|---|
| base64 | Value starts with base64,, decoded as base64 |
| escape | The system unescapes the variable value |
Approach 1 — Node.js (requires test.js, outputs both base64 and escape):
main:
push:
- docker:
image: node:20-alpine
stages:
- name: set output env
script: node test.js
exports:
redline_msg_base64: BASE64_KEY
redline_msg_escape: ESCAPE_KEY
- name: echo env
script:
- echo "BASE64_KEY $BASE64_KEY"
- echo "ESCAPE_KEY $ESCAPE_KEY"Approach 2 — Shell echo (pure Shell, no script file needed, outputs base64 only):
main:
push:
- stages:
- name: set output env
script: echo "##[set-output redline_msg_base64=base64,$(echo -e "Test string\ntest string" | base64 -w 0)]"
exports:
redline_msg_base64: BASE64_KEY
- name: echo env
script:
- echo "BASE64_KEY $BASE64_KEY"Node.js script (test.js, used by Approach 1 above):
const value = 'Test string\ntest string';
console.log(`##[set-output redline_msg_base64=base64,${Buffer.from(value, 'utf-8').toString('base64')}]`);
console.log(`##[set-output redline_msg_escape=${escape(value)}]`);Note
In Unix-like systems, the base64 command adds a newline every 76 characters by default. You can use the -w 0 option to disable newlines to avoid CI failing to parse variables by line.
Variable values without \n can be output directly:
echo "##[set-output redline_msg=some value]"Limitations
- Due to system environment variable length limits, excessively large variable values are invalid
- CI will ignore variable values >=
100KB, you can write to files and parse them yourself - For sensitive information, it's recommended to use the read-file built-in task
Exporting Environment Variables from Built-in Tasks
Some built-in tasks have output results that can be exported as environment variables via exports.
main:
push:
- stages:
- name: xxxx
type: xxx:xxx
options:
product: public
name: cnb
dist: release/
exports:
version: CUSTOM_ENV_VERSION
url: CUSTOM_ENV_URL
nextRelease.gitTag: CUSTOM_ENV_GIT_TAG
- name: echo env
script:
- echo $CUSTOM_ENV_VERSION
- echo $CUSTOM_ENV_URLRefer to each built-in task's documentation for result content.
Passing Variables from a Sub-Pipeline to the Parent Pipeline
A pipeline triggered via cnb:apply (same repo) or cnb:trigger (cross repo)—referred to as a "sub-pipeline"—returns lastJobExports in its result when running in sync: true mode. lastJobExports contains all environment variables exported via exports by the last Job of the sub-pipeline, allowing the parent pipeline to obtain the sub-pipeline's outputs.
Main result properties in sync mode:
| Property | Description |
|---|---|
| sn | Sub-pipeline build number |
| buildLogUrl | Sub-pipeline build log URL |
| buildSuccess | Whether the sub-pipeline succeeded (sync mode only) |
| lastJobExports | Environment variables exported by the sub-pipeline's last Job |
Note
Only sync: true waits for the sub-pipeline to finish and returns lastJobExports. In async mode, the parent pipeline does not wait and cannot get these results.
Example: the sub-pipeline outputs and exports a variable, and the parent pipeline retrieves it after a synchronous trigger.
main:
api_trigger_test:
- stages:
- name: sub-pipeline outputs a variable
script: echo "##[set-output sub_result=base64,$(echo -e "test string\nsecond line" | base64 -w 0)]"
exports:
sub_result: SUB_RESULT
push:
- stages:
- name: trigger sub-pipeline and wait
type: cnb:apply
options:
event: api_trigger_test
sync: true
exports:
lastJobExports: SUB_EXPORTS
lastJobExports.SUB_RESULT: SUB_RESULT
sn: SUB_SN
- name: use variables returned by the sub-pipeline
script: |
echo "SUB_EXPORTS: $SUB_EXPORTS"
echo "SUB_SN: $SUB_SN"
echo "SUB_RESULT: $SUB_RESULT"For cross-repo scenarios, replace cnb:apply with cnb:trigger and specify the target repo slug; variables are retrieved the same way.
Managing Environment Variables
Existing environment variables cannot be modified directly. Setting to an empty string or null will delete them.
main:
push:
- env:
CUSTOM_ENV_DATE_INFO: default
CUSTOM_ENV_FOR_DELETE: default
stages:
- name: set env
script: echo -n $(date "+%Y-%m-%d %H:%M")
exports:
# Add new
code: CUSTOM_ENV_DATE_CODE
# Modify
info: CUSTOM_ENV_DATE_INFO
# Delete
CUSTOM_ENV_FOR_DELETE: null
# Alternative delete syntax
# CUSTOM_ENV_FOR_DELETE:
- name: echo env
script:
- echo $CUSTOM_ENV_DATE_CODE
- echo $CUSTOM_ENV_DATE_INFO
- echo $CUSTOM_ENV_DATE_STDOUT
- echo $CUSTOM_ENV_FOR_DELETE
- echo $CUSTOM_ENV_GIT_TAGUsing Environment Variables
In Script Tasks
When tasks execute, pipeline-declared environment variables are passed as task environment variables. In the example below, CNB_BRANCH is a built-in environment variable:
main:
push:
- stages:
- name: test internal env
script: echo $CNB_BRANCH
- name: test self defined env
env:
cat_name: tomcat
script: echo $cat_nameVariable Substitution
Some property values in configuration files will undergo variable substitution.
Substitution Rules: If there's an environment variable env_name=env_value, then $env_name in property values will be replaced with env_value. If env_name has no value, it will be replaced with an empty string.
Properties Supporting Variable Substitution
| Property | Description |
|---|---|
| Built-in task options | options and optionsFrom |
| Plugin task settings | settings and settingsFrom |
| env | Can reference parent env variables |
| imports | Values in imports and declared files |
| pipeline.runner.tags | Build node tags |
| pipeline.docker | volumes, image and build |
| stage.image and job.image | Environment image configuration |
| ifModify | File change conditions |
| name | pipeline.name, stage.name and job.name |
| lock.key | Lock key name |
| allowFailure | Allow failure configuration |
Built-in Task Example
# options.yml
name: Nightlymain:
push:
- env:
address: options.yml
description: publish for xx task
stages:
- name: git release
type: git:release
optionsFrom: $address
options:
description: $descriptionFinal options content:
name: Nightly
description: publish for xx taskPlugin Task Example
# settings.yml
robot: https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=xxxmain:
push:
- env:
address: settings.yml
message: pr check
stages:
- name: notify
image: tencentcom/wecom-message
settingsFrom: $address
settings:
content: $messageFinal settings content:
robot: https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=xxx
message: pr checksettingsFrom in Dockerfile
settingsFrom specified in Dockerfile LABEL also supports variable substitution:
FROM node:20
LABEL cnb.cool/settings-from="$address"env Example
Property values declared under env can reference variables from parent env for substitution:
main:
push:
- env:
cat_name: tomcat
stages:
- name: echo env
env:
name: "cat $cat_name"
script: echo $nameimports Example
Property values in imports and in declared files will undergo variable substitution. If imports is an array, variables declared in earlier files are effective for later array elements.
In the example below, env1.yml declares address: env2.yml, so $address is replaced with env2.yml, which then imports variables from env2.yml:
# env1.yml
address: env2.yml
platform: amd64# env2.yml
action: build for $platformmain:
push:
- imports:
- env1.yml
- $address
stages:
- name: echo action
script: echo $actionpipeline.runner.tags Example
# Build images for different architectures
.build: &build
runner:
tags: cnb:arch:$CNB_PIPELINE_NAME
services:
- docker
stages:
- name: docker build
script: echo "docker build for $CNB_PIPELINE_NAME"
main:
push:
# "amd64" and "arm64:v8" below will be declared as values of built-in environment variable CNB_PIPELINE_NAME
amd64: *build
"arm64:v8": *buildpipeline.docker Example
main:
push:
- docker:
image: node:22-alpine
volumes:
- /data
stages:
- name: echo
script: echo "building with docker"ifModify Example
# Only compile corresponding module when code under different modules has changes
.build: &build
ifModify: $CNB_PIPELINE_NAME/*
stages:
- name: build $CNB_PIPELINE_NAME
script: echo "build $CNB_PIPELINE_NAME"
main:
push:
module-a: *build
module-b: *buildname Example
Property values of pipeline.name, stage.name and job.name will undergo variable substitution:
main:
push:
- name: build in $CNB_REPO_SLUG
env:
platform: amd64
imports:
- env1.yml
- env2.yml
stages:
- name: stage_$SOME_ENV
script: echo "hello world"lock.key Example
# env.yml
build_key: build key.build: &build
imports: env.yml
lock:
key: $build_key
stages:
- name: echo
script: echo "hello world"
main:
push:
# Of these two pipelines, one acquires the lock and executes successfully, the other fails to acquire the lock
- *build
- *buildallowFailure Example
main:
push:
- env:
allow_fail: true
stages:
- name: echo
allowFailure: $allow_fail
script: echo1 1Preventing Variable Substitution
If you don't want $env_name to be replaced, you can prevent substitution via \$:
main:
push:
- stages:
- name: git release
type: git:release
options:
name: Development
description: some code update \$descriptionLimitations
Environment variables have the following limitations:
| Limitation Item | Description |
|---|---|
| Variable name format | Letters, numbers, and underscores only; cannot start with a number |
| Variable value length | Cannot exceed 100KiB |
Note
Variables that don't meet the above rules will be ignored.
Proxy Environment Variable Auto-Sync
When a pipeline runs inside a Docker container, the following proxy-related environment variables are automatically synced from the Runner host into the container, without any manual declaration in .cnb.yml:
| Variable | Description |
|---|---|
HTTP_PROXY | HTTP proxy address |
HTTPS_PROXY | HTTPS proxy address |
NO_PROXY | Addresses that bypass the proxy |
http_proxy | HTTP proxy address (lowercase) |
https_proxy | HTTPS proxy address (lowercase) |
no_proxy | Addresses that bypass the proxy (lowercase) |
Value Rules
When not declared in env, these proxy variables automatically inherit the Runner host configuration, so no manual setup is needed. If declared in env, the user-declared value takes precedence.