Skip to content

Bytecode Version History

The Move bytecode format carries a version number in every compiled module. The VM uses this version to decide which features are available during verification and execution. This page documents the changes introduced in each version from v5 (the minimum the VM accepts) through v10 (the latest).

VersionDefault ForKey Additions
v5— (minimum supported)Baseline instruction set
v6Internal refactoring; no new user-facing features
v7Enum types and variant instructions
v8First-class closures
v9Language v1 (default)Signed integer types (i8..i256)
v10Language v2.4, v2.5AbortMsg instruction (abort with message)

Version 5 is the minimum bytecode version the Aptos Move VM accepts. It defines the baseline instruction set, the module binary layout, and the core type system. All instructions present before v7 belong to this baseline.

Modules compiled at v5 can use the full set of unsigned integer types (u8, u16, u32, u64, u128, u256), structs with abilities, generics, global storage operations, and vector instructions. See the Instruction Set Reference for the complete baseline instruction list.

Version 6 introduced internal changes to the binary format but did not add any new instructions, table types, or signature tokens visible to Move authors. Modules compiled at v6 are functionally equivalent to v5 modules from a developer perspective.

Version 7 added enum types (also called variants) to the Move bytecode. Enums allow a single type to hold one of several named variants, each with its own fields — similar to Rust enums or algebraic data types in functional languages.

InstructionOpcodeDescription
PackVariant0x52Create a variant value with the given fields
PackVariantGeneric0x53Generic version of PackVariant
UnpackVariant0x54Destructure a variant, pushing its fields onto the stack
UnpackVariantGeneric0x55Generic version of UnpackVariant
TestVariant0x56Test whether a value is a specific variant; pushes bool
TestVariantGeneric0x57Generic version of TestVariant
ImmBorrowVariantField0x4EBorrow a variant field immutably
MutBorrowVariantField0x4FBorrow a variant field mutably
ImmBorrowVariantFieldGeneric0x50Generic version of ImmBorrowVariantField
MutBorrowVariantFieldGeneric0x51Generic version of MutBorrowVariantField

These table types store metadata about enum variants and their fields:

Table TypeCodePurpose
VARIANT_FIELD_HANDLES0x11Maps variant field references to their parent variant and field index
VARIANT_FIELD_INST0x12Instantiations of generic variant field handles
STRUCT_VARIANT_HANDLES0x13Maps variant references to their parent struct definition and variant index
STRUCT_VARIANT_INST0x14Instantiations of generic struct variant handles

With v7, Move developers can define types like:

enum Color {
Red,
Green,
Blue,
Custom { r: u8, g: u8, b: u8 },
}

The compiler emits PackVariant / UnpackVariant instructions to construct and destructure these values, and TestVariant to implement pattern matching. See the Move Book — Enums for the source-level reference.

Version 8 added first-class closures to Move bytecode. Closures capture values from their environment and can be passed as function arguments, enabling higher-order programming patterns.

InstructionOpcodeDescription
PackClosure0x58Create a closure that captures specified stack values and binds them to a function
PackClosureGeneric0x59Generic version of PackClosure
CallClosure0x5AInvoke a closure, pushing its return values onto the stack

Version 8 introduced the Function signature token, which represents the type of a closure or function reference. A Function token carries:

  • A list of parameter types
  • A list of return types
  • An ability set that constrains how the closure can be used

This token appears in signatures wherever a closure type is expected, such as function parameters that accept callbacks.

Closures allow patterns like passing a comparison function to a sorting routine or creating callbacks that carry captured state. The Function signature token gives the type system full visibility into closure types, so the bytecode verifier can enforce type safety and ability constraints on closures just as it does on structs.

Version 9 added signed integer types to Move. Previously, Move supported only unsigned integers (u8 through u256). Version 9 introduced six signed counterparts along with arithmetic negation.

InstructionOpcodeDescription
LdI80x5BLoad a signed 8-bit integer constant
LdI160x5CLoad a signed 16-bit integer constant
LdI320x5DLoad a signed 32-bit integer constant
LdI640x5ELoad a signed 64-bit integer constant
LdI1280x5FLoad a signed 128-bit integer constant
LdI2560x60Load a signed 256-bit integer constant
InstructionOpcodeDescription
CastI80x61Cast the top of stack to i8
CastI160x62Cast the top of stack to i16
CastI320x63Cast the top of stack to i32
CastI640x64Cast the top of stack to i64
CastI1280x65Cast the top of stack to i128
CastI2560x66Cast the top of stack to i256
InstructionOpcodeDescription
Negate0x67Arithmetic negation; pops a signed integer and pushes its negation

Six new signature tokens represent signed integer types in the type system:

  • I8 — signed 8-bit integer
  • I16 — signed 16-bit integer
  • I32 — signed 32-bit integer
  • I64 — signed 64-bit integer
  • I128 — signed 128-bit integer
  • I256 — signed 256-bit integer

These tokens appear in function signatures, struct field definitions, and local variable types wherever signed integers are used.

Signed integers support negative values and two’s complement arithmetic, which simplifies financial calculations, coordinate math, and any domain where negative numbers are natural. Version 9 is the default bytecode version for the standard Move language configuration.

Version 10 added the abort-with-message instruction, which allows a transaction to abort with a human-readable error string in addition to the numeric abort code.

InstructionOpcodeDescription
AbortMsg0x68Abort execution with a u64 error code and an optional UTF-8 message string

Before v10, abort only accepted a numeric code, making it difficult to diagnose failures without consulting the module source. With AbortMsg, modules can include descriptive error messages that appear in transaction output, greatly improving debuggability. Version 10 is the default bytecode version for Move language v2.4 and v2.5.

  • The VM accepts bytecode from v5 through the current maximum version (v10 at the time of writing). Modules compiled at any supported version can coexist on-chain and call each other.
  • When a module declares an older bytecode version, the verifier rejects instructions and types introduced in later versions. For example, a module at v6 cannot use PackVariant (a v7 instruction).
  • The bytecode version is encoded as a little-endian u32 in bytes 4 through 7 of the module binary header, immediately after the magic bytes. See the Module Binary Format page for a full description of the header layout.
  • Publishing a module with a version newer than the VM supports causes the transaction to fail during verification.