Hello, world!
This guide shows how to get started developing on ICP quickly by deploying your first 'Hello, world!' smart contract.
Choosing a developer environment
To deploy a simple 'Hello, world!' smart contract, you can use a variety of developer environments, such as:
Native installation of tools on Linux, Mac, or Windows (using WSL) systems.
Cloud-based environments such as Gitpod or GitHub Codespaces.
Each developer environment uses dfx
, a command-line tool that is used for developing and deploying smart contracts on ICP.
Which environment should you choose?
Native installation requires downloading and installing dfx
and its dependencies manually. Using a native installation of dfx
is better suited for large projects.
Gitpod and GitHub Codespaces are cloud-based developer environments that can be accessed via a web browser. The Gitpod and GitHub Codespace examples linked on this page come with the necessary tools and dependencies pre-installed. These environments use limited cloud resources and may not scale well for building large, complex projects.
- Gitpod
- GitHub Codespaces
- Native installation
Install dfx
Download and install the latest version of dfx. dfx
is a CLI tool used for developing and deploying ICP smart contracts:
sh -ci "$(curl -fsSL https://internetcomputer.org/install.sh)"
Install Node.js
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.3/install.sh | bash
nvm install 18
Start the local replica
dfx start
This command starts a local instance of the ICP replica using a single node testnet. The output will return a dashboard URL that can be used to view information about the local replica:
Running dfx start for version 0.15.2
Initialized replica.
Dashboard: http://localhost:35375/_/dashboard
While dfx start
is running, you will not be able to run other commands in the terminal window. You can open another window, or start dfx
in the background with the dfx start --clean --background
flag.
Create a new project
Use dfx new <project_name>
to create a new project:
dfx new hello
You will be prompted to select the language that your backend canister will use:
? Select a backend language: ›
❯ Motoko
Rust
TypeScript (Azle)
Python (Kybra)
dfx
versions v0.17.0
and newer support this dfx new
interactive prompt. Learn more about dfx v0.17.0
.
Then, select a frontend framework for your frontend canister, or select 'No frontend canister':
? Select a frontend framework: ›
❯ SvelteKit
React
Vue
Vanilla JS
No JS template
No frontend canister
Lastly, you can include extra features to be added to your project:
? Add extra features (space to select, enter to confirm) ›
⬚ Internet Identity
⬚ Bitcoin (Regtest)
⬚ Frontend tests
Smart contract code
The default Hello, world!
dapp uses dfx
's default template which contains two canisters, hello_backend
and hello_frontend
.
The hello_frontend
canister is used to store the dapp's frontend assets. This includes files such as HTML, CSS, JavaScript, React, images, and videos.
The hello_backend
canister is used to store the dapp's functions and core logic.
It is important to note that a canister is capable of storing both the frontend assets and backend code. However, dfx
by default uses a project template with a dedicated canister for the frontend since this allows any language to be used for the backend canister without needing to use a library for the assets storage API.
- Motoko
- Rust
- TypeScript
- Python
Motoko is an actor-based language and it represents the smart contract as an actor with various methods that the users and other smart contract can call.
This hello world actor has a single function called greet. It is marked as query because it doesn't modify the state of the actor. The function accepts a name as input and returns a greetings text.
actor {
public query func greet(name : Text) : async Text {
return "Hello, " # name # "!";
};
};
This Rust smart contract has a single function called greet. It is marked as query because it doesn't modify the state of the canister.
The function accepts a name as input and returns a greetings text.
#[ic_cdk::query]
fn greet(name: String) -> String {
format!("Hello, {}!", name)
}
TypeScript canisters can be written using the Azle canister development kit. For Azle projects, you will need to install the Azle dfx
extension:
npx azle install-dfx-extension
The default canister code for Azle projects contains the following code:
import { IDL, query, update } from 'azle';
export default class {
message: string = 'Hello world!';
@query([], IDL.Text)
getMessage(): string {
return this.message;
}
@update([IDL.Text])
setMessage(message: string): void {
this.message = message;
}
}
Create the project directory and file structure:
from kybra import query
@query
def greet(name: str) -> str:
return f"Hello, {name}!"
Deploy to the local environment
Deploy the project's canisters locally:
dfx deploy
This command performs several functions in the background:
It sets up a special
cycle-wallet
smart contract for storing cycles. All operations require payments in cycles. In your local testnet, this wallet comes prefilled with cycles.It builds the smart contracts defined in the
dfx.json
file into Wasm binaries.It creates smart contracts on the local testnet and saves their addresses in the file
./.dfx/local/canister_ids.json
.It installs the Wasm binaries onto the new smart contracts.
Call the smart contracts from the CLI
- Motoko
- Rust
- TypeScript
- Python
dfx canister call hello_backend greet world
Output:
("Hello, world!")
dfx canister call hello_backend greet world
Output:
("Hello, world!")
dfx canister call hello_backend getMessage
Output:
("Hello world!")
dfx canister call hello_backend greet world
Output:
("Hello, world!")
This call performs several functions in the background:
First, it looks up the smart contract's address (known as the canister id) using the smart contract's name
hello_backend
in the file./.dfx/local/canister_ids.json
.Then, it looks up the smart contract's interface in the file
src/declarations/hello_backend/hello_backend.did
.It looks up the signature of function greet in the interface.
It constructs a message for the smart contract's
greet
endpoint with the givenname
text as an argument.It signs the message with the private key of the developer account.
It sends the message to the local testnet (replica).
Once the message has been executed, the result was decoded using the interface file and printed to the terminal window.
Alternatively, you can interact with the smart contract via the web browser if a frontend smart contract has been deployed. Learn more about using the frontend smart contract in the web browser