Skip to content
IC Reactor

@ic-reactor/cli

The IC Reactor CLI (@ic-reactor/cli) helps you generate typed reactor files, optional React hooks, and TypeScript declarations from your Candid files. It’s useful if you’re not using Vite or want more control over the generation process.

It uses the shared @ic-reactor/codegen pipeline, so its output stays aligned with the Vite plugin.

Requires Node.js 22.12.0 or later.

bash pnpm add -D @ic-reactor/cli

Initialize the configuration file (ic-reactor.json) in the current directory.

Terminal window
npx ic-reactor init

Options:

  • -y, --yes: Skip prompts and use defaults.
  • -o, --out-dir <path>: Output directory for generated files (default: src/declarations). Only applied together with -y; the interactive flow prompts for it instead.

init writes to the current directory and nowhere else. A config in a parent directory belongs to a different project and is never modified, so running init inside a monorepo package creates that package’s own config.

-y is fully non-interactive and safe to run with stdin closed in CI. When ic-reactor.json already exists in the current directory it is left exactly as it is; delete it, or run init without -y and confirm the overwrite, to reconfigure. Cancelling a prompt aborts before anything is written.

Regenerates hooks and declarations for all configured canisters. Run this whenever your .did files change.

Terminal window
npx ic-reactor generate

Options:

  • -c, --canister <name>: Generate only the canister whose key in canisters is <name>.
  • --clean: Remove generated output for canisters that are no longer configured.
  • --bindgen-only: Generate only the files under declarations/.

For each canister, the CLI writes into <outDir>/<canister>/:

  • declarations/<did-basename>.did copy
  • declarations/<did-basename>.d.ts TypeScript service types
  • declarations/<did-basename>.js IDL factory module
  • index.generated.ts managed reactor implementation, with optional typed hook exports
  • index.factories.generated.ts managed query and mutation factories, only for a canister that sets factories: true
  • index.ts user-facing entrypoint

Declaration filenames follow the .did file’s basename, not the canister name. After every run, declarations/ holds only the files that run generated. A file whose content has not changed is not rewritten, so regenerating from an unchanged .did and config leaves every file untouched.

If Prettier resolves from the directory holding ic-reactor.json, installed by that project or by a parent workspace, the CLI formats the .js, .d.ts, index.generated.ts, index.factories.generated.ts and the index.ts wrapper it writes with it and your Prettier config. Regenerating then leaves formatted, committed output unchanged. Without Prettier the declarations hold the Candid parser’s output followed by a newline.

Because every run brings the output of the canisters it generates up to date, the only output that can go stale is the directory of a canister that was renamed or removed from the config. --clean removes those, and only those: it leaves configured canisters (including the index.ts you own) alone, never deletes a directory holding no generated file, and is skipped for --canister <name> runs.

The CLI regenerates index.generated.ts on every run. It creates index.ts once, then preserves it unless the file is still the default wrapper or an older generated scaffold that can be migrated automatically.

Set target to choose the generated runtime:

  • react (default): generates the reactor plus bound React hooks
  • core: generates only the typed reactor exports with no React dependency

Use --bindgen-only when you only want the generated declaration files. In that mode, the CLI skips index.generated.ts, index.factories.generated.ts and index.ts entirely and leaves any existing reactor files untouched.

Set factories: true on a canister to also generate index.factories.generated.ts, with one object per method bound to the generated reactor: createQuery for a query method without arguments, createQueryFactory for one with arguments, and createMutation for an update or oneway method. Each is named after its method in camelCase with a Query or Mutation suffix, so get_message gives getMessageQuery.

{
"canisters": {
"backend": {
"name": "backend",
"didFile": "src/backend/backend.did",
"factories": true
}
}
}
import { getMessageQuery, setMessageMutation } from "./declarations/backend"
// In a component
function Message() {
const { data } = getMessageQuery.useQuery()
return <p>{data}</p>
}
// Anywhere, outside React included
async function saveMessage() {
await setMessageMutation.execute(["hello"])
}

The default index.ts wrapper re-exports the file. If you have edited your index.ts, the CLI leaves it alone and prints a warning until it re-exports the factories. Removing factories, or setting it to false, removes the file on the next run. It needs target: "react". See Query and Mutation Factories for the naming rule for any method name and how to customize a factory.

The ic-reactor.json file controls the CLI behavior.

{
"$schema": "https://raw.githubusercontent.com/B3Pay/ic-reactor/main/packages/cli/schema.json",
"outDir": "src/declarations",
"clientManagerPath": "../../clients",
"target": "react",
"canisters": {
"backend": {
"name": "backend",
"didFile": "src/backend/backend.did",
"canisterId": "rrkah-fqaaa-aaaaa-aaaaq-cai"
}
}
}

Set canisterId for any build that is not served from a local replica. It is written into index.generated.ts. Without it the generated reactor looks its id up in the ic_env cookie, which a ClientManager trusts only on a local replica unless it sets allowEnvConfig: true, so importing the generated module throws canisterId is required for "backend" in Node, during SSR and on a deployed origin. Leave it out only for local development where an ic_env cookie carries the id, such as the one the Vite plugin sets.

Key Type Description
outDir string Base output directory for generated files (required).
canisters Record<string, CanisterConfig> Canister configurations by key (required). --canister selects one by its key.
clientManagerPath string Path to a custom ClientManager instance (optional).
target "react" | "core" Default generated runtime target (optional).
Key Type Description
name string Canister name (required). It names the generated reactor, its hooks and the default output folder <outDir>/<name>, and it need not match the entry’s key in canisters.
didFile string Path to the .did file (required).
mode string Reactor class to generate: Reactor, DisplayReactor (default), CandidReactor, CandidDisplayReactor, MetadataDisplayReactor.
outDir string Override output directory for this canister.
clientManagerPath string Override client manager path.
target string Override generated runtime target.
canisterId string Canister ID written into index.generated.ts. Needed for any build not served from a local replica; see above.
factories boolean Also generate index.factories.generated.ts, a query or mutation object per method (default false). Needs target: "react"; see above.