suideveloper
All questions
Sui Move

What is the difference between entry and public functions in Sui Move?

November 4, 2026

A public function can be called from other modules, other packages and directly from a transaction, so it is the default way to expose functionality. entry is not a visibility level: it is a modifier that makes a non-public (private or public(package)) function callable as a transaction command while keeping it out of other packages' reach. In exchange, the arguments to a non-public entry function are statically checked so they can't be tangled up with an unresolved hot potato from earlier in the same transaction.

Side by side

Move
module book::shop;

// Callable from transactions, other modules and other packages.
public fun buy(/* ... */) { }

// Callable only as a transaction command (and from this module).
entry fun withdraw_all(/* ... */) { }

// Callable from this package and from transactions, not other packages.
public(package) entry fun admin_reset(/* ... */) { }

// Callable only inside this module.
fun helper() { }
Other packages can call it Transaction can call it Arguments checked for hot potatoes
public fun yes yes no
public(package) fun no (same package only) no n/a
entry fun (private) no yes yes
public(package) entry fun no (same package only) yes yes
fun (private) no no n/a

Both public and non-public entry functions can be called from a programmable transaction block or with sui client call.

When to use each

Use public for almost everything. A public function can be a step in a PTB, combined freely with other commands, and used as a building block by other packages. The Move Book calls this "the default - and recommended - way to expose functionality".

Use a non-public entry function when you deliberately want to limit composability:

  • The function should only ever be a top-level transaction command, never wrapped by someone else's package.
  • You want the guarantee about arguments described below.

Keep in mind that public is a long-term commitment: package upgrades must keep existing public function signatures unchanged, while non-public signatures, including entry and public(package) ones, can change. See package upgrades.

The hot potato guarantee

A hot potato is a value with neither store nor drop, such as a flash-loan receipt that must be repaid before the transaction ends. Since Sui v1.62, the arguments to a non-public entry function must not be "entangled" with any hot potato still outstanding in the transaction. The check runs before execution; a transaction that breaks it fails verification and isn't executed.

Concretely, if a PTB borrows a Balance from a flash lender, turns it into a Coin, and passes that coin to your private entry fun spend(coin: &mut Coin<SUI>) before the loan is repaid, the transaction is rejected. Repay first, and the same call is valid. Taking a shared object by value also taints the values used with it, so a non-public entry function can't take anything that previously interacted with a by-value shared object in that transaction.

public entry is redundant

Older code often uses public entry fun. Today entry adds nothing to a public function, and the compiler warns about it:

Text
warning[Lint W99010]: unnecessary `entry` on a `public` function

Drop entry from public functions, or drop public if you meant to restrict callers.

Other details

  • entry places no restrictions on the function's signature; any Move function can be marked entry.
  • init can't be entry (see how init works).
  • Test code (#[test] and #[test_only]) can call entry functions regardless of their visibility.

Sources

More on sui move