Typescript-native tooling & deployments for the Internet Computer. A task runner like hardhat.
npm i -S @ice.ts/runner @ice.ts/canisters-
Npm install canister: Install & distribute canisters via npm, leverage the ecosystem of node.js in your tasks
-
Web2-style DX: No global dependencies. Just
npm installand run. Everything stays local to the project. -
Convenient APIs: Access to users & replica inside tasks via
ctx. Access dependencies insideinstallArgs(). -
Type-safe: No manual candid strings. Catch errors in your editor with full autocomplete for canister methods.
-
Composable: Easily combine multiple project setups without conflicts. Just import like normally.
-
Simple yet Extensible: A small but powerful API-surface. Easy to learn, yet fully programmable for more advanced use cases.
For full documentation, visit ice-ts.github.io/docs
Clone this repo to try it out quickly github.com/MioQuispe/ice-demo
npm i -S @ice.ts/runner @ice.ts/canistersCreate an ice.config.ts file. This is the entry point for your environment.
import { Ice, PICReplica, Ids } from '@ice.ts/runner';
export default Ice(async () => ({
network: 'local',
replica: new PICReplica({ port: 8080 }),
users: {
// Optional, use an existing identity:
default: await Ids.fromDfx("default"),
// Or:
// default: await Ids.fromPem("....")
}
}));Export your canister definitions using the builder API.
import { canister } from '@ice.ts/runner';
export const backend = canister.motoko({
src: 'canisters/backend/main.mo',
}).make();Ice automatically generates lifecycle tasks (create, build, bindings, install...) for your exported canisters.
# Deploy a specific canister
npx ice run backend:deploy
# Or deploy everything
npx iceTasks are the main building block of Ice. They are composable, type-safe and can depend on other tasks.
In this example, Ice ensures the ledger is deployed before running the minting logic.
import { task } from "@ice.ts/runner";
export const mint_tokens = task("Mint tokens to admin")
.deps({ ledger }) // Declare dependency
.run(async ({ ctx, deps }) => {
// deps.ledger is fully typed!
const { ledger } = deps;
const result = await ledger.actor.icrc1_transfer({
to: {
owner: Principal.from(ctx.users.admin.principal),
subaccount: []
},
amount: 100_000n,
// ... types are checked here
});
if ("Ok" in result) {
console.log(`Minted at block: ${result.Ok}`);
}
}).make();Define inter-canister dependencies easily.
import { canister } from "@ice.ts/runner";
// 1. The independent canister
export const ledger = canister.rust({ /* ... */ }).make();
// 2. The dependent canister
export const dex = canister.motoko({ src: "..." })
.deps({ ledger }).make(); // Ensures ledger exists before dex deploysStop wrangling manual Candid strings. Ice allows you to pass fully typed arguments based on your canister's interface.
import { canister } from "@ice.ts/runner";
export const backend = canister.motoko({ src: "..." })
.deps({ ledger })
.installArgs(async ({ ctx, deps }) => {
// TypeScript ensures you return the correct types
return [
ctx.users.admin.principal, // Arg 1: Admin
deps.ledger.canisterId // Arg 2: Ledger ID
];
})
.upgradeArgs(({ ctx, deps }) => [])
.make();Every task receives a shared context containing the environment state.
export const check_balance = task("Check Balance")
.run(async ({ ctx }) => {
// Access identities
console.log(ctx.users.default.principal);
console.log(ctx.users.default.accountId);
// Interact with the Replica
const status =
await ctx.replica.getCanisterStatus({
canisterId: "some-principal",
identity: ctx.users.default.identity
});
// Run other tasks dynamically
await ctx.runTask(some_other_task);
// and more...
}).make();Group tasks into namespaces for better organization.
import { scope } from "@ice.ts/runner";
import { NNSDapp, NNSGovernance } from "@ice.ts/canisters";
export const nns = scope({
dapp: NNSDapp().make(),
governance: NNSGovernance().make(),
}).make();Usage:
npx ice run nns:governance:deployUse popular ecosystem canisters with a single line of code. Ice provides ready-to-use builders.
import {
InternetIdentity,
ICRC1Ledger,
NNS,
NFID,
CyclesWallet
} from "@ice.ts/canisters";
// Just export them to use them
export const ii = InternetIdentity().make();
export const ledger = ICRC1Ledger().installArgs(() => [
// custom args, fully type-checked
]).make();
export const nfid = NFID().make();Install from the Visual Studio Marketplace.
- Inline CodeLens: Quickly execute tasks directly from your source code.
- Inline Results: See execution output without switching context.

