Developer Quickstart
Your 0→1 guide for building a Clarity contract and app on Stacks.

Welcome to the Stacks Developer Quickstart Guide! This is your fast-track path for understanding what you'll need to become a Stacks developer. In this guide, you’ll build a real Clarity smart contract, wire up a functioning Stacks app, and pick up about 75% of the practical knowledge every Stacks builder needs. Whether you’re shipping your first project or leveling up your skills, this guide takes you from zero to deployed—quickly and confidently.
What you'll achieve
By the end of this quickstart, you’ll have built an onchain app by:
Building a Clarity smart contract with Clarinet
Utilize the 1:1 Bitcoin backed token, sBTC
Deploying your smart contract to Stacks' testnet
Interacting with your deployed contract from a frontend app
Why Stacks?
Stacks is a fast, low-cost, builder-friendly layer 2 network on Bitcoin. It’s built on Bitcoin, inheriting Bitcoin’s battle-tested security. By jumping into this guide, you’re joining the Stacks community that’s bringing a global onchain economy to Bitcoin.
What You'll Build
The app you'll build will be a message board contract. Users can add a new message to store on-chain for a fee of 1 satoshi in sBTC. Other functionality to read data from the contract will also be handled. Besides sBTC, there will be other things that'll be introduced to you such as post-conditions, Bitcoin read access, unit testing, wallet connectivity, BNS, Hiro, and more. Hopefully all this will give you a good flavor of what you can expect in the Stacks builder ecosystem.
Let's start building on Bitcoin! 🟧
Set Up Your Developer Environment
Install Clarinet
Clarinet is the popular CLI tool to build, test, and deploy smart contracts on the Stacks blockchain.
Below are a few different ways to install Clarinet on your machine using your terminal. Refer to the dedicated installation guide in the 'Learn Clarinet' section for more information.
brew install clarinetwinget install clarinetsudo apt install build-essential pkg-config libssl-dev
git clone https://github.com/stx-labs/clarinet
cd clarinet
cargo clarinet-installwget -nv https://github.com/stx-labs/clarinet/releases/latest/download/clarinet-linux-x64-glibc.tar.gz -O clarinet-linux-x64.tar.gz
tar -xf clarinet-linux-x64.tar.gz
chmod +x ./clarinet
mv ./clarinet /usr/local/binInstall Clarity Extension
You'll also want to install the Clarity Extension for your code editor. The official one is 'Clarity - Stacks Labs' which is maintained by Stacks Labs.

