Choosing Between Public and View Functions in Clarity Smart Contracts
Learn when to use Clarity view versus public functions, see a side‑by‑side comparison, and validate the choice with a sample contract and CLI commands.
09 Oct 2026, 09:46 UTC

Decision and Constraints
When writing a Clarity contract for Stacks, you must decide whether a function should be able to modify blockchain state or only read it. The decision affects transaction costs, off‑chain usability, and what the function is allowed to do.
Constraints imposed by Clarity
- View (read‑only) functions cannot call any function that mutates state.
- They cannot use
varset, cannot emit events, and must be pure – they may only read constants, maps, or call other view functions. - Public functions may mutate state, use
varset, emit events, and call any other function (view or public).
Option Comparison
| Function Type | State Mutation Allowed | Gas Cost (on‑chain) | Off‑chain Callability | Typical Use Cases |
|---|---|---|---|---|
| Public | Yes | Paid by transaction sender (burns STX) | No – must be invoked via a transaction | Token transfers, contract upgrades, any logic that writes to maps or vars |
| View (read‑only) | No | Free when called through RPC or local simulation | Yes – via RPC call_read_only or clarity-cli |
Balance checks, metadata retrieval, predicate evaluation, reading maps |
Trade‑offs
View functions save gas and enable rich off‑chain tooling (e.g., dApps can query state without signing a transaction). However, they cannot alter state or trigger side effects, so any logic that needs to update a map, issue a token, or upgrade a contract must be public. Public functions incur transaction fees and block latency but are the only way to perform state‑changing operations.
Concrete Implementation
The following Clarity contract illustrates both function types. It defines a simple token‑supply tracker where the supply is stored in a map keyed by the contract principal.
(define-constant TOKEN-SUPPLY-Key u"supply")
;; storage: a map from contract principal to current supply
(define-data-var supply (map principal uint) (map))
;; View function: reads the supply without modifying state
(define-read-only (get-token-supply (who principal))
(let ((current (map-get? supply who)))
(if (is-none current)
u0
(unwrap current))))
;; Public function: mints new tokens, updating the supply map
(define-public (mint (who principal) (amount uint))
(begin
;; Only the contract owner may mint – replace with your own auth logic
(asserts! (is-eq who tx-sender) "Unauthorized")
;; Update the map
(map-set supply who (+ (get-token-supply who) amount))
(ok amount)))
The get-token-supply function is marked define-read-only (a view). It only reads the supply map and returns the stored amount. The mint function is define-public; it calls map-set to mutate state and includes an authorization check.
Validation Steps
To confirm that the view function behaves as expected and that the public function incurs a cost, follow these steps on a local Stacks devnet or testnet.
- Compile and type‑check – Paste the contract into the Clarity Playground () and run the type checker. The view function should pass; any attempt to call
varsetinside it would produce a compile‑time error. - Call the view function off‑chain – Using
clarity-cli(or the Stacks RPC), execute:
clarity-cli call-read-only \
--contract-address ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM.my-token \
--function get-token-supply \
--argument ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM \
--network testnet
This command returns the current supply without generating a transaction hash, confirming zero on‑chain cost.
- Invoke the public function via a transaction – Create a transaction that calls
mint:
clarity-cli contract-call \
--contract-address ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM.my-token \
--function mint \
--argument ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM \
--argument 100 \
--fee 1000 \
--network testnet \
--wallet-wallet-name mywallet
After broadcasting, inspect the transaction on the Stacks Explorer. You should see a transaction hash, a fee deduction from the sender, and an updated supply when you re‑run the view call.
Limitations and Practical Checks
- View functions cannot emit events, so any off‑chain listener that relies on events must be triggered from a public function.
- If you accidentally place a state‑changing call inside a view function, the Clarity compiler will reject the contract – treat this as a safeguard, not a runtime surprise.
- To verify that a view call truly consumed no gas, check the transaction receipt on the Explorer for the call: the
tx_statusfield will besuccessbut theburnedamount will be0.
By following the decision guide above, you can choose the appropriate function type for each piece of logic in your Clarity contract, minimizing costs while preserving the ability to modify state when required.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.