---
title: "Migrate to Move 2024"
description: "Move 2024 offers new features, including method syntax, positional fields, and loop labels."
author: "Sam Blackshear"
datePublished: 2024-04-03
dateModified: 2026-07-30
category: "Developer Resources"
readTime: "6 min"
canonical: https://www.sui.io/blog/move-2024-migration-guide
---

# Migrate to Move 2024

Migrating to the [Move 2024 edition](https://blog.sui.io/move-edition-2024-update/) introduces changes that make Move easier to write, and hopefully easier to read. The relatively few breaking changes in the source language better position Move to handle future advancements.

Many of these changes enhance the source language, affecting the compiler without requiring any changes to the binary representation published on chain.

Existing code will continue to compile, even with the addition of these new features. And because these features are opt-in, you can write your packages with the new features, even if your dependencies do not include them. Opting to take advantage of the new features in your current modules, however, introduces a few breaking changes.

Read our [migration guide on GitHub](https://github.com/tnowacki/sui/blob/ccbf0c4b86112886abbbea25b7991dd5decd1f0f/docs/content/guides/developer/advanced/move-2024-migration.mdx) for full details.

# How to migrate

To migrate a project to Move 2024 Beta, you have two options:

1.  Delete your existing `Move.lock` file (if one exists) to make sure you're using the newest `sui-framework` version.
2.  Run `sui move migrate` in the root of your Move project. See the [Automatic migration](https://github.com/tnowacki/sui/blob/ccbf0c4b86112886abbbea25b7991dd5decd1f0f/docs/content/guides/developer/advanced/move-2024-migration.mdx#automatic-migration-automatic-migration) section of the migration guide for more information.
    1.  Alternatively, update your `Move.toml` file's `[package]` entry to include `edition = "2024.beta"`. If you do this, you might receive a number of new errors as part of our [breaking changes](https://github.com/tnowacki/sui/blob/ccbf0c4b86112886abbbea25b7991dd5decd1f0f/docs/content/guides/developer/advanced/move-2024-migration.mdx#breaking-changes).

## **Automatic migration** 

Move 2024 includes an automatic migration script that you can use by calling `sui move migrate` in the root of your Move project. Upon running, your console prompts you for which Move edition to use. If you select `2024.beta`, the script invokes the compiler and attempts to automatically update your code to avoid the [breaking changes](https://github.com/tnowacki/sui/blob/ccbf0c4b86112886abbbea25b7991dd5decd1f0f/docs/content/guides/developer/advanced/move-2024-migration.mdx#breaking-changes) the update introduces (including marking structs as `public`, mutable variables with the `mut` keyword, avoiding restricted keywords, swapping `friends` for `public(package)`, and even updating paths to global paths in many cases).

After this script runs, your console displays a diff of the changes the script intends to make. If you accept the changes, the script updates your code and your `Move.toml` file automatically. You are now using Move 2024 Beta.

# New features

Here is a brief overview of some of the new features in Move 2024.

## Method syntax

You can call certain functions now as methods using the `.` syntax. For example, the following call:

`vector::push_back(&mut v, coin::value(&c));`

can now be written as:

`v.push_back(c.value());`

Where the receiver of the method (`v` and `c` in this example) is automatically borrowed if necessary (as `&mut v` and `&c` respectively).

You can call any function defined in the same module as the receiver's type as a method if it takes the receiver as its first argument.

For functions defined outside the module, you can declare methods using `public use fun` and `use fun`.

## Index syntax

With method syntax, you can annotate certain functions as being `#[syntax(index)]` methods. You then call these methods using `v[i]`\-style calls.

For example,

`*&mut v[i] = v[j];`

resolves to

`*vector::borrow_mut(&mut v, i) = *vector::borrow(&v, j);`

## `public(package)`

`friend` declarations, and the associated `public(friend)` visibility modifiers, are deprecated. In their place is the `public(package)` visibility modifier, which allows calling functions only within the same package where they are defined.

## Positional fields

You can now define structs with positional fields, which are accessed by a zero-based index. For example,

`public struct Pair(u64, u64) has copy, drop, store;`

then to access each field,

`public fun sum(p: &Pair): u64 {     p.0 + p.1   }`

And as this example shows, you can now declare abilities after the struct field list.

## Nested use and standard library defaults

You can now nest `use` aliases for more conciseness.

`use sui::{balance, coin::{Self, Coin}};`

Additionally, the following use declarations are now automatically included in every module:

`use std::vector;   use std::option::{Self, Option};   use sui::object::{Self, ID, UID};   use sui::transfer;   use sui::tx_context::{Self, TxContext};`

## Automatic referencing in equality

Equality operations, `==` and `!=`, now automatically borrow if one side is a reference and the other is not. For example,

`fun check(x: u64, r: &u64): bool {     x == r   }`

is equivalent to

`fun check(x: u64, r: &u64): bool {     &x == r   }`

This automatic borrowing can occur on either side of `==` and `!=`.

## Loop labels

When nesting loops, it can be convenient to break to the outer loop. For example,

`let mut i = 0;   let mut j = 0;   let mut terminate_loop = false;   while (i < 10) {       while (j < 10) {           if (haystack(i, j) == needle) {               terminate_loop = true;               break;           };           j = j + 1;       };       if (terminate_loop) break;       i = i + 1;   }`

Now, you can directly name the outer loop (`outer` in this case) and break it all at once:

`let mut i = 0;   let mut j = 0;   'outer: while (i < 10) {       while (j < 10) {           if (haystack(i, j) == needle) break'outer;           j = j + 1;       };       i = i + 1;   }`

## `break` with value

It's now possible to break with a value from a loop. For example,

`let mut i = 0;   let x: u64 = loop {       if (v[i] > 10) break i;       i = i + 1;   };`

You can achieve this with labels, as well. For example,

`let mut i = 0;   let mut j = 0;   let item = 'outer: loop {       while (j < 10) {           let item = haystack(i, j);           if (item == needle) break'outer option::some(item);           j = j + 1;       };       i = i + 1;       if (i == 10) break option::none();   };`

# Breaking changes 

Breaking changes are, unfortunately, a growing pain in Move 2024. We anticipate these changes to be minimally invasive and provided a migration script to automate them in most cases. In addition, these changes pave the way for new features still to come in Move 2024.

## Datatype visibility requirements

Currently, all structs in Move are, by convention, public: any other module or package can import them and refer to them by type. To make this clearer, Move 2024 requires that all structs be declared with the public keyword. For example,

`// legacy code   struct S { x: u64 }      // Move 2024 code   public struct S { x: u64 }`

Any non-public struct produces an error at this time, although the Move team is working on new visibility options for future releases.

## Mutability requirements

Previously, all variables in Move were implicitly mutable. For example,

`fun f(s: S, y: u64): u64 {       let a = 0;       let S { x } = s;       a = 1;       x = 10;       y = 5;       x + y   }`

Now, you must declare mutable variables explicitly:

`fun f(s: S, mut y: u64): u64 {       let mut a = 0;       let S { mut x } = 5;       a = 1;       x = 10;       y = 5;       x + y   }`

The compiler now produces an error if you attempt to reassign or borrow a variable mutably without this explicit declaration.

## Removing friends and `public(friend)`

Friends and the `public(friend)` visibilities were introduced early in Move's development, predating even the package system. As indicated in the [public(package)](https://github.com/tnowacki/sui/blob/ccbf0c4b86112886abbbea25b7991dd5decd1f0f/docs/content/guides/developer/advanced/move-2024-migration.mdx#public-package) section, `public(package)` deprecates `public(friend)` in Move 2024.

The following declaration now produces an error:

`module pkg::m {       friend pkg::a;       public(friend) fun f() { ... }   }      module pkg::a {       fun calls_f() { ... pkg::m::f() ... }   }`

Instead, if you want your function to be visible only in the package, write:

`module pkg::m {       public(package) fun f() { ... }   }      module pkg::a {       // this now works directly       fun calls_f() { ... pkg::m::f() ... }   }`

## New keywords

Looking toward the future, Move 2024 Beta adds the following keywords to the language: `enum`, `for`, `match`, `mut`, and `type`. The compiler, unfortunately, now produces parsing errors when it finds these in other positions. This is a necessary change as the language matures. If you perform automatic migration, the migration tool renames these as `enum` and so on, rewriting the code to use these escaped forms.

## Revised paths and namespaces

Move 2024 revises how paths and namespaces work compared to legacy Move, toward easing `enum` aliasing in the future. Consider the following snippet from a test annotation in the `sui_system` library:

`use sui_system::sui_system;      ...      #[expected_failure(abort_code = sui_system::validator_set::EInvalidCap)]`

Legacy Move would always treat a three-part name as an address (`sui_system`), module (`validator_set`), and module member (`EInvalidCap`). Move 2024 respects scope for `use`, so `sui_system` in the attribute resolves to the module, producing a name resolution error overall.

To avoid cases where this is the intended behavior, Move 2024 introduces a prefix operation for global qualification. To use it, you can rewrite this annotation as:

``use sui_system::sui_system;      ...      #[expected_failure(abort_code = ::sui_system::validator_set::EInvalidCap)]                                // ^ note `::` here``

The migration script attempts to remediate naming errors using global qualification when possible.

# Follow along

The beta release of Move 2024 comes with some powerful new features beyond the breaking changes described here. There are also more on the horizon. Join the [Sui newsletter](https://sui.io/developers#newsletter) to learn about new, exciting features coming to Move this year, including syntactic macros, enums with pattern matching, and other user-defined syntax extensions.

Please, provide any feedback or report any issues you encounter via [GitHub](https://github.com/MystenLabs), [Discord](https://discord.com/channels/916379725201563759/925109817834631189), or the [Sui Developer Forums](https://forums.sui.io/).