Install a Stacks wallet
There are many Stacks supported wallets in the market. For this guide, we'll be using the Leather wallet. Leather supports Stacks, Bitcoin, and other Bitcoin related meta-protocols. Download and install its browser extension so you can interact with your smart contract later on in this guide. Make sure to switch to the Testnet network in your wallet settings. Later on, we'll show you how to get testnet STX and sBTC tokens that you'll use for contract interaction.
Create a Clarity smart contract
Create a new Clarinet project
Let's start by creating a new Clarinet project which will house our smart contract. The clarinet new command sets up everything you need for smart contract development, including a testing framework, deployment configurations, and a local development environment.
clarinet new my-stacks-contractsA Clarinet project will be scaffolded with the below:
Generate your contract
Now that we have our project structure, let's create a smart contract. Navigate into your project directory and use Clarinet's contract generator:
$ cd my-stacks-contracts
$ clarinet contract new message-board
Created file contracts/message-board.clar
Created file tests/message-board.test.ts
Updated Clarinet.toml with contract message-boardClarinet automatically creates both your contract file and a corresponding test file.
Write your Clarity smart contract
Define constants
Open contracts/message-board.clar and remove its existing content. This is where we'll start writing our own Clarity smart contract.
Let's first define some constants:
contract owner to establish control access
custom error codes to handle errors in functions
;; Simple Message Board Contract
;; This contract allows users to read and post messages for a fee in sBTC.
;; Define contract owner
(define-constant CONTRACT_OWNER tx-sender)
;; Define error codes
(define-constant ERR_NOT_ENOUGH_SBTC (err u1004))
(define-constant ERR_NOT_CONTRACT_OWNER (err u1005))
(define-constant ERR_BLOCK_NOT_FOUND (err u1003))You'll notice in the CONTRACT_OWNER constant that tx-sender is set in place as the value. When this contract is deployed, the Clarity VM will determine who the tx-sender is based on who deployed the contract. This allows the hardcoded tx-sender to always point to the principal that deployed the contract.
Define data storage
We'll then need to define some data storage:
A map to store key-value pairs of the message id and it's related metadata
A data variable to count the total number of messages added
;; Define a map to store messages
;; Each message has an ID, content, author, and Bitcoin block height timestamp
(define-map messages
uint
{
message: (string-utf8 280),
author: principal,
time: uint,
}
)
;; Counter for total messages
(define-data-var message-count uint u0)Define an add message function
Next up is our main function of the contract. This function allows users to add a new message to the contract for a fee of 1 satoshi in sBTC. Invoking this function will change the state of our contract and update the data storage pieces we setup before.
There's quite a lot going on in this function above that covers in-contract post-conditions, calling the official sBTC token contract, reading Bitcoin state, emitting events, and etc. We'll break it down for you:
Add sBTC contract requirements
Since we're working with sBTC in our local developer environment, we'll need to make sure Clarinet can recognize this. Clarinet can automatically wire up the official sBTC contracts so you can build and test sBTC flows locally.
In our case, all we'll need to do is add the .sbtc-deposit contract as a project requirement.
clarinet requirements add SM3VDXK3WZZSA84XXFKAFAF15NNZX32CTSG82JFQ4.sbtc-depositYou'll notice in the add-message public function, we're making an external contract call to the .sbtc-token contract. This is the official sBTC token contract that contains the SIP-010 standard transfer function that we are invoking.
Check out the dedicated sBTC integration page to learn more.
Allow contract owner to withdraw funds
In the beginning of our contract, we defined a constant to store the Stacks principal of the contract owner. Having a contract owner allows for specific access control of the contract that is entitled to the owner. Let's allow the owner to be able to withdraw the accumulated sBTC fees that were sent by anyone who created a new message in the contract.
You'll notice in the highlighted line that the function performs an asserts! check to confirm that the tx-sender calling the contract is in fact the CONTRACT_OWNER . If it is in fact the owner of the contract, the function body proceeds with transferring the balance of sBTC to the owner or else it'll throw an error that we defined earlier.
Implement read only functions
We'll round out our contract with important read only functions that will return us needed data from the contract.
You'll notice the usage of a at-block function in the highlighted line of code. The at-block function evaluates the inner expression as if it were evaluated at the end of a specific Stacks block.
Test your contract
Now with the actual writing of your contract complete, we now need to test its functionality. There's a few different ways we can go about iterating and testing the functionality of your contract.
Contract interaction in the Clarinet REPL
Running your contract in a local blockchain environment
Fuzz testing with Rendezvous
Writing unit tests with the Clarinet JS SDK
We'll go with unit testing for now. In your tests folder, open up the related message-board.test.ts file and let's use the unit test written below.
You'll notice we have two it blocks setup to test out 2 different scenarios:
Allows user to add a new message
Allows owner to withdraw sBTC funds
Run the test via npm run test to confirm that the two scenarios are functioning as intended.
$ npm run test
✓ tests/message-board.test.ts (2 tests) 46ms
✓ message board tests (2)
✓ allows user to add a new message 26ms
✓ allows contract owner to withdraw funds 19ms
Test Files 1 passed (1)
Tests 2 passed (2)
Start at 14:05:07
Duration 886ms (transform 40ms, setup 42ms, collect 8ms, tests 46ms, environment 699ms, prepare 4ms)Great! Now that your contract is working as intended, let's deploy the contract to testnet.
Get testnet faucet tokens
Navigate to the Hiro Platform faucet
Hiro is a platform to build and scale Bitcoin apps, including custom data streams, onchain alerts, API key management, and more. Create an account and navigate to the top tab of 'Faucet'. On the Faucet page, you can request testnet STX and/or sBTC. We'll be needing both so fund your Leather wallet account with both.

Grab the testnet Stacks address from your Leather wallet and paste it in the recipient field.
Important: Switch to the Testnet network in your wallet settings
Confirm testnet tokens in your wallet
Open up your Leather extension to confirm that you've received testnet STX and sBTC. You might need to enable the viewing of the sBTC token in your wallet under 'Manage tokens'.

