Getting Started with Flow: Environment Setup & First Smart Contract

Building on blockchain doesn’t need to be complicated. Flow was designed by application developers who wanted infrastructure that actually works for real products. No byzantine setup processes. No fighting with tooling. Just clean developer experience from day one.

This guide walks you through setting up your Flow development environment, deploying your first smart contract, and understanding the fundamentals. By the end, you’ll have working code running on Flow’s local emulator and the knowledge to build real applications.

Let’s start building.

What You’re Building Toward


Flow development centers on smart contracts. These are programs that run on the blockchain, managing data and logic that can’t be tampered with or taken down.

Flow supports two approaches:

  • Cadence: Flow’s resource-oriented language, designed specifically for digital assets and consumer applications
  • Solidity: Ethereum’s smart contract language, fully supported on Flow EVM since the Crescendo upgrade

This guide focuses on Cadence. It’s Flow-native, safer for asset management, and designed for the platform’s unique architecture. If you’re coming from Ethereum and prefer Solidity, Flow’s EVM documentation has you covered. But learning Cadence unlocks Flow’s full potential.

Install the Flow CLI


The Flow Command Line Interface is your primary development tool. It manages accounts, deploys contracts, runs the local blockchain emulator, sends transactions, and queries state. Everything flows through the CLI.

If you have Homebrew (Mac/Linux):

bash
brew install flow-cli

For other systems: Visit Flow CLI Installation Guide for Windows, Linux, and alternative installation methods.

Verify installation:

bash
flow version

You should see output showing your Flow CLI version. If not, check the installation guide for troubleshooting.

Set Up Your Code Editor


Install the Flow Cadence VSCode Extension from the Visual Studio Code marketplace. This provides:

  • Syntax highlighting for Cadence
  • Inline error checking
  • Auto-completion
  • Code snippets
  • Direct integration with Flow CLI

You can develop without VSCode, but the extension makes Cadence development significantly smoother. If you use a different editor, syntax highlighting plugins may be available for Vim, Emacs, or others, check the Flow community resources.

Create Your First Project


Flow CLI includes project scaffolding. Initialize a new project:

bash
flow init

This generates a basic project structure with:

  • flow.json: Central configuration file containing accounts, contracts, deployments, and network settings
  • emulator-account.pkey: Private key for the default emulator account (safe to commit for local dev)
  • Basic directory structure for contracts, transactions, and scripts

Alternatively, you can create a more complete project template:

bash
flow setup hello-world –scaffold

Select “Basic Cadence project (no dependencies)” when prompted. This creates:

  • /contracts: Where your Cadence smart contracts live
  • /transactions: Code that modifies blockchain state
  • /scripts: Code that reads blockchain state (no modifications)
  • /tests: Test files for your contracts

The scaffold sets up a complete structure immediately usable for development.

Understanding flow.json


The flow.json file is your project’s configuration center. It defines:

Networks: Where your code deploys (emulator, testnet, mainnet) Accounts: Which accounts exist and their keys Contracts: Which contracts deploy where Deployments: Network-specific deployment configurations

A basic flow.json looks like this:

json
{
“networks”: {
“emulator”: “127.0.0.1:3569”
},
“accounts”: {
“emulator-account”: {
“address”: “f8d6e0586b0a20c7”,
“key”: “…”
}
},
“contracts”: {},
“deployments”: {}
}

The emulator account (f8d6e0586b0a20c7) is the default account that signs transactions on your local emulator. Its private key is safe to commit because the emulator wipes state on restart. Never commit keys for testnet or mainnet.

Start the Flow Emulator


The Flow emulator is a local blockchain that runs on your machine. It’s fast, deterministic, and perfect for development. No testnet tokens required. No network latency. Full control.
Start the emulator:

bash
flow emulator start

The emulator runs on http://localhost:8888 by default. Keep this terminal window open. The emulator needs to stay running while you develop.

You’ll see output indicating the emulator started successfully and is listening for transactions.

Write Your First Smart Contract


Create a simple counter contract. In your /contracts directory, create Counter.cdc:

cadence
access(all) contract Counter {
// Storage for the counter value
access(all) var count: Int
// Initialize the counter at 0
init() {
self.count = 0
}
// Function to increment the counter
access(all) fun increment() {
self.count = self.count + 1
}
// Function to get the current count
access(all) fun getCount(): Int {
return self.count
}
}

This contract does three things:

  1. Stores a counter value
  2. Provides a function to increment it
  3. Provides a function to read it

Simple, but it demonstrates the fundamental pattern: state storage and functions to modify or read that state.

Deploy Your Contract


Update flow.json to include your contract:

json
{
“contracts”: {
“Counter”: “./contracts/Counter.cdc”
},
“deployments”: {
“emulator”: {
“emulator-account”: [“Counter”]
}
}
}

This tells Flow CLI:
  • The Counter contract exists at ./contracts/Counter.cdc
  • On the emulator network, deploy Counter to the emulator-account

Deploy the contract:

bash
flow project deploy –network emulator

You’ll see output confirming the contract deployed successfully. The emulator now has your Counter contract live and ready for interaction.

Read Data with Scripts


Scripts read blockchain state without modifying it. They’re free (no gas fees) and return results immediately.

