Write
ICP supports a wide range of applications and architecture types, ranging from a single canister to complex, multi-canister projects and everything in between.
ICP accepts and executes canister code in the WebAssembly (Wasm) binary format. Usually, developers write code in a higher-level language and then compile the code into a Wasm binary that can be installed into a canister.
You can begin writing and structuring your application using one of two primary workflows:
Standard workflow: The developer writes an application's code and deploys it to ICP as one or more canisters.
Framework-based workflow: An external framework is used to help facilitate creating and deploying canisters.
Standard workflow
Choosing the programming language for the backend
The backend stores the application’s data and contains the core logic. Several languages are supported, such as:
Motoko: Supported by DFINITY. Motoko is production-ready and was specifically designed to leverage the actor-based programming model of ICP. It is a high-level language with a garbage collector and syntax that is similar to TypeScript. Examples of production canisters that use Motoko include ICDex and CycleOps. Learn more about using Motoko.
Rust: Supported by DFINITY. Currently, Rust is the language with the most production coverage for ICP applications. All system canisters, such as the DAO governing ICP, the ICP ledger, and the Bitcoin and Ethereum integration canisters, are written in Rust. This language gives the developer full control over all aspects of the canister, from performance to memory management. The only disadvantage of Rust is that it is lower-level compared to other languages and requires more expert programming skills to write safe and secure code. Learn more about using Rust.
TypeScript (beta): Supported by Demergent Labs under the name Azle. It is in beta. Please check the Azle website for more information.
Python (beta): Supported by Demergent Labs under the name Kybra. It is in beta. Please check the Kybra website for more information.
Choosing a web framework for the frontend
The HTTP Gateway protocol of ICP allows browsers to load web assets, such as JS, HTML, and CSS, from a canister via HTTP. This means that web assets can be stored fully onchain.
Svelte, React, and Vue have been used successfully in production. dfx v0.17.0
and newer can be used to generate project templates that include one of these frameworks.
Using a frontend stored off-chain or having no frontend at all are also valid options for applications. Learn more.
Framework-based workflow
Juno
Juno is a community project that is tailored for Web2 developers. It takes care of hosting code and data in canisters such that developers can write Web3 applications using familiar Web2 concepts and patterns. For more details, refer to the official Juno documentation.
Bitfinity EVM
Bitfinity EVM is tailored for Solidity developers. It runs an instance of the Ethereum virtual machine on ICP and enables developers to upload and execute canisters written in Solidity. For more details, refer to the official Bitfinity documentation.
Creating projects
Default project architecture
The backend
canister stores the dapp's functions and core logic.
The frontend
canister stores the app's frontend assets, including files such as HTML, CSS, JavaScript, React, images, and videos.

Using a sample project
You can obtain sample or boilerplate projects from sources such as ICP Ninja or the sample repository. Confirm that the project's root directory contains a dfx.json
file that defines the project's canisters.
ICP Ninja provides several sample project templates that can be opened, edited, and deployed directly from your web browser, while the sample repository provides examples for specific use cases and workflows such as token transfers and the Bitcoin integration.
Creating a new project with dfx
Before writing canister code, you need to create a project by running the command:
dfx new PROJECT_NAME --type=motoko
cd PROJECT_NAME
Options for the --type
flag are motoko
, rust
, azle
, and kybra
. Using Rust, Azle, or Kybra may require additional dependencies to be installed if you have not developed with those languages in your environment before. View their corresponding documentation for more information.
dfx.json
Regardless whether you are using a sample project or have created a new project, your project directory should contain a file called dfx.json
. This file is used to configure your project's settings. It includes the project's canister definitions, such as the canister's type, source code file, and dependencies.
{
"canisters": {
"PROJECT_NAME_backend": { // Backend canister name
"main": "src/PROJECT_NAME_backend/main.mo", // Backend canister source code
"type": "motoko" // Canister language
},
"PROJECT_NAME_frontend": { // Frontend canister name
"dependencies": [
"PROJECT_NAME_backend"
],
"source": [
"src/PROJECT_NAME_frontend/dist" // Frontend canister source code
],
"type": "assets", // All frontend canisters will have type 'assets' regardless of the frontend framework used
"workspace": "PROJECT_NAME_frontend"
}
},
"defaults": {
"build": {
"args": "",
"packtool": ""
}
},
"output_env_file": ".env",
"version": 1
}