For AI agents: Documentation index at /llms.txt

Skip to content

Application Canisters

Application canisters are well-known canisters at the application layer of the Internet Computer that developers commonly integrate into their projects. Unlike system canisters (which govern the network) or protocol canisters (which provide platform infrastructure), application canisters implement higher-level functionality: hosting web frontends, governing apps via DAO, and running AI inference.

The asset canister hosts static web assets (HTML, CSS, JavaScript, images, and other files) directly onchain. It is the standard way to deploy a web frontend on ICP. Responses are certified by the subnet, allowing HTTP gateways to verify integrity before serving content to browsers.

Asset canisters are deployed per-project. There is no global asset canister ID: each project creates its own.

canisters:
- name: frontend
recipe:
type: "@dfinity/asset-canister@v2.1.0"
configuration:
dir: dist
build:
- npm install
- npm run build
  • recipe.type: identifies this as an asset canister deployment
  • dir: the build output directory whose contents are uploaded
  • build: commands run automatically by icp deploy before uploading

The asset canister exposes the following Candid methods:

Permission management:

MethodDescription
grant_permission(arg)Grant a principal a permission role (Prepare, Commit, or ManagePermissions)
revoke_permission(arg)Revoke a permission role from a principal
list_permitted(arg)Query principals with a given permission role
take_ownership()Caller becomes the sole authorized principal

Asset operations:

MethodDescription
store(arg)Upload a single asset in one call
create_batch()Begin a chunked upload batch
create_chunk(arg)Upload a chunk of a large asset
commit_batch(arg)Finalize a batch and make assets live
create_asset(arg)Create an asset entry without uploading content
set_asset_content(arg)Set or replace the content of an asset
unset_asset_content(arg)Remove content encoding from an asset
delete_asset(arg)Delete an asset
clear()Remove all assets from the canister

Asset queries:

MethodDescription
retrieve(key)Fetch raw asset bytes by key
get(arg)Fetch an asset with encoding and metadata
get_chunk(arg)Fetch a specific chunk of a large asset
list()List all uploaded assets with metadata
get_asset_properties(key)Query per-asset headers and aliasing settings
set_asset_properties(arg)Set per-asset headers and aliasing
certified_tree()Return the certificate tree for response verification

HTTP serving:

MethodDescription
http_request(req)Serve an HTTP request with certified response
http_request_streaming_callback(token)Stream large responses in chunks

