For AI agents: Documentation index at /llms.txt

Skip to content

Canister Settings

Every canister has settings that control its resource allocation, access control, and runtime behavior. Only a controller of the canister can read or modify these settings.

This guide covers how to view, configure, and update canister settings using icp-cli, icp.yaml, and programmatic calls to the management canister.

Viewing settings

Use icp canister settings show to display a canister’s current settings:

Terminal window
icp canister settings show backend

For a broader view that includes settings alongside status, cycle balance, and module hash:

Terminal window
icp canister status backend

Settings reference

Controllers

A list of principals that can manage the canister. Controllers can install code, upgrade the canister, change settings, stop/start the canister, and delete it.

  • Default: The identity that created the canister.
  • Maximum: 10 controllers.
  • A canister with no controllers is immutable (sometimes called “blackholed”).

Controllers are managed through the CLI rather than icp.yaml:

Terminal window
# Add a controller
icp canister settings update backend --add-controller PRINCIPAL
# Remove a controller
icp canister settings update backend --remove-controller PRINCIPAL
# Replace the entire controller list
icp canister settings update backend --set-controller PRINCIPAL_1 --set-controller PRINCIPAL_2

Removing yourself from the controller list or using --set-controller without including yourself will cause you to permanently lose control of the canister.

Compute allocation

Guarantees a percentage of an execution core for the canister.

PropertyValue
TypeInteger (0—100)
Default0 (best effort)
icp.yaml keycompute_allocation
settings:
compute_allocation: 10

A value of 50 means the canister gets 50% of an execution core and is scheduled at least every other round. A value of 100 means the canister runs every round.

Compute allocation incurs a rental fee based on time and allocation percentage, regardless of whether the canister actually executes. This increases idle cycle consumption. See cycles costs for pricing details.

Memory allocation

Pre-allocates a fixed amount of memory for the canister.

PropertyValue
TypeInteger or string with suffix
Default0 (dynamic allocation)
icp.yaml keymemory_allocation
settings:
memory_allocation: 4gib

Supported suffixes: kb (1,000), kib (1,024), mb (1,000,000), mib (1,048,576), gb (1,000,000,000), gib (1,073,741,824). Decimals are supported (e.g., 2.5gib).

When set, the canister draws new Wasm and stable memory from the pre-allocated pool. If usage exceeds the allocation, additional memory is allocated on demand and may fail if the subnet is at capacity.

Like compute allocation, memory allocation incurs a rental fee based on time and allocated amount, regardless of actual usage. See cycles costs for pricing.

Freezing threshold

The minimum time the canister should be able to survive on its current cycle balance. Survival is estimated based on the canister’s memory usage and the subnet’s current storage cost: a canister with large stable memory freezes sooner than execution rate alone would suggest. If the balance drops below what is needed to sustain this duration, the canister freezes.

PropertyValue
TypeInteger or string with duration suffix
Default2_592_000 (30 days)
icp.yaml keyfreezing_threshold
settings:
freezing_threshold: 90d

Duration suffixes: s (seconds), m (minutes), h (hours), d (days), w (weeks). A bare number is treated as seconds.

A frozen canister does not execute messages. It only pays for rented resources (compute allocation, memory allocation, and memory usage). If cycles are fully exhausted and the threshold expires, the canister is uninstalled: its code and data are deleted, and only metadata (canister ID, controllers, settings) is retained.

For more on cycle management, see cycles management.

Reserved cycles limit

Caps the secondary “reserved cycles” balance used for future resource payments. When a canister allocates storage on a subnet above 750 GiB usage, cycles are moved from the main balance into a reserved balance. This setting limits that reserved balance.

PropertyValue
TypeInteger or string with suffix
Default5_000_000_000_000 (5T)
icp.yaml keyreserved_cycles_limit
settings:
reserved_cycles_limit: 5t

Cycles suffixes: k (thousand), m (million), b (billion), t (trillion). Set to 0 to disable resource reservation entirely (prevents memory allocation on subnets above 750 GiB).

Wasm memory limit

A soft limit on the canister’s 32-bit Wasm heap size. Protects against reaching the 4 GiB hard limit, which would make the canister unrecoverable.

PropertyValue
TypeInteger or string with suffix
Default3_221_225_472 (3 GiB)
icp.yaml keywasm_memory_limit
settings:
wasm_memory_limit: 3gib

Enforcement varies by message type:

  • Update messages: Enforced up to the first await point. After the first await, execution continues in a response callback where the limit is not enforced.
  • Canister init and post-upgrade: Enforced. Installation or upgrade fails if Wasm memory exceeds the limit.
  • Queries: Not enforced (state changes are not preserved).
  • Response callbacks and pre-upgrade: Not enforced.
  • Heartbeats and timers: Currently not enforced.

Wasm memory threshold

When the canister’s remaining Wasm memory falls below this value, the system triggers the on_low_wasm_memory hook. Use this to take corrective action before memory runs out.

PropertyValue
TypeInteger or string with suffix
DefaultNone
icp.yaml keywasm_memory_threshold
settings:
wasm_memory_threshold: 512mib

Log visibility

Controls who can fetch canister logs through the fetch_canister_logs management canister endpoint.

PropertyValue
Typecontrollers, public, or allowed_viewers object
Defaultcontrollers
icp.yaml keylog_visibility
# Only controllers
settings:
log_visibility: controllers
# Anyone
settings:
log_visibility: public
# Specific principals (e.g. a monitoring service or auditor identity)
settings:
log_visibility:
allowed_viewers:
- "<principal-of-monitoring-service>"
- "<principal-of-auditor>"

