Acton
Building

Overview

Learn how Acton's build system manages smart contract compilation, dependencies, and code generation

Acton provides a flexible smart contract build system with support for code generation and dependency management between contracts. The build system automatically handles contract compilation, dependency resolution, and generates helper functions for embedding child contracts.

For a complete reference of all configuration options and CLI flags, see:

Basic Configuration

Contracts are described in the Acton.toml project configuration file. A simple contract might look like this:

[package]
name = "my-counter"
description = "The Best Counter Ever"
version = "0.1.0"
license = "MIT"

[contracts.Counter]
display-name = "Counter"
src = "contracts/Counter.tolk"
depends = []

Now when calling acton build, the contract will be compiled and added to the cache.

Contract Dependencies

Very often, one contract's code needs to be included in another contract. There are three main ways to implement this:

  1. Storage approach: Store the code in Storage during deployment
  2. Code embedding: Compile the child contract code and embed it through an assembly function directly into the parent contract's code
  3. Library reference: Deploy a library with the child contract code and reference this library through an assembly function

Acton supports all three approaches and provides convenient file generation for the second and third methods.

Code Embedding

Let's imagine we have a Jetton Minter and Jetton Wallet, and we need the Wallet code inside the Minter. All you need to do to embed the Wallet code into the Minter is to specify the dependency in Acton.toml:

[contracts.JettonMinter]
display-name = "Minter"
src = "contracts/JettonMinter.tolk"
depends = ["JettonWallet"]

[contracts.JettonWallet]
display-name = "Wallet"
src = "contracts/JettonWallet.tolk"
depends = []

Now after calling acton build, a file gen/JettonWallet.code.tolk will appear in the gen/ folder with the function jettonWalletCompiledCode which returns a Cell with the Wallet code.

Library References

If you want to reference code through a library reference, specify the dependency kind in the depends array:

[contracts.JettonMinter]
display-name = "Minter"
src = "contracts/JettonMinter.tolk"
depends = [
  { name = "JettonWallet", kind = "library_ref" }
]

[contracts.JettonWallet]
display-name = "Wallet"
src = "contracts/JettonWallet.tolk"
depends = []

The generated file gen/JettonWallet.code.tolk will contain the function jettonWalletCompiledCode which references the library by its hash instead of embedding the full code.

Check out the Libraries guide for more information on how to deploy and use libraries.

Dependency Resolution

Acton automatically resolves contract dependencies and ensures they are compiled in the correct order. If a circular dependency is detected between contracts, the build will fail with a detailed error message showing the cycle path:

Error: Circular dependency detected in contracts: A B A C

Dependency-graph failures such as missing contracts or cycles happen before the main compile loop starts, so those failures do not leave behind partial build artifacts.

Best-Effort Builds

Once dependency resolution succeeds, acton build switches to best-effort execution:

  • a compile failure for one contract is recorded, but Acton continues building other eligible contracts
  • artifact-writing failures are also collected instead of aborting the whole run
  • contracts that compiled successfully before a later failure keep their JSON, BoC, helper, or Fift artifacts on disk

This means a failing build can still leave useful partial outputs behind for the contracts that already succeeded.

There is one dependency-related caveat: if a dependency failed earlier, its generated helper file is not produced. A parent contract may then fail later because the expected generated import is missing.

When you run acton build <NAME>, Acton does not build every configured contract. It limits work to the requested contract and its transitive dependencies.

Build vs Compile

acton build and acton compile share the same compiler and cache, but they solve different problems:

Aspectacton buildacton compile
ScopeContract graph from Acton.tomlOne explicit .tolk file
ManifestRequired for normal operationOptional; used for mappings/project context when available
OutputsProject build JSON, optional BoC, dependency helpers, optional FiftOnly the files explicitly requested via CLI flags
DefaultsUses [build] config and contract metadataDoes not use [build] output defaults or generate helper files

Use build when you want project-aware artifact generation. Use compile when you want to inspect or export one file in isolation.

Build Caching

Acton uses a shared file-based compilation cache to speed up repeated build, compile, and test runs. By default it lives under build/cache relative to the project root.

Cache Layout

PathPurpose
build/cache/*.jsonNormal compilation cache entries
build/cache/debug/*.jsonDebug-oriented entries compiled with source-map/debug metadata
build/cache/.lockA write lock that coordinates concurrent cache updates between processes

Debug and non-debug compilation results are stored separately, so a source-map-enabled compile does not overwrite the normal cached artifact for the same file.

Cache Management

CommandDescription
acton buildBuild with incremental caching
acton build --clear-cacheClear cache and rebuild everything

How Caching Works

The build system tracks:

  • Source file content and imported file content
  • Declared contract dependencies from Acton.toml
  • Compiler mode differences such as debug/source-map output and Fift output
  • Compiler/cache schema version changes

Each cache entry stores the compiled code, code hash, and any optional metadata requested for that compilation mode, such as ABI, source-map data, debug marks, or Fift output.

When Acton checks whether a cache entry is still valid, it recomputes a hash across the normalized dependency set for that source file. This includes both regular file imports and source files pulled in through contract dependencies. If any of those inputs change, the cached entry is treated as stale and the file is recompiled.

Because dependency hashes are part of cache validation, changing a child contract or imported file invalidates parent cache entries that depend on it. That is what lets incremental builds recompile only the affected part of the graph instead of rebuilding everything.

What --clear-cache Actually Clears

Commands that expose --clear-cache wipe the shared file cache before continuing. In practice this means:

  • all cached JSON entries under build/cache/ are removed
  • the debug cache subdirectory build/cache/debug/ is removed and recreated on demand
  • the lock file build/cache/.lock is preserved
  • other generated artifacts are not deleted automatically

So --clear-cache does not clean the rest of build/, your generated helpers under gen/, saved traces under build/traces/, logs under build/logs/, or mutation-session artifacts. It only forces recompilation by resetting the file compilation cache.

Shared Cache Across Commands

The same cache directory is reused by several workflows:

  • acton build reads and writes cache entries while building project contracts
  • acton compile uses the same cache for standalone file compilation
  • acton test reuses the same cache during the contract build/preparation phase

This shared design means a recent acton build often speeds up a later acton test, and vice versa.

Cache writes are guarded by build/cache/.lock. If another process is already updating the cache, Acton waits for that lock instead of writing concurrently.

Last updated on

On this page