| title | description |
|---|---|
Tutorial |
Step-by-step walkthrough of deploying a full-stack Motoko and React app on the Internet Computer. |
This tutorial walks through deploying a full-stack app on the Internet Computer, explaining each step along the way.
Already did the Quickstart? This tutorial covers the same steps with detailed explanations. The Quickstart used
--defineflags to skip the interactive prompts — here you'll see what those prompts are and what they mean.
A canister is your application running on the Internet Computer. It combines code and persistent state into a single unit — no servers to manage, no databases to configure. Your code runs on a decentralized network and persists automatically.
In this tutorial, you'll deploy two canisters:
- A backend canister (Motoko) — your application logic
- A frontend canister (React) — your web UI, also served from the blockchain
Required: Node.js (LTS) for the installation commands below.
Windows users: This tutorial requires WSL (for Motoko) and Docker Desktop (for local networks). Install both first, then run all commands inside WSL.
Install the required tools:
# icp-cli and ic-wasm (required)
npm install -g @icp-sdk/icp-cli @icp-sdk/ic-wasm
# Motoko toolchain (for Motoko projects)
npm install -g ic-mopsThis installs:
- icp-cli — the core CLI for building and deploying canisters
- ic-wasm — optimizes WebAssembly for the Internet Computer
- mops — Motoko package manager, which also installs the Motoko compiler
Alternative methods: See the Installation Guide for Homebrew, shell script, Rust setup, or other options.
Verify the tools are installed:
icp --version
ic-wasm --version
mops --versionicp new my-projectYou'll see three prompts:
1. Template selection — Choose hello-world for a full-stack app with backend and frontend.
2. Backend language — Choose motoko (or rust if you prefer).
3. Network type — Choose Default for native local networks. On Windows, Docker is always used regardless of this setting.
Tip: The Quickstart skipped these prompts using
--defineflags:icp new my-project --subfolder hello-world \ --define backend_type=motoko \ --define frontend_type=react \ --define network_type=Default
Templates are fetched from the icp-cli-templates repository by default. You can also create your own templates.
Enter the project directory:
cd my-projectYour project contains:
icp.yaml— Project configuration (canisters, networks, environments)backend/— Motoko source codefrontend/— React applicationREADME.md— Project-specific instructions
icp network start -dThis starts a local Internet Computer replica on your machine. The -d flag runs it in the background (detached) so you can continue using your terminal.
Verify the network is running:
icp network statusNote: For local development, icp-cli uses an anonymous identity by default. This identity is automatically funded with ICP and cycles on local networks, so you can deploy immediately without setting up a wallet. For mainnet deployment, you'll create a dedicated identity — see Deploying to Mainnet.
icp deployThis single command:
- Builds your Motoko code into WebAssembly (WASM)
- Builds your React frontend
- Creates canisters on the local network
- Installs your code into the canisters
After deployment, you'll see output like:
Deployed canisters:
backend (Candid UI): http://...localhost:8000/?id=...
frontend: http://...localhost:8000
Open the frontend URL in your browser. You'll see a React app that calls your backend canister.
How does the frontend know the backend's canister ID? The asset canister (which serves your frontend) provides canister IDs via a cookie. The template's frontend code reads this cookie to discover the backend. This works the same way locally and on mainnet — see Canister Discovery for details.
Open the Candid UI URL (shown next to "backend"). Candid UI is a web interface that lets you interact with any canister that has a known Candid interface — no frontend code required.
Try it:
- Find the
greetmethod - Enter a name (e.g., "World")
- Click "Call"
- See the response:
"Hello, World!"
Candid UI works with any backend canister, not just this example. It's useful for:
- Testing methods during development
- Exploring what methods a canister exposes
- Debugging without writing frontend code
You can also call your backend from the terminal:
icp canister call backend greet '("World")'You should see: ("Hello, World!")
The argument format '("World")' is Candid — the interface description language for the Internet Computer.
Don't want to type Candid manually? Omit the argument and icp-cli will prompt you interactively:
icp canister call backend greetYou'll see a prompt asking for the name parameter — just type World and press Enter. This works for any method with any argument types, making it easy to explore canister APIs without memorizing Candid syntax.
You can also omit the method name to get an interactive method picker:
icp canister call backendThis lists all available methods on the canister and lets you select one, which is handy when you're exploring an unfamiliar canister.
When you're done:
icp network stopYou've deployed a full-stack app on the Internet Computer! Continue your journey:
- Local Development — Learn the day-to-day development workflow
- Deploying to Mainnet — Go live on the Internet Computer
- Project Model — Understand how icp-cli organizes projects