Forte is Live on Testnet and Forte Hacks has $250k in Prizes for Developers! Learn more.
开发者生态
October 8, 2025

How to Build a Web3 App on Flow: A Complete Guide

通过
流程
团队
How to Build a Web3 App on Flow: A Complete Guide

Blockchain and Web3 development can seem intimidating at first, but the Flow network and its smart contract language Cadence make it surprisingly accessible. This guide walks through building a complete blockchain application from scratch, all the way to a working "Hello World" example with a React frontend.

什么是流?

Flow is a network designed for the next generation of apps, games, and digital assets. It offers fast finality, low fees, and a developer-friendly environment. Flow was built with Cadence, its resource-oriented smart contract programming language, and recently added EVM compatibility for Solidity developers.

Cadence is designed for safety and simplicity, with built-in support for digital assets and composable contracts.

This tutorial focuses on Cadence, but you can also explore EVM on Flow if you prefer Solidity.

先决条件

In order to begin, make sure to have:

  • Node.js (version 18 or higher)
  • Git
  • A code editor (VS Code recommended)

For detailed setup, see the Flow Getting Started Guide.

Step 1: Install the Flow CLI

The Flow CLI is the gateway to interacting with Flow: deploying contracts, running scripts, managing accounts, and more.

Installation

macOS

brew install flow-cli

Linux

sh -ci "$(curl -fsSL https://storage.googleapis.com/flow-cli/install.sh)"

Windows (PowerShell)

iex "& { $(irm https://storage.googleapis.com/flow-cli/install.ps1) }"

Verify installation:

flow version

You can explore all commands with:

flow help

Step 2: Create a Project

flow init

Enter the name of your project (i.e. your-project-name) Then choose "Basic Cadence project" from the interactive prompt.This creates a project folder:

  • cadence/ - Contracts, scripts, transactions, and tests
  • flow.json - Project configuration (accounts, deployments, contracts)
  • emulator-account.pkey - Private key for a default account

cd your-project-name

Step 3: Cadence Basics

Cadence is built on resources, objects that can only exist in one place at a time and cannot be duplicated or lost. Perfect for assets like fungible tokens and NFTs.

Every Flow account has private storage for contracts, resources, and data.  Digital property, such as collectibles and tokens are kept in this storage. Access is managed with fine-grained controls and capabilities.

Learn more in the Cadence Getting Started tutorial.

Step 4: Write a Smart Contract

Create cadence/contracts/HelloWorld.cdc with the CLI:

flow generate contract HelloWorld

Then, implement the contract:

access(all) contract HelloWorld {

   access(all) var greeting: String

   access(all) event HelloEvent(message: String)

   init() {
       self.greeting = "Hello, World!"
   }

   access(all) fun sayHello(): String {
       return self.greeting
   }

   // Warning: Anyone can call this function to change the greeting
   // See https://cadence-lang.org/docs/language/access-control
   // to learn about the granular access control available in Cadence

   access(all) fun changeGreeting(newGreeting: String) {
       self.greeting = newGreeting
       emit HelloEvent(message: newGreeting)
   }

}

This contract includes:

  • A public variable greeting
  • An event HelloEvent
  • A function sayHello()
  • A function changeGreeting()

⚠️ Warning: This contract allows anyone to change the greeting. For production apps, see Access Control.

Step 5: Deploy the Contract

Start the local emulator:

流动仿真器启动

In a new terminal, add the contract to be deployed:

flow config add deployment

Select emulator as the network for deployment.

Choose emulator-account as the account to deploy to.

Then pick HelloWorld as the contract you wish to create a deployment for.

Finally, deploy:

flow project deploy

You’ll see something similar to:

Deploying 1 contracts for accounts: emulator-account

HelloWorld -> 0xf8d6e0586b0a20c7 (e167b88c81f83d6c88fe5e4055ea138ba79a8fbdb4248c174c27e2bd745c7450) 

🎉 All contracts deployed successfully

Step 6: Interact with the Contract

Script

Create cadence/scripts/GetGreeting.cdc with the CLI:

flow generate script GetGreeting

Then implement the script:

import "HelloWorld"

access(all) fun main(): String {
   return HelloWorld.sayHello()
}

Run:

flow scripts execute cadence/scripts/GetGreeting.cdc

Transaction

Create cadence/transactions/UpdateHello.cdc with the CLI:

flow generate transaction UpdateHello

Then implement the transaction:

import "HelloWorld"

transaction {
   execute {
       let message = HelloWorld.sayHello()
       log(message)
   }
}

Run:

