What are canisters?
The smart contracts running on ICP are a powerful evolution of traditional smart contracts. ICP smart contracts are called canisters and are computational units that combine both code and data. Canisters can contain any arbitrary code or data, from serving web pages to creating a secure messaging app or implementing a decentralized token exchange.

Canisters have special properties that allow developers to build scalable Web3 services. To better understand these properties, one has to consider canisters from different perspectives to form a complete picture of their capabilities.
The Internet Computer Protocol (ICP) accepts and executes canisters in the WebAssembly (Wasm) binary format. In theory, developers could write valid canisters directly in the Wasm bytecode. Since that would be too tedious and time-consuming, the standard practice is to write canister code in a higher-level language, such as JavaScript/TypeScript, Motoko, Python, or Rust, then compile it into Wasm.
The primary developer tool in the ICP ecosystem is the IC SDK, which includes dfx
.
dfx
is a command line multi-tool that assists the developer throughout the entire development process, starting from the generation of developer keys and setting up a new project to compiling, deploying, and managing canisters.

By default, dfx
generates a project structure consisting of two canisters: the frontend canister and the backend canister.
The frontend canister contains web assets such as JavaScript, HTML, CSS, and images that are served to the browser.
The actual program logic of the application is defined in the backend canister.
The configuration with a frontend and a backend canister is just a convention. It is possible to write a single canister that contains both the program logic and hosts the web assets.
Since canisters can be written in different languages, it is important that they all agree on the binary format in which they accept their arguments and return results. This common format allows users and canisters to call other canisters regardless of the language they were written in. In traditional programming, this concept is known as Application Binary Interface (ABI). ICP has its own ABI language called Candid, which is similar to JSON or Protobuf, but tailored for ICP.
During the build process, dfx
uses the backend ABI to automatically generate JavaScript boilerplate code for the frontend.
Under the hood, the boilerplate code uses a library called the ICP JavaScript agent to encode Candid values and make HTTP requests from the browser to the backend canister.
This is similar to web3.js
in Ethereum.
The Wasm standard defines only the instructions and the memory of the Wasm virtual machine; how a Wasm program interacts with other programs and users is left up to the host that embeds the virtual machine. ICP as a Wasm host provides a set of functions that Wasm code can use to read the incoming arguments, call the system and other canisters, and return results. Collectively these functions are referred to as the System API. Developers are not intended to use the System API directly because that would be too low-level and error-prone. Instead, developers should use language-specific Canister Development Kit (CDK) libraries that are high-level wrappers around the System API.
Canister lifecycle
Write
The 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 deployed into a canister.
Learn more about writing canister code.
Create
A developer can create an empty canister on ICP by using dfx canister create
in the command line or the NNS frontend dapp in the browser.
The developer can specify the initial canister settings and choose the target subnet.
Once the canister is created, the developer receives its canister ID and becomes the controller of the canister.
Learn more about creating canisters.

Compile
Once an empty canister has been created, the canister's code must be compiled into a Wasm binary using dfx build
.
Learn more about compiling code into Wasm.
Install
The next step after writing the code, creating a canister, and compiling the code is to install the code into the canister.
This can be done by calling the install_code
endpoint of the management canister and passing the canister ID and the Wasm binary to it.
The dfx canister install
command is used for making this call.

Deploy
Once a canister has an installed Wasm binary, it can be deployed to the local, playground, or mainnet environments with dfx deploy
.
Learn more about deploying canisters.
Call
After deployment, the canister accepts and processes messages (calls) from users and other canisters.
Only the public endpoints of the canister can be called.
These endpoints correspond to exported Wasm functions that are annotated with canister_update
or canister_query
in their names.

Maintain
Certain system operations that change the state of the canister can be performed only by the controllers of the canister. The most important operation is upgrading the canister by installing a different Wasm binary. In the initial stages of development, the canister is usually controlled by its developer, which allows the developer to iterate quickly. As the canister becomes mature and production ready, the control over it could move to a DAO in order to make the canister secure and trustworthy. Learn more about different types of controllers.

Since ICP uses a reverse gas model, the canister pays for its execution, storage, and other operations with cycles. This means that controllers and/or users of the canister have to ensure that the canister does not run out of cycles. If the canister runs out of cycles, it will be uninstalled by removing its Wasm binary and its storage.
If the canister is no longer used or needed, a controller of the canister can delete it. ICP guarantees that the canister ID will not be reused for another canister.