Create .ic-assets.json5 in your dir directory (or public//static/ so your build copies it):

[
{
"match": "**/*",
"security_policy": "standard",
"headers": {
"Cache-Control": "public, max-age=0, must-revalidate"
},
"allow_raw_access": false
},
{
"match": "assets/**/*",
"headers": {
"Cache-Control": "public, max-age=31536000, immutable"
}
},
{
"match": "**/*",
"enable_aliasing": true
}
]
  • security_policy: "standard": applies the default Content Security Policy and security headers
  • allow_raw_access: false: disables serving assets on the uncertified raw.ic0.app domain
  • enable_aliasing: true: enables SPA fallback, serving index.html for unmatched paths

Use @icp-sdk/canisters (>= 3.5.0) to upload assets from code:

import { AssetManager } from "@icp-sdk/canisters/assets";
import { HttpAgent } from "@icp-sdk/core/agent";
const agent = await HttpAgent.create({
host: "https://ic0.app",
shouldFetchRootKey: false, // never fetch root key against mainnet
});
const assetManager = new AssetManager({
canisterId: "your-asset-canister-id",
agent,
});
// Upload a file (files >1.9MB are chunked automatically)
// fileBuffer: Uint8Array | ArrayBuffer | number[]: e.g. from fs.readFileSync, fetch, or the File API
await assetManager.store(fileBuffer, {
fileName: "photo.jpg",
contentType: "image/jpeg",
path: "/uploads",
});
// List all assets
const assets = await assetManager.list();
// Delete an asset
await assetManager.delete("/uploads/old-photo.jpg");

The asset canister Wasm version determines which features are available. Key versions:

  • 0.30.2+: required for the ic_env cookie (used by safeGetCanisterEnv() from @icp-sdk/core)
  • Omitting configuration.version in the recipe uses the latest version automatically

Downgrading the Wasm version may fail if the stable memory format changed between versions. If a downgrade is necessary, use icp deploy --mode reinstall (wipes all stored assets).

For version history, upgrade guidance, and deployment pitfalls, see the Asset canister guide.


When an SNS (Service Nervous System) is launched for an app, the SNS-W canister deploys a set of governance canisters on an SNS subnet. These canisters are created per-app: there is no single global SNS. To find the canister IDs for a specific SNS, look up the app on the ICP Dashboard.

CanisterPurpose
GovernanceProposal submission, voting, neuron management
LedgerSNS token transfers (ICRC-1 standard)
RootSole controller of all app canisters post-launch
SwapRuns the decentralization swap (ICP for SNS tokens)
IndexTransaction indexing for the SNS ledger
ArchiveHistorical transaction storage

The governance canister is the primary interface for SNS operations:

MethodDescription
manage_neuronCreate, configure, or vote with a neuron
get_neuronQuery a neuron’s state and voting power
list_neuronsList neurons for a principal
get_proposalQuery a proposal
list_proposalsList proposals with filtering
get_nervous_system_parametersQuery the current governance parameters
get_metadataQuery the SNS name, description, and logo

The SNS ledger implements ICRC-1, ICRC-2, and ICRC-3. The key methods are the same as any ICRC-1 ledger:

MethodDescription
icrc1_transferTransfer SNS tokens
icrc1_balance_ofQuery an account balance
icrc1_total_supplyQuery the total token supply
icrc2_approveApprove a spender
icrc2_transfer_fromTransfer on behalf of an approver
icrc3_get_blocksQuery transaction history (ICRC-3 transaction log)

For ICRC interface details, see Digital Asset Standards.

After an SNS is launched, call the list_sns_canisters method on the Root canister to retrieve the IDs of all canisters in the set:

Terminal window
icp canister call <sns_root_id> list_sns_canisters '()' -e ic
# Returns: record { root: principal; swap: principal; ledger: principal; index: principal; governance: principal; dapps: vec principal; archives: vec principal }

For SNS launch configuration and governance setup, see Launching an SNS.


The LLM canister provides onchain AI inference using large language models, enabling canisters to generate text, run chat completions, and build AI agents without external API keys.

FieldValue
Canister IDw36hm-eqaaa-aaaal-qr76a-cai
Candid interfacellm-canister-ollama.did
ModelIdentifier
Llama 3.1 8BLlama3_1_8B

Add the ic-llm crate to your project:

[dependencies]
ic-cdk = "0.17"
ic-llm = "1.1.0"

Single-turn prompt:

use ic_cdk::update;
use ic_llm::{ChatMessage, Model};
#[update]
async fn prompt(prompt_str: String) -> String {
ic_llm::prompt(Model::Llama3_1_8B, prompt_str).await
}

Multi-turn chat:

use ic_cdk::update;
use ic_llm::{ChatMessage, Model};
#[update]
async fn chat(messages: Vec<ChatMessage>) -> String {
let response = ic_llm::chat(Model::Llama3_1_8B)
.with_messages(messages)
.send()
.await;
response.message.content.unwrap_or_default()
}

Add the llm package to your mops.toml:

[dependencies]
llm = "2.1.0"

Single-turn prompt:

import LLM "mo:llm";
persistent actor {
public func prompt(prompt : Text) : async Text {
await LLM.prompt(#Llama3_1_8B, prompt);
};
};

Multi-turn chat:

import LLM "mo:llm";
persistent actor {
public func chat(messages : [LLM.ChatMessage]) : async Text {
let response = await LLM.chat(#Llama3_1_8B).withMessages(messages).send();
switch (response.message.content) {
case (?text) text;
case null "";
};
};
};

The LLM canister requires an Ollama server for local testing:

Terminal window
# Start the Ollama server
ollama serve
# Pull the model (one-time download, ~4 GiB)
ollama pull llama3.1:8b

icp-cli does not yet have an equivalent of dfx’s "type": "custom" / "remote" canister configuration for pointing a local replica at the Ollama-backed LLM Wasm. To test the LLM canister locally, use the example project from dfinity/examples which includes the dfx.json configuration needed for this setup.

For a complete onchain AI guide, see Onchain AI.


CanisterCanister IDPurpose
Asset canisterPer-projectStatic web asset hosting with HTTP certification
SNS governancePer-appDAO governance for a specific app
SNS ledgerPer-appICRC-1/ICRC-2/ICRC-3 token ledger for a specific SNS
SNS rootPer-appController of all app canisters in the SNS set
SNS swapPer-appDecentralization swap (ICP for SNS tokens)
LLMw36hm-eqaaa-aaaal-qr76a-caiOnchain AI inference (Llama 3.1 8B)