Skip to main content

Deploy overview


After you have built a canister, you can deploy it to:

  • The local canister execution environment on your machine where   no tokens or cycles are required
  • The playground on the mainnet, a testnet-like sandbox   environment. No tokens or cycles are required to deploy and run your canister   smart contract, but it will be removed after 20 minutes.
  • Mainnet for production use. This deployment method will require   cycles.

This page will guide you through all 3 deployment methods.


Most blockchain networks have separate testnets that allow smart contract developers to test their projects in a production-like environment at significantly lower cost than on the mainnet. Because the execution of canisters is fairly cheap on ICP, and ICP smart contracts can be upgraded once deployed, there is no testnet for ICP. Developers are encouraged to test their canister smart contracts locally or directly on the mainnet.

However, the playground sandbox environment can be used as a testnet-like deployment option. It does not require cycles or tokens to deploy and operate a canister, but it has limitations, and canisters will be automatically removed after 20 minutes.

For the majority of developers, the playground option can be used for most workflows, as will be demonstrated below. For more advanced developers and use cases, there are two possible options for a testnet-like environment:

  • Private testnets: Developers can deploy their own custom instance of the playground on the mainnet, allowing for full customization of the playground's parameters.

  • Synthetic testnets: The dfx named network feature can be used to create custom local networks that can be used for local testing segmented from other projects deployed locally.


Before you deploy your canister, open a new terminal and navigate to your project directory. Verify the canisters you'd like to deploy are configured in the project's dfx.json file.

Need to create a project? Check out the Hello, world! sample project.

An example dfx.json file can be found in the default project template document.

Local deployment

Start the local canister execution environment:

dfx start

To deploy locally, use the command:

dfx deploy

Deploying to playground

To deploy to the playground, use the command:

dfx deploy --playground

Deploying to mainnet

To deploy to the mainnet, use the command:

dfx deploy --network ic

Deploying canisters to the mainnet will cost cycles. Learn more about cycles and how to acquire them.

Deploying specific canisters

The deploy command deploys all canisters configured in your dfx.json file. To deploy just one canister, specify the canister's name:

dfx deploy hello_backend ## Deploy locally
dfx deploy hello_backend --playground ## Deploy to the playground
dfx deploy hello_backend --network ic ## Deploy to the mainnet

Use a custom Motoko version with dfx deploy

To use a custom Motoko version with dfx deploy, export the following environment variable that indicates which Motoko base version you'd like dfx to use:

DFX_MOC_PATH="$(vessel bin)/moc" dfx deploy

Setting a canister's init arguments

You can set a canister's init arguments when the canister is deployed by passing the --argument flag in either the dfx install or dfx deploy commands:

dfx canister install <CANISTER_NAME> --argument "(arg in candid)"
dfx deploy <CANISTER_NAME> --argument "(arg in candid)"

If several arguments should be used, an argument file can be defined with the --argument-file flag instead:

dfx deploy <CANISTER_NAME> --argument-file file.txt

Alternatively, init arguments can be set in dfx.json in dfx versions v0.17.0 and newer:

"canisters": {
    "hello_backend": {
      "candid": "src/hello_backend/hello_backend.did",
      "package": "hello_backend",
      "type": "rust",
      "init_arg": "(arg in candid)"

If an init argument is set in dfx.json and set with the CLI command, the argument set in the CLI command is used.

Setting tasks to execute once a canister has been deployed

For certain workflows, it may be important to have a canister execute a task or call as soon as the canister is deployed or started. For this workflow, using timers can be useful.

Here is an example:

This example uses a global timer that gets called immediately after the canister starts:

system func timer(setGlobalTimer : Nat64 -> ()) : async () {
  let next = Nat64.fromIntWrap( + 20_000_000_000;
  setGlobalTimer(next); // absolute time in nanoseconds

You can learn more in the Motoko Timer library documentation.

Next steps