flow transactions send cadence/transactions/UpdateHello.cdc

Re-run the script to see the new message:

flow scripts execute cadence/scripts/GetGreeting.cdc

Step 7: Add a React Frontend

Below, explore a sketch of a UI built with the Flow React SDK.  The SDK is compatible with Next.js, Vite, and other popular frameworks.

See the frontend quickstart for more details.

src/app/page.tsx

'use client'

import { useState } from 'react'

import {
 FlowProvider,
 useFlowCurrentUser,
 useFlowQuery,
 useFlowMutate,
} from '@onflow/react-sdk'

import flowJson from '../flow.json'

function HelloWorldApp() {
 const [newGreeting, setNewGreeting] = useState('')
 const { user, authenticate, unauthenticate } = useFlowCurrentUser()
 const { data: greeting, isLoading, error, refetch } = useFlowQuery({

   cadence: `
     import "HelloWorld"
     access(all) fun main(): String {
       return HelloWorld.sayHello()
     }
   `,

   query: { enabled: true },

 })

 const { mutate: changeGreeting, isPending, error: txError } = useFlowMutate({
   mutation: { onSuccess: () => { setNewGreeting(''); refetch() } },

 })

 return (
   <div style={{ padding: 20 }}>
     <h1>Hello World dApp</h1>
     <p>{isLoading ? 'Loading…' : error ? error.message : greeting}</p>
     {user?.loggedIn ? (
       <>
         <input
           value={newGreeting}
           onChange={(e) => setNewGreeting(e.target.value)}
           placeholder="New greeting"
         />
         <button onClick={() =>
           changeGreeting({
             cadence: `
               import "HelloWorld"
               transaction(newGreeting: String) {
                 prepare(acct: &Account) {}
                 execute { HelloWorld.changeGreeting(newGreeting: newGreeting) }
               }
             `,
             args: (arg, t) => [arg(newGreeting, t.String)],
           })
         } disabled={isPending || !newGreeting.trim()}>
           {isPending ? 'Changing…' : 'Change'}
         </button>
         <button onClick={unauthenticate}>Disconnect</button>
       </>
     ) : (
       <button onClick={authenticate}>Connect Wallet</button>
     )}
     {txError && <p style={{ color: 'crimson' }}>{txError.message}</p>}
   </div>
 )
}

export default function App() {
 return (
   <FlowProvider
     config={{
       accessNodeUrl: 'http://localhost:8888',
       flowNetwork: 'emulator',
       discoveryWallet: 'https://fcl-discovery.onflow.org/emulator/authn',
     }}
     flowJson={flowJson}
   >
     <HelloWorldApp />

   </FlowProvider>
 )
}

Step 8: Testing

Flow CLI includes a built-in test runner.

Open the autogenerated file cadence/tests/hello_world_test.cdc and update it to import the contract and test the hello message:

import Test

import "HelloWorld"

access(all) let account = Test.createAccount()

access(all) fun testContract() {
   let err = Test.deployContract(
       name: "HelloWorld",
       path: "../contracts/HelloWorld.cdc",
       arguments: [],
   )

   Test.expect(err, Test.beNil())

   Test.expect(HelloWorld.sayHello(), Test.equal("Hello, World!"))

}

Run:

flow test

See Flow Testing Docs for details.

Step 9: Deploy to Testnet

When ready to move beyond the emulator, start by creating a new account for testnet:

flow accounts create

Fund the account from the faucet:

flow accounts fund <address>

Then add a deployment:

flow config add deployment

Finally, deploy:

# Deploy contract to testnet
flow deploy --network testnet

⚠️ Ensure your flow.json is configured with a testnet account and keys.

接下来的步骤

For more complex applications, the following will be needed:

  • Resources — unique, non-copyable objects (e.g., NFTs)
  • Capabilities — controlled access to resources/functions

To learn this and more, see:

总结

By following this guide, a Web3 developer can go from setting up the Flow CLI to writing, deploying, and interacting with their first Cadence smart contract, and even connecting it to a React frontend. Along the way, they’ve seen how Flow’s developer tools, emulator, and testing framework simplify the process of building real blockchain applications.

What’s been built here is just the starting point. With Cadence’s resource-oriented model, a builder can create secure, composable digital assets. Whether they’re experimenting locally or deploying to testnet, Flow provides a smooth path from idea to production-ready app.

Keep exploring the resources linked above, and consider extending the project with capabilities, NFTs, or DeFi logic. The Flow community is active and welcoming, so don’t hesitate to join developer office hours or contribute to open-source projects.

资源