@mysten/sui v2.0 and a new dApp Kit are here! Check out the migration guide
Mysten Labs SDKs

Sui TypeScript Codegen

The @mysten/codegen package automatically generates type-safe TypeScript code from your Move packages, enabling seamless interaction with your smart contracts from TypeScript applications.

This package is currently in development and may have breaking changes.

Features

  • Type-safe Move calls: Generate TypeScript functions with full type safety for calling your Move functions
  • BCS type definitions: Automatic BCS struct definitions for parsing on-chain data
  • Auto-completion: IDE support with intelligent code completion for Move function arguments
  • Package resolution: Support for both MVR-registered packages and local packages

Installation

Install the codegen package as a dev dependency:

npm install -D @mysten/codegen

Quick Start

1. Create a configuration file

Create a sui-codegen.config.ts file in your project root:

import type { SuiCodegenConfig } from '@mysten/codegen';

const config: SuiCodegenConfig = {
	output: './src/contracts',
	packages: [
		{
			package: '@local-pkg/counter',
			path: './move/counter',
		},
	],
};

export default config;

2. Generate TypeScript code

Add a script to your package.json:

{
	"scripts": {
		"codegen": "sui-ts-codegen generate"
	}
}

Then run:

pnpm codegen

This generates TypeScript code in your configured output directory (e.g., ./src/contracts).

Configuration Options

The SuiCodegenConfig type supports the following options:

