# Upgrading Packages

*[Documentation index](/llms.txt) · [Full index](/llms-full.txt)*

Sui smart contracts are immutable package objects consisting of a collection of Move modules. Because packages are immutable, a transaction identifies a package version by its package ID rather than passing it as a versioned object input. If packages were mutable, they would be [shared objects](/develop/objects/object-ownership/shared), and every call into a package would contend on that object.

The inability to change packages, however, becomes a problem when considering the iterative nature of code development. Builders require the ability to update their code and pull changes from other developers while keeping the properties that immutability provides. The Sui network provides a method for upgrading your packages while still retaining their immutable properties.

## Upgrade considerations

Consider the following details before upgrading your packages.

**Module initializers do not re-run with package upgrades.** When you publish your initial package, Move runs the `init` function you define for the package once (and only once) at the time of the publish event. Any `init` functions you might include in subsequent versions of your package are ignored. See the [module initializer section](https://move-book.com/programmability/module-initializer) in The Move Book for more information.

You cannot delete old packages from the network. Nothing prevents other packages from accessing the methods and types defined in the old versions of your upgraded packages. Because a transaction identifies a package version by its package ID, any transaction or package that references an old version's package ID can still call it.

## Which changes are compatible with a package upgrade?

To upgrade a package, your package must satisfy the following requirements:

- You must have an `UpgradeTicket` for the package you want to upgrade. The Sui network issues `UpgradeCap`s when you publish a package, then you can issue `UpgradeTicket`s as the owner of that `UpgradeCap`. After a successful upgrade, the `UpgradeReceipt` from the upgrade is used to update the `UpgradeCap`. The Sui Client CLI handles this requirement automatically.

- Your changes must be layout-compatible with the previous version. A change is layout-compatible only if it follows these rules:

  - Existing `public` function signatures must remain the same.

  - Existing struct layouts, including struct abilities, must remain the same.

  - You can add new structs and functions.

  - You can remove generic type constraints from existing functions (public or otherwise).

  - You can change function implementations.

  - You can change non-`public` function signatures, including `public(package)` and `entry` function signatures.

The `sui client upgrade` command checks these requirements and alerts you if the new package doesn't satisfy them.

:::info

If you have a package with a dependency, and that dependency is upgraded, your package does not automatically depend on the newer version. You must explicitly upgrade your own package to point to the new dependency.

:::

## How do I upgrade a package?

Use the `sui client upgrade` command to upgrade packages that meet the previous requirements, providing values for the following flags:

:::tip

Beginning with the Sui `v1.24.1` [release](https://github.com/MystenLabs/sui/releases/tag/mainnet-v1.24.1), the `--gas-budget` option is no longer required for CLI commands.

:::

- `--gas-budget`: The maximum number of gas units that can be expended before the network cancels the transaction.
- `--upgrade-capability` (or `-c`): The ID of the `UpgradeCap`. You receive this ID as a return from the publish command.

Developers upgrading packages using Move code have access to types and functions to define [custom upgrade policies](/develop/publish-upgrade-packages/custom-policies). For example, a Move developer might want to disallow upgrading a package, regardless of the current package owner. The [`make_immutable` function](https://github.com/MystenLabs/sui/blob/main/crates/sui-framework/docs/sui/package.md#0x2_package_make_immutable) is available to them to create this behavior. More advanced policies using available types like `UpgradeTicket` and `UpgradeReceipt` are also possible. For an example, see this [custom upgrade policy](https://github.com/MystenLabs/sui/issues/2045#:~:text=Implement%20a%20custom%20upgrade%20policy) on GitHub. After you apply a restriction to a package's upgrade policy, you cannot widen it again.

When you use the Sui client CLI, the `upgrade` command handles generating the upgrade digest, authorizing the upgrade with the `UpgradeCap` to get an `UpgradeTicket`, and updating the `UpgradeCap` with the `UpgradeReceipt` after a successful upgrade. To learn more about these processes, see the Move documentation for the [package module](https://github.com/MystenLabs/sui/blob/main/crates/sui-framework/docs/sui/package.md).

The upgrade objects work together in this order:

1. When you publish a package, the `Publish` command returns an `UpgradeCap`, and `sui client publish` transfers it to your address.

1. As the `UpgradeCap` owner, you authorize the upgrade with the `UpgradeCap` to get an `UpgradeTicket` (the `authorize_upgrade` call in the [example](#example) output).

1. The `Upgrade` command in the same transaction consumes the `UpgradeTicket` and returns an `UpgradeReceipt`.

1. The `UpgradeReceipt` updates the `UpgradeCap` after the upgrade succeeds (the `commit_upgrade` call in the [example](#example) output).

:::tip Secure upgrade checklist

Before you run an upgrade:

- Verify the old and new package IDs and the upgrade `digest`.
- Confirm your dependencies resolve to the expected package IDs.
- Confirm `UpgradeCap` custody (ideally multisig or timelock).

When the upgrade changes shared object access:

- Ensure the `migrate` function is authorized (for example, behind an `AdminCap`).
- Emit a migration event for observability.
- Know when to call [`make_immutable`](/develop/publish-upgrade-packages/custom-policies) to relinquish upgrade authority.

See [Security Best Practices](/develop/security/best-practices) for more.

:::

## How do I migrate users to the latest version?

By default, users can choose to keep using the old version of a package, as well. As a package developer, you must be aware of and account for this possibility.

For example, you might define an `increment` function in your original package:

```move
public fun increment(c: &mut Counter) {
    c.value = c.value + 1;
}
```

Then, your package upgrade might add an emit event to the `increment` function:

```move
public struct Progress has copy, drop {
    reached: u64
}

public fun increment(c: &mut Counter) {
    c.value = c.value + 1;

    if (c.value % 100 == 0) {
        event::emit(Progress { reached: c.value });
    }
}
```

If callers use both the old and upgraded `increment` function, the process fails because the old function is not aware of the `Progress` event.

You might also run into issues maintaining dynamic fields that need to remain in sync with a struct's original fields. To address these issues, you can introduce a new type as part of the upgrade and port users over to it, breaking backwards compatibility. For example, if you're using owned objects to demonstrate proof like proof of ownership, and you develop a new version of your package to address problematic code, you can introduce a new type in the upgraded package. You can then add a function to your package that trades old objects for new ones. Because your logic only recognizes objects with the new type, you effectively force users to update.

Another example: you discover a shared object in your package has flawed logic. You want users to use only the corrected object from the upgraded package, so you add a new type and migration function. This requires 2 transactions: 1 for the upgrade and 1 to set up the new shared object. Protect the setup function by creating an `AdminCap` object to ensure only you, as the package owner, can initiate it. You might also include a flag in the shared object to toggle its enabled state, preventing public access during migration. Create this flag proactively if you anticipate future migrations, not in response to flawed logic.

### Versioned shared objects

When you create packages that involve shared objects, think about upgrades and versioning from the start because all prior versions of a package still exist onchain. Without a version check, callers can keep calling the old version of a function, such as the original `increment`, on the same shared object. A useful pattern is to introduce versioning to the shared object and use a version check to guard access to functions in the package. This limits access to the shared object to the latest package version.

Using the earlier `counter` example:

```move
module example::counter;

public struct Counter has key {
    id: UID,
    value: u64,
}

fun init(ctx: &mut TxContext) {
    transfer::share_object(Counter {
        id: object::new(ctx),
        value: 0,
    })
}

public fun increment(c: &mut Counter) {
    c.value = c.value + 1;
}
```

To ensure that upgrades to this package can limit access of the shared object to the latest version of the package, you must:

1. Track the current version of the module in a constant, `VERSION`.

1. Track the current version of the shared object, `Counter`, in a new `version` field.

1. Introduce an `AdminCap` to protect privileged calls, and associate the `Counter` with its `AdminCap` with a new field. You might already have a similar type for shared object administration, in which case you can reuse that. This cap is used to protect calls to migrate the shared object from version to version.

1. Guard the entry of all functions that access the shared object with a check that its `version` matches the package `VERSION`.

An upgrade-aware `counter` module looks like the following:

```move
module example::counter;

/// Not the right admin for this counter
const ENotAdmin: u64 = 0;

/// Calling functions from the wrong package version
const EWrongVersion: u64 = 1;

// 1. Track the current version of the module
const VERSION: u64 = 1;

public struct Counter has key {
    id: UID,
    // 2. Track the current version of the shared object
    version: u64,
    // 3. Associate the `Counter` with its `AdminCap`
    admin: ID,
    value: u64,
}

public struct AdminCap has key {
    id: UID,
}

fun init(ctx: &mut TxContext) {
    let admin = AdminCap { id: object::new(ctx) };

    transfer::share_object(Counter {
        id: object::new(ctx),
        version: VERSION,
        admin: object::id(&admin),
        value: 0,
    });

    transfer::transfer(admin, ctx.sender());
}

public fun increment(c: &mut Counter) {
    // 4. Guard the entry of all functions that access the shared object
    //    with a version check.
    assert!(c.version == VERSION, EWrongVersion);
    c.value = c.value + 1;
}
```

To upgrade a module using this pattern requires making 2 extra changes on top of any implementation changes your upgrade requires:

1. Bump the `VERSION` of the package.

1. Introduce a `migrate` function to upgrade the shared object.

The following module is an upgraded `counter` that emits `Progress` events as originally discussed, but also provides tools for an admin (`AdminCap` holder) to prevent accesses to the counter from older package versions:

```move
module example::counter;

use sui::event;

/// Not the right admin for this counter
const ENotAdmin: u64 = 0;

/// Migration is not an upgrade
const ENotUpgrade: u64 = 1;

/// Calling functions from the wrong package version
const EWrongVersion: u64 = 2;

// 1. Bump the `VERSION` of the package.
const VERSION: u64 = 2;

public struct Counter has key {
    id: UID,
    version: u64,
    admin: ID,
    value: u64,
}

public struct AdminCap has key {
    id: UID,
}

public struct Progress has copy, drop {
    reached: u64,
}

fun init(ctx: &mut TxContext) {
    let admin = AdminCap {
        id: object::new(ctx),
    };

    transfer::share_object(Counter {
        id: object::new(ctx),
        version: VERSION,
        admin: object::id(&admin),
        value: 0,
    });

    transfer::transfer(admin, ctx.sender());
}

public fun increment(c: &mut Counter) {
    assert!(c.version == VERSION, EWrongVersion);
    c.value = c.value + 1;

    if (c.value % 100 == 0) {
        event::emit(Progress { reached: c.value })
    }
}

// 2. Introduce a migrate function
entry fun migrate(c: &mut Counter, a: &AdminCap) {
    assert!(c.admin == object::id(a), ENotAdmin);
    assert!(c.version < VERSION, ENotUpgrade);
    c.version = VERSION;
}
```

Upgrading to this version of the package requires 2 transactions, in this order:

1. Perform the package upgrade. Pass the `UpgradeCap` ID to the `--upgrade-capability` flag:

   ```sh
   $ sui client upgrade --upgrade-capability <UPGRADE-CAP-ID>
   ```

1. In a follow-up transaction, call the upgraded package's `migrate` function, passing the `Counter` and its `AdminCap`. Use the new package ID that the upgrade returns.

The `migrate` function:

- Is an `entry` function and not `public`. You can still call it directly from a transaction, but because it is not `public`, the layout-compatibility rules do not apply to its signature. This allows it to be entirely changed, including changing its signature or removing it entirely, in future upgrades.

- Accepts an `AdminCap` and checks that its ID matches the ID of the counter being migrated, making it a privileged operation.

- Includes a sanity check that the version of the module is actually an upgrade for the object. This helps catch errors such as failing to bump the module version before upgrading.

After a successful upgrade, calls to `increment` on the previous version of the package abort on the version check, while calls on the later version should succeed.

### Extensions

This pattern forms the basis for upgradeable packages involving shared objects, but you can extend it in a number of ways, depending on your package's needs:

- The version constraints can be made more expressive:

  - Rather than using a single `u64`, versions could be specified as a `String`, or a pair of upper and lower bounds.

  - You can control access to specific functions or sets of functions by adding and removing marker types as [dynamic fields](/develop/objects/dynamic-fields) on the shared object.

- The `migrate` function could be made more sophisticated by modifying other fields in the shared object, adding or removing dynamic fields, or migrating multiple shared objects simultaneously.

- You can implement large migrations that need to run over multiple transactions in a 3 phase setup:

  - Disable general access to the shared object by setting its version to a sentinel value (for example, `U64_MAX`), using an `AdminCap`-guarded call.

  - Run the migration over the course of multiple transactions. For example, if a large volume of objects need to be moved, it is best to do this in batches, to avoid hitting transaction limits.

  - Set the version of the shared object back to a usable value.

## Example

Develop a package named `sui_package`. Its manifest (`Move.toml`) looks like the following:

```toml
[package]
name = "sui_package"
```

When your package is ready, you publish it:

```sh
$ sui client publish
```

**Output**

```sh
INCLUDING DEPENDENCY Sui
INCLUDING DEPENDENCY MoveStdlib
BUILDING sui_package
Successfully verified dependencies onchain against source.
Transaction Digest: GPSpH264CjQPaXQPpMHpkzyGidZnQFvd1yUH5s9ncesi
╭──────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
│ Transaction Data                                                                                             │
├──────────────────────────────────────────────────────────────────────────────────────────────────────────────┤
│ Sender: PUBLISHER-ID                                                                                         │
│ Gas Owner: PUBLISHER-ID                                                                                      │
│ Gas Budget: 12298000 MIST                                                                                    │
│ Gas Price: 1000 MIST                                                                                         │
│ Gas Payment:                                                                                                 │
│  ┌──                                                                                                         │
│  │ ID: GAS-COIN-ID                                                                                           │
│  │ Version: 2                                                                                                │
│  │ Digest: QDssxM4QKnhutWCYijiWWmYPtKWnHB9xVaLqPsDHiep                                                       │
│  └──                                                                                                         │
│                                                                                                              │
│ Transaction Kind: Programmable                                                                               │
│ ╭──────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │
│ │ Input Objects                                                                                            │ │
│ ├──────────────────────────────────────────────────────────────────────────────────────────────────────────┤ │
│ │ 0   Pure Arg: Type: address, Value: "PUBLISHER-ID"                                                       │ │
│ ╰──────────────────────────────────────────────────────────────────────────────────────────────────────────╯ │
│ ╭─────────────────────────────────────────────────────────────────────────╮                                  │
│ │ Commands                                                                │                                  │
│ ├─────────────────────────────────────────────────────────────────────────┤                                  │
│ │ 0  Publish:                                                             │                                  │
│ │  ┌                                                                      │                                  │
│ │  │ Dependencies:                                                        │                                  │
│ │  │   0x0000000000000000000000000000000000000000000000000000000000000001 │                                  │
│ │  │   0x0000000000000000000000000000000000000000000000000000000000000002 │                                  │
│ │  └                                                                      │                                  │
│ │                                                                         │                                  │
│ │ 1  TransferObjects:                                                     │                                  │
│ │  ┌                                                                      │                                  │
│ │  │ Arguments:                                                           │                                  │
│ │  │   Result 0                                                           │                                  │
│ │  │ Address: Input  0                                                    │                                  │
│ │  └                                                                      │                                  │
│ ╰─────────────────────────────────────────────────────────────────────────╯                                  │
│                                                                                                              │
│ Signatures:                                                                                                  │
│    4NqP6CL1/LN1Ekr9NeL82PFGgVdEjrwsP82l/0mFvCd9TYO94CKBQAm8C/D6DsAuBrwu4cogQ3Mbh1huGc0yCg==                  │
│                                                                                                              │
╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
╭───────────────────────────────────────────────────────────────────────────────────────────────────╮
│ Transaction Effects                                                                               │
├───────────────────────────────────────────────────────────────────────────────────────────────────┤
│ Digest: GPSpH264CjQPaXQPpMHpkzyGidZnQFvd1yUH5s9ncesi                                              │
│ Status: Success                                                                                   │
│ Executed Epoch: 285                                                                               │
│                                                                                                   │
│ Created Objects:                                                                                  │
│  ┌──                                                                                              │
│  │ ID: ORIGINAL-PACKAGE-ID                                                                        │
│  │ Owner: Immutable                                                                               │
│  │ Version: 1                                                                                     │
│  │ Digest: 4ZvhnDgehkRmzo3mtHjCc6aQkEz1SA87rDpDS6pGarFR                                           │
│  └──                                                                                              │
│  ┌──                                                                                              │
│  │ ID: 0xaa06f409af7a36c20a552e729eb985a9979149ae9ada5ce3ed413836fd12ed16                         │
│  │ Owner: Account Address ( PUBLISHER-ID )                                                        │
│  │ Version: 3                                                                                     │
│  │ Digest: 71G4PuCUoqx1KDTnt8zGMYUf6Qpf4CWgZsDxYN1d7mXE                                           │
│  └──                                                                                              │
│  ┌──                                                                                              │
│  │ ID: UPGRADE-CAP-ID                                                                             │
│  │ Owner: Account Address ( PUBLISHER-ID )                                                        │
│  │ Version: 3                                                                                     │
│  │ Digest: FNxdiGCk1fwXByda6Q2sx8RjuwUQBFYQk7C4Zr2H4qVw                                           │
│  └──                                                                                              │
│ Mutated Objects:                                                                                  │
│  ┌──                                                                                              │
│  │ ID: GAS-COIN-ID                                                                                │
│  │ Owner: Account Address ( PUBLISHER-ID )                                                        │
│  │ Version: 3                                                                                     │
│  │ Digest: 9Fet6LPSBsjYjVMEQxkB4LRHfAJDFCQQ2iUAiUQ5eygF                                           │
│  └──                                                                                              │
│ Gas Object:                                                                                       │
│  ┌──                                                                                              │
│  │ ID: GAS-COIN-ID                                                                                │
│  │ Owner: Account Address ( PUBLISHER-ID )                                                        │
│  │ Version: 3                                                                                     │
│  │ Digest: 9Fet6LPSBsjYjVMEQxkB4LRHfAJDFCQQ2iUAiUQ5eygF                                           │
│  └──                                                                                              │
│ Gas Cost Summary:                                                                                 │
│    Storage Cost: 10298000 MIST                                                                    │
│    Computation Cost: 1000000 MIST                                                                 │
│    Storage Rebate: 978120 MIST                                                                    │
│    Non-refundable Storage Fee: 9880 MIST                                                          │
│                                                                                                   │
│ Transaction Dependencies:                                                                         │
│    3eHwwq6p2xQwBtXDE9KKNQwZFdHUGEKiJsR5LDmv4o7b                                                   │
│    7KAuWTJHCZmh2rMSAqobkhU5cuRBoVicwae78i9woDUK                                                   │
╰───────────────────────────────────────────────────────────────────────────────────────────────────╯
╭─────────────────────────────╮
│ No transaction block events │
╰─────────────────────────────╯

╭────────────────────────────────────────────────────────────────────────────────────────────────────╮
│ Object Changes                                                                                     │
├────────────────────────────────────────────────────────────────────────────────────────────────────┤
│ Created Objects:                                                                                   │
│  ┌──                                                                                               │
│  │ ObjectID: 0xaa06f409af7a36c20a552e729eb985a9979149ae9ada5ce3ed413836fd12ed16                    │
│  │ Sender: PUBLISHER-ID                                                                            │
│  │ Owner: Account Address ( PUBLISHER-ID )                                                         │
│  │ ObjectType: ORIGINAL-PACKAGE-ID::module::TYPE                                                   │
│  │ Version: 3                                                                                      │
│  │ Digest: 71G4PuCUoqx1KDTnt8zGMYUf6Qpf4CWgZsDxYN1d7mXE                                            │
│  └──                                                                                               │
│  ┌──                                                                                               │
│  │ ObjectID: UPGRADE-CAP-ID                                                                        │
│  │ Sender: PUBLISHER-ID                                                                            │
│  │ Owner: Account Address ( PUBLISHER-ID )                                                         │
│  │ ObjectType: 0x2::package::UpgradeCap                                                            │
│  │ Version: 3                                                                                      │
│  │ Digest: FNxdiGCk1fwXByda6Q2sx8RjuwUQBFYQk7C4Zr2H4qVw                                            │
│  └──                                                                                               │
│ Mutated Objects:                                                                                   │
│  ┌──                                                                                               │
│  │ ObjectID: GAS-COIN-ID                                                                           │
│  │ Sender: PUBLISHER-ID                                                                            │
│  │ Owner: Account Address ( PUBLISHER-ID )                                                         │
│  │ ObjectType: 0x2::coin::Coin<0x2::sui::SUI>                                                      │
│  │ Version: 3                                                                                      │
│  │ Digest: 9Fet6LPSBsjYjVMEQxkB4LRHfAJDFCQQ2iUAiUQ5eygF                                            │
│  └──                                                                                               │
│ Published Objects:                                                                                 │
│  ┌──                                                                                               │
│  │ PackageID: ORIGINAL-PACKAGE-ID                                                                  │
│  │ Version: 1                                                                                      │
│  │ Digest: 4ZvhnDgehkRmzo3mtHjCc6aQkEz1SA87rDpDS6pGarFR                                            │
│  │ Modules: example                                                                                │
│  └──                                                                                               │
╰────────────────────────────────────────────────────────────────────────────────────────────────────╯
╭───────────────────────────────────────────────────────────────────────────────────────────────────╮
│ Balance Changes                                                                                   │
├───────────────────────────────────────────────────────────────────────────────────────────────────┤
│  ┌──                                                                                              │
│  │ Owner: Account Address ( PUBLISHER-ID )                                                        │
│  │ CoinType: 0x2::sui::SUI                                                                        │
│  │ Amount: -10319880                                                                              │
│  └──                                                                                              │
╰───────────────────────────────────────────────────────────────────────────────────────────────────╯
```

The result includes an **Object Changes** section with information you need for upgrading: an `UpgradeCap` ID and your package ID.

You can identify the different objects using the `Object.objectType` value in the response. The `UpgradeCap` entry has a value of `String("0x2::package::UpgradeCap")` and the `objectType` for the package reads `String("<PACKAGE-ID>::sui_package::<MODULE-NAME>")`. In the example output, the `UpgradeCap` ID is the `ObjectID` of the entry whose `ObjectType` is `0x2::package::UpgradeCap` (`UPGRADE-CAP-ID`), and the package ID is the `PackageID` under **Published Objects** (`ORIGINAL-PACKAGE-ID`).

After publishing, the package system automatically records the published address and upgrade capability in `Published.toml`. You do not need to manually edit `Move.toml` with addresses or `published-at` values. See [Move Package Management](/develop/manage-packages/move-package-management) for details on how publication tracking works.

After a while, you decide to upgrade your `sui_package` to include some requested features.

Run `sui client upgrade` command to upgrade your package. Pass the `UpgradeCap` ID (the `<UPGRADE-CAP-ID>` value from the example) to the `--upgrade-capability` flag.

```sh
$ sui client upgrade --upgrade-capability <UPGRADE-CAP-ID>
```

The console alerts you if the new package doesn't satisfy the requirements, otherwise the compiler publishes the upgraded package to the network and returns its result.

**Output**

---
*Content truncated for size. See the full page on the documentation site.*
