Environment Variables Reference
Environment variables used by icp-cli.
Build Script Variables
During script build steps, icp-cli sets the following environment variables. The script runs with the canister directory as the current working directory, so relative paths in your build commands resolve from there.
ICP_WASM_OUTPUT_PATH
A temporary file path where your build script must place the compiled WASM file.
icp-cli creates a temporary directory before running your build script and sets ICP_WASM_OUTPUT_PATH to a file path within it (e.g., /tmp/abc123/out.wasm). Your script must copy or write the final WASM to this location. After your script completes, icp-cli reads the WASM from this path and stores it for deployment.
Example:
build: steps: - type: script commands: - cargo build --target wasm32-unknown-unknown --release - |- TARGET_DIR=$(cargo metadata --format-version 1 --no-deps | sed -n 's/.*"target_directory":"\([^"]*\)".*/\1/p') cp "${TARGET_DIR}/wasm32-unknown-unknown/release/my_canister.wasm" "$ICP_WASM_OUTPUT_PATH"ICP_CLI_ENVIRONMENT
The name of the environment being built for (e.g. local, staging, production). icp build and icp deploy take it from their -e/--environment argument, defaulting to local; icp project bundle takes it from its own -e/--environment, defaulting to ic because a bundle is built to be deployed elsewhere.
The artifact a build produces is stored per canister, not per environment, so the most recent build wins. icp build and icp deploy always rebuild, but icp canister install without --wasm installs whatever is stored — including the ic build left behind by icp project bundle — regardless of its own -e/--environment.
Sync scripts receive this variable as well.
Sync Script Variables
During script sync steps, icp-cli sets ICP_CLI_ENVIRONMENT as described above, plus the following:
ICP_CLI_NETWORK
The name of the current network (e.g. local, ic).
ICP_CLI_CID
The canister ID (principal) of the canister being synced.
ICP_CLI_CID_<NAME>
The canister ID (principal) of every canister with a registered ID in the current environment, one variable per canister. <NAME> is the canister name uppercased with any non-alphanumeric character replaced by _.
For example, a project with canisters backend and my-frontend produces:
ICP_CLI_CID_BACKEND=bkyz2-fmaaa-aaaaa-qaaaq-caiICP_CLI_CID_MY_FRONTEND=bd3sg-teaaa-aaaaa-qaaba-caiExample:
sync: steps: - type: script commands: - echo "Syncing canister $ICP_CLI_CID on $ICP_CLI_NETWORK" - my-tool upload --canister "$ICP_CLI_CID" --backend "$ICP_CLI_CID_BACKEND"Like build scripts, sync scripts run with the canister directory as the current working directory.
CLI Configuration Variables
ICP_ENVIRONMENT
Sets the default environment when no -e/--environment flag is provided.
| Default | local |
|---|
export ICP_ENVIRONMENT=stagingicp deploy # Deploys to staging environmentThis is equivalent to passing -e staging to commands that accept an environment flag. The explicit -e flag takes precedence over this variable.
ICP_NETWORK
Sets the default network when no -n/--network flag is provided.
| Default | local |
|---|
export ICP_NETWORK=icicp token balance # Checks balance on IC mainnetThis is equivalent to passing -n ic to commands that accept a network flag. The explicit -n flag takes precedence over this variable.
ICP_PROJECT_ROOT
Sets the project root directory, equivalent to the global --project-root-override flag.
By default, icp-cli walks up from the current directory to the workspace root (the top-most project that declares the one you are in as a dependency). When this variable is set, the given directory is used as the root with no upward walk. It must contain an icp.yaml:
export ICP_PROJECT_ROOT=./vendor/my-projecticp deploy # Deploys my-project on its own, not as part of the workspaceThe explicit --project-root-override flag takes precedence over this variable. See Project Dependencies.
ICP_HOME
Overrides the default location for global icp-cli data (identities, package cache).
By default, icp-cli stores global data in platform-standard directories:
| Platform | Default Location |
|---|---|
| macOS | ~/Library/Application Support/org.dfinity.icp-cli/ |
| Linux | ~/.local/share/icp-cli/ |
| Windows | %APPDATA%\icp-cli\data\ |
When ICP_HOME is set, all global data is stored in that directory instead:
export ICP_HOME=~/.icp
# Identities will be stored in ~/.icp/identity/# Package cache will be stored in ~/.icp/pkg/Use cases:
- Keep icp-cli data in a specific location
- Share identities across machines via a synced folder
- Isolate icp-cli data for testing
ICP_CLI_NETWORK_LAUNCHER_PATH
Path to a custom network launcher binary.
By default, icp-cli automatically downloads the network launcher on first use. Set this variable to use a specific binary instead:
export ICP_CLI_NETWORK_LAUNCHER_PATH=/path/to/icp-cli-network-launcherUse cases:
- Air-gapped or offline environments where auto-download isn’t possible
- Testing a custom or development version of the launcher
- CI environments where you pre-download dependencies
Download the launcher manually from icp-cli-network-launcher releases.
ICP_CLI_GITHUB_TOKEN
A GitHub token icp-cli sends when it fetches the network launcher or checks GitHub for updates. Set it in CI to avoid hitting GitHub’s rate limit for unauthenticated requests.
In GitHub Actions:
env: ICP_CLI_GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}ICP_CLI_PLUGIN_COMPUTE_LIMIT_SECS
Maximum seconds of pure WebAssembly compute a sync plugin may use during icp sync. Defaults to 60.
This is a runaway guard, not a security limit: sync plugins run locally in a read-only sandbox, so the limit only protects the machine running icp sync from a plugin that never terminates. Network/canister-call latency is already excluded from the budget, so the limit counts only time the plugin spends executing.
Legitimately heavy plugins — for example, brotli-compressing a large asset bundle — can exceed the default, especially on slower CI runners where the same work takes more wall-clock time. Raise the limit if you hit plugin exceeded the 60s compute-time limit:
export ICP_CLI_PLUGIN_COMPUTE_LIMIT_SECS=300An invalid value (non-integer or 0) is rejected rather than silently ignored, so a typo can’t leave you thinking you raised the limit when you didn’t.
Use cases:
- CI jobs syncing large asset bundles that trip the default limit
- Compression-heavy or otherwise compute-intensive sync plugins
ENGINE_CANISTER_ID
The engine canister that --engine resolves cloud engine names through, and that cloud engine subnets are looked up in when creating canisters. When set to a canister id, it overrides the built-in mainnet engine canister. An empty value is ignored; an invalid one is an error.
export ENGINE_CANISTER_ID=<canister-id>icp deploy -e staging --engine my-engineICP_CYCLES_GATEWAY_CANISTER_ID
The cycles gateway canister that icp cycles buy buys cycles with a card through: any canister serving the cycles gateway interface. Defaults to CyclePay’s backend canister on mainnet (2bwus-iiaaa-aaaac-bee3a-cai). icp cycles buy --gateway takes precedence. An empty value is ignored; an invalid one is an error, so a typo never sends an order to the default gateway. Everything else about the gateway, its payment page, its per-order range and its fees, is read from the gateway itself.
NO_COLOR
When set to any value, icp-cli prints its output without colors, following the NO_COLOR convention. Colors are also turned off when output is not a terminal.
Telemetry Variables
Any of these turns off telemetry:
| Variable | Effect |
|---|---|
ICP_TELEMETRY_DISABLED | Disables telemetry when set to any value |
DO_NOT_TRACK | Cross-tool standard; disables telemetry when set to any value |
CI | Set by most CI providers; telemetry is disabled automatically |
Docker Variables
These apply to containerized networks, including every local network on Windows.
DOCKER_HOST
The address of the Docker daemon, e.g. unix:///var/run/docker.sock or tcp://<ip>:<port>. When unset, icp-cli uses \\.\pipe\docker_engine on Windows. On macOS and Linux it uses /var/run/docker.sock if it exists, and otherwise asks docker context inspect for the current context’s endpoint.
ICP_CLI_DOCKER_WSL2_DISTRO
On Windows, the name of the WSL2 distribution running dockerd, for setups without Docker Desktop. icp-cli uses it to translate the paths it mounts into the container. See Manual dockerd in WSL2.
Windows-Specific Variables
ICP_CLI_BASH_PATH
Path to the bash executable on Windows.
icp-cli uses bash to run build scripts. On Windows, it searches for bash in common locations (Git Bash, MSYS2). If bash is not found automatically, set this variable:
$env:ICP_CLI_BASH_PATH = "C:\Program Files\Git\bin\bash.exe"Common bash locations on Windows:
- Git Bash:
C:\Program Files\Git\bin\bash.exe - MSYS2:
C:\msys64\usr\bin\bash.exe
Canister Runtime Environment Variables
These variables are stored in canister settings and accessible to canister code at runtime. They are distinct from the build-time and CLI configuration variables above.
Automatic Variables
PUBLIC_CANISTER_ID:<canister-name>
During deployment, icp-cli automatically creates canister environment variables containing the canister IDs of all canisters in the current environment.
| Property | Value |
|---|---|
| Format | PUBLIC_CANISTER_ID:<name> |
| Value | Canister principal (text) |
| When Set | Automatically during icp deploy |
Example:
For an environment with canisters backend and frontend:
PUBLIC_CANISTER_ID:backend = bkyz2-fmaaa-aaaaa-qaaaq-caiPUBLIC_CANISTER_ID:frontend = bd3sg-teaaa-aaaaa-qaaba-caiPurpose: Enables canisters to discover other canisters in the same environment without hardcoding IDs. This is especially important for:
- Frontend canisters calling backend canisters
- Multi-canister architectures with service dependencies
- Environment-agnostic deployments (same code works in local, staging, production)
IC_ROOT_KEY
The asset canister automatically includes the network’s root key in the ic_env cookie. This is not set by icp-cli during deployment — the asset canister provides it directly based on the network it’s running on.
| Property | Value |
|---|---|
| Cookie key | ic_root_key (lowercase) |
| Cookie value | Hex-encoded root key |
| When Set | By the asset canister at request time |
Purpose: The root key is required by the IC agent to verify response signatures. By providing it via the cookie, frontends work consistently across local networks and mainnet without code changes.
How frontends access these: Use @icp-sdk/core/agent/canister-env to read the ic_env cookie. The library parses the hex-encoded root key and returns it as Uint8Array:
import { getCanisterEnv } from "@icp-sdk/core/agent/canister-env";
interface CanisterEnv { "PUBLIC_CANISTER_ID:backend": string; IC_ROOT_KEY: Uint8Array; // Converted from hex by the library}
const env = getCanisterEnv<CanisterEnv>();const backendId = env["PUBLIC_CANISTER_ID:backend"];const rootKey = env.IC_ROOT_KEY; // Ready for agent's rootKey optionSee Canister Discovery for detailed usage patterns.
Custom Variables
Define custom canister environment variables in canister settings:
canisters: - name: backend settings: environment_variables: API_ENDPOINT: "https://api.example.com" DEBUG: "false"A value can also be read from a file, relative to the canister’s directory:
canisters: - name: backend settings: environment_variables: API_KEY: path: ./secrets/api-keyOverride per environment:
environments: - name: production network: ic canisters: [backend] settings: backend: environment_variables: API_ENDPOINT: "https://api.prod.example.com"See Canister Settings Reference for full configuration options.
See Also
- Canister Discovery — How canisters discover each other
- Local Development — Frontend development workflow
- Canister Settings Reference — Full settings documentation
- Managing Identities — Identity storage paths and directory contents
- Project Model — Project directory structure (
.icp/) and what’s safe to delete