Log memory limit

Maximum memory for storing canister logs. Oldest logs are purged when usage exceeds this value.

PropertyValue
TypeInteger or string with suffix
Max2 MiB
Default4096 bytes
icp.yaml keylog_memory_limit
settings:
log_memory_limit: 2mib

Snapshot visibility

Controls who can list and read canister snapshots through the management canister.

PropertyValue
Typecontrollers, public, or allowed_viewers object
Defaultcontrollers
VariantMeaning
controllers (default)Only controllers can list and read snapshots
publicAnyone can list and read snapshots
allowed_viewersSpecific principals can list and read snapshots

Configuring snapshot_visibility via icp.yaml or CLI flags is not yet supported in icp-cli. Set it programmatically via the management canister: see Updating settings programmatically.

Environment variables

Key-value pairs accessible at runtime. Allow the same Wasm module to run with different configurations across environments.

PropertyValue
TypeObject (string keys, string values)
DefaultNone
icp.yaml keyenvironment_variables
settings:
environment_variables:
API_URL: "https://api.example.com"
DEBUG: "false"

Configuring settings in icp.yaml

Define default settings at the canister level in icp.yaml:

canisters:
- name: backend
settings:
compute_allocation: 5
memory_allocation: 2gib
freezing_threshold: 30d
reserved_cycles_limit: 5t
wasm_memory_limit: 3gib
wasm_memory_threshold: 512mib
log_visibility: controllers
log_memory_limit: 2mib
environment_variables:
ENV: "development"

After editing icp.yaml, apply the settings to a deployed canister:

Terminal window
icp canister settings sync backend

Environment-specific overrides

Use the environments section to override settings per deployment target:

canisters:
- name: backend
settings:
compute_allocation: 1
freezing_threshold: 7d
environments:
- name: production
network: mainnet
canisters: [backend]
settings:
backend:
compute_allocation: 20
freezing_threshold: 90d
environment_variables:
ENV: "production"

Environment-level settings merge with and override canister-level settings. In the example above, the production environment uses compute_allocation: 20 and freezing_threshold: 90d instead of the defaults, while all other settings remain unchanged.

Updating settings via CLI

Update individual settings directly without editing icp.yaml:

Terminal window
# Compute allocation
icp canister settings update backend --compute-allocation 10
# Freezing threshold
icp canister settings update backend --freezing-threshold 90d
# Wasm memory limit
icp canister settings update backend --wasm-memory-limit 3gib
# Log visibility
icp canister settings update backend --log-visibility public
# Multiple settings at once
icp canister settings update backend \
--compute-allocation 10 \
--freezing-threshold 90d \
--wasm-memory-limit 3gib

For mainnet canisters, add -e <env> where <env> is the name of your mainnet environment in icp.yaml (commonly ic or production):

Terminal window
icp canister settings update backend -e ic --freezing-threshold 90d

Additional flags: --reserved-cycles-limit, --wasm-memory-threshold, --log-memory-limit, --add-environment-variable. Run icp canister settings update --help for the full list.

For the full list of CLI flags, see the icp-cli reference.

Updating settings programmatically

Canisters can update their own settings or the settings of canisters they control by calling the management canister’s update_settings endpoint.

import Principal "mo:core/Principal";
persistent actor Self {
// All fields are optional: only include those you want to change
type CanisterSettings = {
controllers : ?[Principal];
compute_allocation : ?Nat;
memory_allocation : ?Nat;
freezing_threshold : ?Nat;
reserved_cycles_limit : ?Nat;
log_visibility : ?{
#controllers;
#public;
#allowed_viewers : [Principal];
};
snapshot_visibility : ?{
#controllers;
#public;
#allowed_viewers : [Principal];
}; // controls who can list/read canister snapshots
wasm_memory_limit : ?Nat;
wasm_memory_threshold : ?Nat;
environment_variables : ?[{name : Text; value : Text}];
};
let ic = actor ("aaaaa-aa") : actor {
update_settings : shared {
canister_id : Principal;
settings : CanisterSettings;
} -> async ();
};
public func setFreezingThreshold(
canisterId : Principal,
seconds : Nat,
) : async () {
await ic.update_settings({
canister_id = canisterId;
settings = {
controllers = null;
compute_allocation = null;
memory_allocation = null;
freezing_threshold = ?seconds;
reserved_cycles_limit = null;
log_visibility = null;
snapshot_visibility = null;
wasm_memory_limit = null;
wasm_memory_threshold = null;
environment_variables = null;
};
});
};
}

Only a controller of the target canister can call update_settings. Set fields to null/None to leave them unchanged.

For the full management canister interface, see the management canister reference.

Common control models

How you configure controllers depends on the trust model for your canister:

Developer or team: One or more developer identities as controllers. Suitable for development and early-stage projects. Add a backup controller to prevent lockout if a key is lost.

Multi-signature: A multi-sig canister (such as the Threshold canister) controls the application canister. Administrative actions require multiple signers, preventing any single developer from making unilateral changes.

DAO-governed: The canister is controlled by a decentralized autonomous organization. On ICP, the most common pattern is handing control to a Service Nervous System (SNS), where upgrades and settings changes are decided by token-holder vote.

Immutable (blackholed): The canister has no controllers. No one can upgrade, change settings, or delete it. This is the strongest trust guarantee but makes bug fixes impossible.

Next steps