How do I publish a Move package to Sui?
November 13, 2026
Run sui client publish from your package's root directory (the folder with Move.toml). The CLI compiles the package, checks dependencies against their on-chain bytecode, sends a publish transaction from your active address on your active network, and prints the new package ID, the UpgradeCap that controls future upgrades, and any objects your init functions created. It also writes the publication details to Published.toml.
Before you publish
You need the Sui CLI, an active address with SUI for gas, and a package that builds:
sui client active-env # which network you're on
sui client active-address # which address pays
sui client gas # coins available for gas
sui move build
sui move testOn testnet, get SUI from the faucet. A minimal Move.toml for the current package system is just:
[package]
name = "counter"
edition = "2024"std and sui are included automatically, so don't list them. Modules declare the package's own name as their address, as in module counter::counter;. The publish step assigns the real address.
Publish
cd counter
sui client publishYou don't need --gas-budget. When you leave it out, the CLI dry-runs the transaction to estimate one. To check cost and output without spending anything, run:
sui client publish --dry-runIn the output, look at Object Changes:
- Published Objects: the
PackageIDis your package ID. - Created Objects: one object of type
0x2::package::UpgradeCap, plus anythinginitcreated (shared objects, admin caps, aPublisher, and so on).
Save both IDs. See how to find a package ID if you lost them.
Published.toml
Since Sui CLI 1.63, the package manager writes a Published.toml next to Move.toml with an entry per network: published-at, original-id, version, upgrade-capability, the toolchain version and the build config. Commit it to source control. Other packages use it to link against yours, and sui client upgrade reads the UpgradeCap from it.
mainnet and testnet are built-in environments. For localnet or devnet, use sui client test-publish instead, which records addresses in an ephemeral Pub.<env>.toml file that you shouldn't commit:
sui client test-publish --build-env testnetIf you see Your active environment is not present in Move.toml, this is usually why.
Calling it
sui client call --package 0x<PACKAGE_ID> --module counter --function increment --args 0x<COUNTER_ID>More on this in calling Move functions from the CLI.
Gotchas
- Publishing can't be undone. The package is an immutable object on chain. You can upgrade it with the
UpgradeCap, but old versions stay callable. initruns once, at first publish only. Upgrades don't re-run it.- Protect the
UpgradeCap. Whoever holds it can change your code. For production, hold it in a multisig, restrict its policy, or make the package immutable. See UpgradeCap and upgrade policies. - Multisig publishing:
sui client publish --serialize-unsigned-transactionprints transaction bytes that signers can sign elsewhere. Submit the result withsui client execute-signed-tx. - Verify afterwards:
sui client verify-sourcerebuilds your package with the toolchain it was published with and compares the result to the on-chain bytecode.
Sources
- Publishing Packages, Sui documentation
- Move Package Management, Sui documentation
- Sui Client CLI, Sui documentation
client_commands.rs(PublishArgs), MystenLabs/sui on GitHub