Features
Creating Assets
Last updated January 31, 2026
This guide shows how to create a Core Asset (NFT) on Solana using the Metaplex Core SDK. You'll upload off-chain metadata, create the on-chain Asset account, and optionally add it to a Collection or attach plugins.
What You'll Build
A Core Asset with:
- Off-chain metadata (name, image, attributes) stored on Arweave
- On-chain Asset account with ownership and metadata URI
- Optional: Collection membership
- Optional: Plugins (royalties, freeze, attributes)
Summary
Create a Core Asset by uploading metadata JSON to decentralized storage, then calling create() with the URI. Assets can be minted standalone or into Collections, and can include plugins at creation time.
- Upload metadata JSON to Arweave/IPFS, get a URI
- Call
create()with name, URI, and optional plugins - For collections: pass the
collectionparameter - Costs ~0.0029 SOL per asset
Out of Scope
Token Metadata NFTs (use mpl-token-metadata), compressed NFTs (use Bubblegum), fungible tokens (use SPL Token), and NFT migration.
Quick Start
Jump to: Upload Metadata · Create Asset · With Collection · With Plugins
- Install:
npm install @metaplex-foundation/mpl-core @metaplex-foundation/umi - Upload metadata JSON to get a URI
- Call
create(umi, { asset, name, uri }) - Verify on core.metaplex.com
Prerequisites
- Umi configured with a signer and RPC connection
- SOL for transaction fees (~0.003 SOL per asset)
- Metadata JSON ready to upload (name, image, attributes)
The Creation Process
- Upload off-chain data. Store a JSON file containing name, description, image URL, and attributes. The file must be accessible via a public URI.
- Create on-chain Asset account. Call the
createinstruction with the metadata URI to mint the Asset.
Uploading Off-chain Data
Use any storage service (Arweave, IPFS, AWS) to upload your metadata JSON. Umi provides uploader plugins for common services. See the JSON Schema for all available metadata fields.
import { irysUploader } from '@metaplex-foundation/umi-uploader-irys'
// Configure an uploader (Irys, AWS, etc.)
umi.use(irysUploader())
// Upload image first
const [imageUri] = await umi.uploader.upload([imageFile])
// Upload metadata JSON
const uri = await umi.uploader.uploadJson({
name: 'My NFT',
description: 'This is my NFT',
image: imageUri,
attributes: [
{ trait_type: 'Background', value: 'Blue' },
],
})
Now that you have a URI, you can create the Asset.
Create an Asset
Use the create instruction to mint a new Core Asset.
1import { createUmi } from '@metaplex-foundation/umi-bundle-defaults'
2import { create } from '@metaplex-foundation/mpl-core'
3import { mplCore } from '@metaplex-foundation/mpl-core'
4
5// Initialize UMI
6const umi = createUmi('https://api.devnet.solana.com')
7 .use(mplCore())
8
9// Create a new NFT asset
10const asset = await create(umi, {
11 name: 'My NFT',
12 uri: 'https://example.com/metadata.json'
13}).sendAndConfirm(umi)
14
15console.log('Asset created:', asset.publicKey)
Create an Asset into a Collection
To create an Asset as part of a Collection, pass the collection parameter. The Collection must already exist.
1import { createUmi } from '@metaplex-foundation/umi-bundle-defaults'
2import { create, fetchCollection } from '@metaplex-foundation/mpl-core'
3import { mplCore } from '@metaplex-foundation/mpl-core'
4import { generateSigner, publicKey } from '@metaplex-foundation/umi'
5
6// Initialize UMI
7const umi = createUmi('https://api.devnet.solana.com')
8 .use(mplCore())
9
10const collectionAddress = publicKey('YOUR_COLLECTION_ADDRESS')
11
12// Fetch the existing collection
13const collection = await fetchCollection(umi, collectionAddress)
14
15// Generate a new keypair for the asset
16const assetSigner = generateSigner(umi)
17
18// Create asset in the collection
19await create(umi, {
20 asset: assetSigner,
21 collection,
22 name: 'Collection Item #1',
23 uri: 'https://example.com/item1.json',
24}).sendAndConfirm(umi)
25
26console.log('Asset created in collection:', assetSigner.publicKey)
See Collections for creating Collections.
Create an Asset with Plugins
Add plugins at creation time by passing them in the plugins array. This example adds the Royalties plugin:
1import { createUmi } from '@metaplex-foundation/umi-bundle-defaults'
2import { create, ruleSet } from '@metaplex-foundation/mpl-core'
3import { mplCore } from '@metaplex-foundation/mpl-core'
4import { generateSigner, publicKey } from '@metaplex-foundation/umi'
5
6// Initialize UMI
7const umi = createUmi('https://api.devnet.solana.com')
8 .use(mplCore())
9
10const creator = publicKey('YOUR_CREATOR_ADDRESS')
11
12// Generate a new keypair for the asset
13const assetSigner = generateSigner(umi)
14
15// Create asset with Royalties plugin
16await create(umi, {
17 asset: assetSigner,
18 name: 'NFT with Royalties',
19 uri: 'https://example.com/metadata.json',
20 plugins: [
21 {
22 type: 'Royalties',
23 basisPoints: 500, // 5%
24 creators: [
25 { address: creator, percentage: 100 },
26 ],
27 ruleSet: ruleSet('None'),
28 },
29 ],
30}).sendAndConfirm(umi)
31
32console.log('Asset created with plugins:', assetSigner.publicKey)
Common Plugins
Here are a few commonly used plugins. See Plugins Overview for the full list.
- Royalties - Creator royalty enforcement
- Freeze Delegate - Allow freezing/unfreezing
- Burn Delegate - Allow burning
- Transfer Delegate - Allow transfers
- Update Delegate - Allow metadata updates
- Attributes - On-chain key/value data See Plugins Overview for the full list.
Common Errors
Asset account already exists
The asset keypair was already used. Generate a new signer:
const assetSigner = generateSigner(umi) // Must be unique
Collection not found
The collection address doesn't exist or isn't a valid Core Collection. Verify the address and that you've created the Collection first.
Insufficient funds
Your payer wallet needs ~0.003 SOL for rent. Fund it with:
solana airdrop 1 <WALLET_ADDRESS> --url devnet
Notes
- The
assetparameter must be a new keypair - you cannot reuse an existing account - If minting to a different owner, pass the
ownerparameter - Plugins added at creation are cheaper than adding them after (one transaction vs two)
- Use
commitment: 'finalized'when creating assets in a script that immediately fetches them
Quick Reference
Program ID
| Network | Address |
|---|---|
| Mainnet | CoREENxT6tW1HoK8ypY1SxRMZTcVPm7R94rH4PZNhX7d |
| Devnet | CoREENxT6tW1HoK8ypY1SxRMZTcVPm7R94rH4PZNhX7d |
Minimum Code
import { generateSigner } from '@metaplex-foundation/umi'
import { create } from '@metaplex-foundation/mpl-core'
const asset = generateSigner(umi)
await create(umi, { asset, name: 'My NFT', uri: 'https://...' }).sendAndConfirm(umi)
Cost Breakdown
| Item | Cost |
|---|---|
| Asset account rent | ~0.0029 SOL |
| Transaction fee | ~0.000005 SOL |
| Total | ~0.003 SOL |
FAQ
What's the difference between Core Assets and Token Metadata NFTs?
Core Assets use a single account and cost ~80% less. Token Metadata uses 3+ accounts (mint, metadata, token). Core is recommended for new projects.
Can I create multiple assets in one transaction?
No. Each create instruction creates one asset. For bulk minting, use Core Candy Machine or batch transactions.
Do I need to create a Collection first?
No. Assets can exist without a Collection. However, Collections enable collection-level royalties and operations.
How do I mint to a different wallet?
Pass the owner parameter:
await create(umi, { asset, name, uri, owner: recipientAddress })
What metadata format should I use?
Use the standard NFT metadata format with name, description, image, and optional attributes array. See JSON Schema.
Glossary
| Term | Definition |
|---|---|
| Asset | A Core on-chain account representing an NFT |
| URI | The URL pointing to off-chain metadata JSON |
| Signer | A keypair that signs the transaction (asset must be a signer at creation) |
| Collection | A Core account that groups related Assets |
| Plugin | A modular extension adding behavior to an Asset |
| Rent | SOL required to keep an account alive on Solana |