With both testnet STX and sBTC, you're ready to deploy your contract and interact with it from a front-end client.
Deploy your Clarity smart contract
Generate testnet deployment plan
You'll first want to input a mnemonic seed phrase in the settings/Testnet.toml file and specify the account derivation path that you want to use for deploying the contract. The account should be the same one you used to request testnet STX to. This will be the account that actually deploys the contract and becomes the contract owner.
[network]
name = "testnet"
stacks_node_rpc_address = "https://api.testnet.hiro.so"
deployment_fee_rate = 10
[accounts.deployer]
mnemonic = "<YOUR TESTNET MNEMONIC>"
derivation = "m/44'/5757'/0'/0/0"Then generate a deployment plan for the testnet network. Deployment plans are YAML files that describe how contracts are published or called.
For more information on configuring deployment plans, check out the specific guide here.
$ clarinet deployments generate --testnet --medium-cost
Analyzing contracts...
Calculating deployment costs...
Generating deployment plan
Created file deployments/default.testnet-plan.yamlDeploy contract to testnet
Once your deployment plan is generated and configured properly, go ahead and deploy the contract to testnet.
clarinet deployments apply --testnetIf the contract was successfully deployed, you should see the below confirmation:
Broadcasting transactions to https://api.testnet.hiro.so
Publish ST11V9ZN6E6VG72SHMAVM9GDE30VD3VGW5Q1W9WX3.message-board Transaction confirmedUse stacks.js on the frontend
Connect wallet
Using stacks.js packages on the frontend will allow our frontend app to authenticate wallets, call our contract functions, and interact with the Stacks network.
We'll first want to connect and authenticate our Leather wallet extension with our frontend app. The stacks.js monorepo contains several underlying packages specific to different use cases. The package @stacks/connect is the main connectivity package used in Stacks.
In the snippet below, you'll notice we have 3 functions setup to handle connectWallet , disconnectWallet, and for getBns . All 3 functions will be integral in how we want to display the 'Connect' and 'Disconnect' button in the UI.
The connect() method comes with ability to configure how you want the wallet selector modal to appear for your app. You can decide which wallets to have only appear as an option or allow any wallet that follows the SIP-030 standard to appear as an available Stacks wallet.

Call `add-message` public function
Next, we'll setup a stx_callContract to invoke the add-message public function of our contract. This function will accept a string content to be passed into our contract call.
You'll notice in the transaction data object that we pass into our string literal method of stx_callContract, that we're setting up post-conditions. Post-Conditions for the frontend are declared to protect user assets. The Pc helper from @stacks/transactions helps us to declare post-condition statements for any type of asset and equality operator.
Invoking our addMessage function will prompt the user's connected wallet to prompt a transaction confirmation popup. This popup will display all of the relevant information of the transaction as well as the post-condition statements that we've declared.

Call read-only function
As how we've created a few read-only functions in our contract, we'll also want to call these from the frontend to retrieve certain contract data.
Let's setup a fetchCallReadOnlyFunction to invoke our contract's get-message-count-at-block read-only function. For this, we'll fetch the current Stacks block height from the Hiro API endpoint and pass that returned value into our read-only function.
And that's it, you've successfully created an sBTC powered Clarity smart contract which can be interacted with from a frontend app. There's obviously much more you can do to complete this but you've got some of the basics down pat now. Go ahead and finish creating the frontend functions to call on the other contract functions we have.
Further Improvements
This is just the beginning. There are many ways we can improve upon this app. Here are some suggestions for you to extend the functionality of this app:
Deploy to mainnet and share your project with the community
Use Chainhooks to index emitted events from the contract
Integrate the
sbtclibrary so users can directly bridge their BTC to sBTC in-appUtilize SIP-009 NFTs to uniquely identify each message for each author
Next Steps
Now that you have the basics down, here are some ways to continue your Stacks development journey:
Learn More About Clarity
Clarity Book: Comprehensive guide to Clarity development
Clarity Reference: Complete documentation of Clarity functions
Clarity Crash Course: Quick introduction to Clarity concepts
Development Tools
Clarinet: Local development environment for Clarity
Hiro Platform: Hosted development environment
Stacks Explorer: View transactions and contracts on mainnet
Community Resources
Stacks Discord: Connect with other developers
Stacks Forum: Ask questions and share projects
Stacks GitHub: Contribute to the ecosystem
Last updated
Was this helpful?