Create /scripts/get_counter.cdc:

cadence
import Counter from “../contracts/Counter.cdc”

access(all) fun main(): Int {
return Counter.getCount()
}

Run the script:

bash
flow scripts execute ./scripts/get_counter.cdc –network emulator

Output: Result: 0

The counter starts at 0 because that’s what the contract’s init() function sets. The script confirmed deployment worked and the contract’s state is accessible.

Modify State with Transactions


Transactions change blockchain state. They cost gas fees (on mainnet/testnet) and require account authorization.

Create /transactions/increment_counter.cdc:

cadence
import Counter from “../contracts/Counter.cdc”

transaction {
prepare(acct: &Account) {
// Prepare phase handles authorization
// We don’t need the account for this simple transaction
}
execute {
Counter.increment()
}
}

Send the transaction:

bash
flow transactions send ./transactions/increment_counter.cdc –network emulator –signer emulator-account

The --signer flag specifies which account signs (and pays for) the transaction. On emulator, the emulator-account signs by default.
Run the get_counter script again:

bash
flow scripts execute ./scripts/get_counter.cdc –network emulator

Output: Result: 1

The counter incremented. You just modified blockchain state through a transaction.

Understanding the Development Cycle


Flow development follows a pattern:

  1. Write contracts defining state and logic
  2. Deploy contracts to emulator/testnet/mainnet
  3. Write scripts to read state (testing, debugging, frontend queries)
  4. Write transactions to modify state (user actions, admin functions)
  5. Test everything using Flow’s testing framework or manual verification
  6. Iterate based on results

The emulator makes this cycle fast. Write code, deploy, test, repeat. No waiting for block confirmations or testnet faucets.

Next Steps: Testing


Flow supports comprehensive testing. Create /tests/Counter_test.cdc:

cadence
import Test

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

access(all) fun testContract() {
let err = Test.deployContract(
name: “Counter”,
path: “../contracts/Counter.cdc”,
arguments: []
)
Test.expect(err, Test.beNil())
}

Run tests:

bash
flow test ./tests/Counter_test.cdc

Tests verify your contracts work as expected before deploying to testnet or mainnet. Flow’s testing framework supports comprehensive test scenarios, from basic functionality to edge cases and error handling.

Building a Frontend


Contracts deployed. Transactions working. Next step: connect a frontend.

Flow provides @onflow/react-sdk for React applications (or @onflow/fcl for framework-agnostic JavaScript). These SDKs handle wallet connections, transaction signing, and blockchain queries.

Basic setup in a React app:

javascript
import { FlowProvider } from ‘@onflow/react-sdk’

function App() {
return (
<FlowProvider
config={{
“flow.network”: “emulator”,
“accessNode.api”: “http://localhost:8888”,
“0xCounter”: “f8d6e0586b0a20c7”
}}
>
{/* Your app components */}
</FlowProvider>
)
}

The FlowProvider configures your app to connect to the local emulator and maps contract addresses. From there, you can use hooks to query state and submit transactions directly from React components.

Full frontend integration is beyond this guide’s scope, but Flow’s documentation provides complete tutorials: Building a Frontend App

Moving to Testnet


Local development is fast. But eventually, you deploy to testnet for real network testing.

Get testnet FLOW: Flow provides 100,000 testnet FLOW tokens (not real value) through the Flow Faucet. No drip limits. No waiting.

Create a testnet account:

bash
flow accounts create –network testnet

Update flow.json with your testnet account details:

json
{
“accounts”: {
“testnet-account”: {
“address”: “YOUR_TESTNET_ADDRESS”,
“key”: “YOUR_PRIVATE_KEY”
}
},
“deployments”: {
“testnet”: {
“testnet-account”: [“Counter”]
}
}
}

Deploy to testnet:

bash
flow project deploy –network testnet

Your contract is now live on Flow’s public testnet, accessible to anyone.

Key Resources


Official Documentation:

Learning Platforms:

Community:

Development Tools:

Common Gotchas


Emulator state resets on restart. Contracts and accounts disappear when you stop the emulator. That’s intentional, clean state every time.

Private keys in flow.json: Safe for emulator. Never commit testnet/mainnet keys.

Account addresses differ by network. Same contract, different addresses on emulator vs testnet vs mainnet. flow.json handles this with deployment configurations.

Resource-oriented thinking takes adjustment. If you’re coming from Solidity, Cadence’s resource model feels different. Resources can’t be copied or lost. That’s the safety mechanism.

Imports reference deployment locations. When importing contracts, the address comes from flow.json configurations. import Counter from 0xCounter resolves based on the network you’re using.

Final Thought


You’ve set up a complete Flow development environment. Installed CLI. Created a project. Deployed a contract. Ran scripts and transactions. Verified everything works.

This is the foundation. From here, you can build NFT platforms, DeFi protocols, games, or consumer applications. The patterns stay consistent: contracts define logic, transactions modify state, scripts read state, frontends connect it all.

Flow was built for applications that scale. The infrastructure handles millions of users. The developer experience makes building practical. The tooling removes friction.

Now start building.
Facebook
Twitter
LinkedIn
Pinterest
WhatsApp