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.
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