OptionTypeDefaultDescription
outputstringThe directory where generated code will be written
packagesPackageConfig[]Array of Move packages to generate code for
prunebooleantrueWhen enabled, only generates code for the main package and omits dependency modules (dependency types referenced by included types are still generated under deps/)
generateSummariesbooleantrueAutomatically run sui move summary before generating code. Creates a package_summaries directory in your Move package which can be added to .gitignore
generateGenerateOptionsDefault generate options (types, functions) for all packages
importExtension'.js' | '.ts' | '''.js'File extension used in generated import statements

Package Configuration

Each entry in the packages array configures a Move package to generate code from. Packages can be local (from source) or on-chain (fetched from a network).

Local Packages

OptionTypeRequiredDescription
packagestringyesPackage identifier (e.g., @local-pkg/my-package)
pathstringyesPath to the Move package directory
packageNamestringnoCustom name for generated code directory
generatePackageGenerateOptionsnoControl what gets generated from this package
{
  package: '@local-pkg/my-package',
  path: './move/my-package',
}

On-Chain Packages

For packages already deployed on-chain, generate code directly from a package ID or MVR name without needing local source code:

OptionTypeRequiredDescription
packagestringyesPackage ID or MVR name
packageNamestringyesName for the generated code directory
network'mainnet' | 'testnet'yesNetwork to fetch the package from
generatePackageGenerateOptionsnoControl what gets generated from this package
{
  package: '0xabf837e98c26087cba0883c0a7a28326b1fa3c5e1e2c5abdb486f9e8f594c837',
  packageName: 'pyth',
  network: 'testnet',
}

The generate option

The generate option controls what code is produced. It can be set at the global level (as a default for all packages), at the per-package level, and at the per-module level. More specific settings override less specific ones.

When no generate option is set, everything is generated (all types and functions). Package-level types and functions also default to true. In the record form of modules, per-module types and functions default to false — you opt in to exactly what you need from each module. Use true as a shorthand to include everything from a module with package-level defaults.

At the global and package levels, types and functions only accept boolean values (or an object for functions). Name-based filtering with string[] is only available at the module level inside the record form of modules, where the filter applies unambiguously to a single module.

// Global or package level
generate: {
  types: true | false,
  functions: true | false | { private: boolean | 'entry' },
  modules: string[] | Record<string, true | { types?, functions? }>,  // package-level only
}

// Module level (inside the record form of modules)
modules: {
  my_module: true,  // shorthand for "include everything"
  other_module: {
    types: true | false | string[],
    functions: true | false | string[] | { private: boolean | 'entry' },
  }
}

Types

Controls which BCS type definitions (structs and enums) are generated:

  • true — generate all types
  • false — skip type generation
  • string[] — generate only the listed types by name (module level only)

Functions

Controls which Move function wrappers are generated:

  • true — generate all public functions and private entry functions
  • false — skip function generation
  • string[] — generate only the listed functions by name; includes private functions (module level only)
  • { private: 'entry' } — generate public functions plus private entry functions
  • { private: true } — generate all functions including private
  • { private: false } — only generate public functions

Modules

Controls which modules from the package are included. Only available at the package level, not at the global level.

  • Not set (default) — include all modules
  • string[] — only include the listed modules
  • Record<string, true | { types?, functions? }> — only include the listed modules, with per-module overrides for types and functions. Use true as a shorthand to include everything from a module with package-level defaults

Examples

Only generate code from specific modules of the Sui framework:

{
  package: '0x0000000000000000000000000000000000000000000000000000000000000002',
  packageName: '0x2',
  network: 'testnet',
  generate: {
    modules: ['kiosk', 'kiosk_extension', 'transfer_policy'],
  },
}

Only generate a single type from a dependency (functions are omitted automatically since generate is configured and functions is not specified):

{
  package: '0xabf837e98c26087cba0883c0a7a28326b1fa3c5e1e2c5abdb486f9e8f594c837',
  packageName: 'pyth',
  network: 'testnet',
  generate: {
    modules: {
      state: { types: ['State'] },
    },
  },
}

Generate specific types and functions from individual modules:

{
  package: '@local-pkg/my-package',
  path: './move/my-package',
  generate: {
    modules: {
      token: {
        types: ['Token', 'TokenMetadata'],
        functions: ['mint', 'burn', 'transfer'],
      },
      admin: {
        types: true,
        functions: ['initialize'],
      },
    },
  },
}

Generate all types but include all private functions for a local package:

{
  package: '@local-pkg/my-package',
  path: './move/my-package',
  generate: {
    functions: { private: true },
  },
}

Dependency pruning

The global prune option (default: true) controls whether dependency packages are included in the output. Even when pruning is enabled, dependency types referenced by your included types are still generated under deps/:

src/contracts/
├── mypackage/
│   ├── module_a.ts
│   ├── module_b.ts
│   └── deps/
│       └── 0x2/
│           └── balance.ts     # Auto-included dependency type
└── utils/
    └── index.ts               # Shared utilities (always generated)

Set prune: false to generate all dependency modules with their full types and functions.

Using Generated Code

Calling Move Functions

The generated code provides type-safe functions for calling Move functions:

import { Transaction } from '@mysten/sui/transactions';
import * as counter from './contracts/counter/counter';

// Increment a counter
const tx = new Transaction();
tx.add(
	counter.increment({
		arguments: {
			counter: '0x123...', // Counter object ID
		},
	}),
);

Parsing BCS Data

Use generated BCS types to parse on-chain object data with the core API:

import { Counter as CounterStruct } from './contracts/counter/counter';

async function readCounter(id: string) {
	const { response } = await client.ledgerService.getObject({
		objectId: id,
		readMask: {
			paths: ['*'],
		},
	});

	if (!response.object?.contents?.value) {
		throw new Error('Expected a move object with contents');
	}

	// Parse with generated BCS type
	const parsed = CounterStruct.parse(response.object.contents.value);
	console.log('Counter value:', parsed.value);
	console.log('Counter owner:', parsed.owner);

	return parsed;
}

Client Configuration

Using with MVR (Move Version Registry)

If your package is registered on MVR, the generated code works without additional configuration.

Local Packages

For local packages using @local-pkg/* identifiers, configure your client with package overrides:

import { SuiGrpcClient } from '@mysten/sui/grpc';

const client = new SuiGrpcClient({
	network: 'testnet',
	baseUrl: 'https://fullnode.testnet.sui.io:443',
	mvr: {
		overrides: {
			packages: {
				'@local-pkg/counter': '0xYOUR_PACKAGE_ID',
			},
		},
	},
});

With dApp Kit

Configure package overrides when creating your dApp Kit instance:

import { createDAppKit } from '@mysten/dapp-kit-core';
import { SuiGrpcClient } from '@mysten/sui/grpc';

const GRPC_URLS = {
	testnet: 'https://fullnode.testnet.sui.io:443',
};

const PACKAGE_IDS = {
	testnet: {
		counter: '0xYOUR_PACKAGE_ID',
	},
};

const dAppKit = createDAppKit({
	networks: ['testnet'],
	createClient: (network) => {
		return new SuiGrpcClient({
			network,
			baseUrl: GRPC_URLS[network],
			mvr: {
				overrides: {
					packages: {
						'@local-pkg/counter': PACKAGE_IDS[network].counter,
					},
				},
			},
		});
	},
});

On this page