> ## Documentation Index
> Fetch the complete documentation index at: https://docs.ton.org/llms.txt
> Use this file to discover all available pages before exploring further.

<AgentInstructions>

## Submitting Feedback

If you encounter incorrect, outdated, or confusing documentation on this page, submit feedback:

POST https://docs.ton.org/feedback

```json
{
  "path": "/standard/tokens/nft/deploy",
  "feedback": "Description of the issue"
}
```

Only submit feedback when you have something specific and actionable to report.

</AgentInstructions>

# How to deploy an NFT item

export const Image = ({src, darkSrc, alt = '', darkAlt, href, target, height = 342, width = 608, noZoom = false, center = false}) => {
  const isSVG = src.match(/\.svg(?:[#?].*?)?$/i) !== null;
  const shouldInvert = isSVG && !darkSrc;
  const shouldCreateLink = href !== undefined;
  const minPx = 9;
  const maxPx = 608;
  const expectedPx = `a number or a string with a number that is greater than ${minPx - 1} and less than or equal to ${maxPx}`;
  const createInvalidPropCallout = (title, received, expected) => {
    return <Danger>
        <span className="font-bold">
          Invalid <code>{title.toString()}</code> passed!
        </span>
        <br />
        <span className="font-bold">Received: </span>
        {received.toString()}
        <br />
        <span className="font-bold">Expected: </span>
        {expected.toString()}
        {}
      </Danger>;
  };
  const checkValidDimensionValue = value => {
    switch (typeof value) {
      case "string":
      case "number":
        const num = Number(value);
        return Number.isSafeInteger(num) && num >= minPx && num <= maxPx;
      default:
        return false;
    }
  };
  let callouts = [];
  if (height && !checkValidDimensionValue(height)) {
    callouts.push(createInvalidPropCallout("height", height, expectedPx));
  }
  if (width && !checkValidDimensionValue(width)) {
    callouts.push(createInvalidPropCallout("width", width, expectedPx));
  }
  if (callouts.length !== 0) {
    return callouts;
  }
  const heightPx = Number(height);
  const widthPx = Number(width);
  const shouldCenter = center === "true" || center === true ? true : false;
  const shouldNotZoom = noZoom === "true" || noZoom === true ? true : false;
  const images = <>
      <img className="block dark:hidden" src={src} alt={alt} {...height && ({
    height: heightPx
  })} {...width && ({
    width: widthPx
  })} {...(shouldCreateLink || shouldInvert || shouldNotZoom) && ({
    noZoom: "true"
  })} />
      <img className={`hidden dark:block ${shouldInvert ? "invert" : ""}`} src={darkSrc ?? src} alt={darkAlt ?? alt} {...height && ({
    height: heightPx
  })} {...width && ({
    width: widthPx
  })} {...(shouldCreateLink || shouldInvert || shouldNotZoom) && ({
    noZoom: "true"
  })} />
    </>;
  if (shouldCreateLink) {
    if (shouldCenter) {
      return <div style={{
        display: "flex",
        justifyContent: "center"
      }}>
          <a href={href} target={target ?? "_self"}>
            {images}
          </a>
        </div>;
    }
    return <a href={href} target={target ?? "_self"}>
        {images}
      </a>;
  }
  if (shouldCenter) {
    return <div style={{
      display: "flex",
      justifyContent: "center"
    }}>{images}</div>;
  }
  return images;
};

export const Aside = ({type = "note", title = "", icon = "", iconType = "regular", children}) => {
  const asideVariants = ["note", "tip", "caution", "danger"];
  const asideComponents = {
    note: {
      outerStyle: "border-sky-500/20 bg-sky-50/50 dark:border-sky-500/30 dark:bg-sky-500/10",
      innerStyle: "text-sky-900 dark:text-sky-200",
      calloutType: "note",
      icon: <svg width="14" height="14" viewBox="0 0 14 14" fill="currentColor" xmlns="http://www.w3.org/2000/svg" className="w-4 h-4 text-sky-500" aria-label="Note">
          <path fill-rule="evenodd" clip-rule="evenodd" d="M7 1.3C10.14 1.3 12.7 3.86 12.7 7C12.7 10.14 10.14 12.7 7 12.7C5.48908 12.6974 4.0408 12.096 2.97241 11.0276C1.90403 9.9592 1.30264 8.51092 1.3 7C1.3 3.86 3.86 1.3 7 1.3ZM7 0C3.14 0 0 3.14 0 7C0 10.86 3.14 14 7 14C10.86 14 14 10.86 14 7C14 3.14 10.86 0 7 0ZM8 3H6V8H8V3ZM8 9H6V11H8V9Z"></path>
        </svg>
    },
    tip: {
      outerStyle: "border-emerald-500/20 bg-emerald-50/50 dark:border-emerald-500/30 dark:bg-emerald-500/10",
      innerStyle: "text-emerald-900 dark:text-emerald-200",
      calloutType: "tip",
      icon: <svg width="11" height="14" viewBox="0 0 11 14" fill="currentColor" xmlns="http://www.w3.org/2000/svg" className="text-emerald-600 dark:text-emerald-400/80 w-3.5 h-auto" aria-label="Tip">
          <path d="M3.12794 12.4232C3.12794 12.5954 3.1776 12.7634 3.27244 12.907L3.74114 13.6095C3.88471 13.8248 4.21067 14 4.46964 14H6.15606C6.41415 14 6.74017 13.825 6.88373 13.6095L7.3508 12.9073C7.43114 12.7859 7.49705 12.569 7.49705 12.4232L7.50055 11.3513H3.12521L3.12794 12.4232ZM5.31288 0C2.52414 0.00875889 0.5 2.26889 0.5 4.78826C0.5 6.00188 0.949566 7.10829 1.69119 7.95492C2.14321 8.47011 2.84901 9.54727 3.11919 10.4557C3.12005 10.4625 3.12175 10.4698 3.12261 10.4771H7.50342C7.50427 10.4698 7.50598 10.463 7.50684 10.4557C7.77688 9.54727 8.48281 8.47011 8.93484 7.95492C9.67728 7.13181 10.1258 6.02703 10.1258 4.78826C10.1258 2.15486 7.9709 0.000106649 5.31288 0ZM7.94902 7.11267C7.52078 7.60079 6.99082 8.37878 6.6077 9.18794H4.02051C3.63739 8.37878 3.10743 7.60079 2.67947 7.11294C2.11997 6.47551 1.8126 5.63599 1.8126 4.78826C1.8126 3.09829 3.12794 1.31944 5.28827 1.3126C7.2435 1.3126 8.81315 2.88226 8.81315 4.78826C8.81315 5.63599 8.50688 6.47551 7.94902 7.11267ZM4.87534 2.18767C3.66939 2.18767 2.68767 3.16939 2.68767 4.37534C2.68767 4.61719 2.88336 4.81288 3.12521 4.81288C3.36705 4.81288 3.56274 4.61599 3.56274 4.37534C3.56274 3.6515 4.1515 3.06274 4.87534 3.06274C5.11719 3.06274 5.31288 2.86727 5.31288 2.62548C5.31288 2.38369 5.11599 2.18767 4.87534 2.18767Z"></path>
        </svg>
    },
    caution: {
      outerStyle: "border-amber-500/20 bg-amber-50/50 dark:border-amber-500/30 dark:bg-amber-500/10",
      innerStyle: "text-amber-900 dark:text-amber-200",
      calloutType: "warning",
      icon: <svg className="flex-none w-5 h-5 text-amber-400 dark:text-amber-300/80" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2" aria-label="Warning">
          <path stroke-linecap="round" stroke-linejoin="round" d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z"></path>
        </svg>
    },
    danger: {
      outerStyle: "border-red-500/20 bg-red-50/50 dark:border-red-500/30 dark:bg-red-500/10",
      innerStyle: "text-red-900 dark:text-red-200",
      calloutType: "danger",
      icon: <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" fill="currentColor" className="text-red-600 dark:text-red-400/80 w-4 h-4" aria-label="Danger">
          <path d="M17.1 292c-12.9-22.3-12.9-49.7 0-72L105.4 67.1c12.9-22.3 36.6-36 62.4-36l176.6 0c25.7 0 49.5 13.7 62.4 36L494.9 220c12.9 22.3 12.9 49.7 0 72L406.6 444.9c-12.9 22.3-36.6 36-62.4 36l-176.6 0c-25.7 0-49.5-13.7-62.4-36L17.1 292zm41.6-48c-4.3 7.4-4.3 16.6 0 24l88.3 152.9c4.3 7.4 12.2 12 20.8 12l176.6 0c8.6 0 16.5-4.6 20.8-12L453.4 268c4.3-7.4 4.3-16.6 0-24L365.1 91.1c-4.3-7.4-12.2-12-20.8-12l-176.6 0c-8.6 0-16.5 4.6-20.8 12L58.6 244zM256 128c13.3 0 24 10.7 24 24l0 112c0 13.3-10.7 24-24 24s-24-10.7-24-24l0-112c0-13.3 10.7-24 24-24zM224 352a32 32 0 1 1 64 0 32 32 0 1 1 -64 0z"></path>
        </svg>
    }
  };
  let variant = type;
  let gotInvalidVariant = false;
  if (!asideVariants.includes(type)) {
    gotInvalidVariant = true;
    variant = "danger";
  }
  const iconVariants = ["regular", "solid", "light", "thin", "sharp-solid", "duotone", "brands"];
  if (!iconVariants.includes(iconType)) {
    iconType = "regular";
  }
  return <>
      <div className={`callout my-4 px-5 py-4 overflow-hidden rounded-2xl flex gap-3 border ${asideComponents[variant].outerStyle}`} data-callout-type={asideComponents[variant].calloutType}>
        <div className="mt-0.5 w-4" data-component-part="callout-icon">
          {}
          {icon === "" ? asideComponents[variant].icon : <Icon icon={icon} iconType={iconType} size={14} />}
        </div>
        <div className={`text-sm prose min-w-0 w-full ${asideComponents[variant].innerStyle}`} data-component-part="callout-content">
          {gotInvalidVariant ? <p>
              <span className="font-bold">
                Invalid <code>type</code> passed!
              </span>
              <br />
              <span className="font-bold">Received: </span>
              {type}
              <br />
              <span className="font-bold">Expected one of: </span>
              {asideVariants.join(", ")}
            </p> : <>
              {title && <p className="font-bold">{title}</p>}
              {children}
            </>}
        </div>
      </div>
    </>;
};

The creator sends a message to the collection contract, which deploys a new NFT item with the specified data: the initial owner and the item-specific content. The [NFT standard](/standard/tokens/nft/overview) does not prescribe how this data must be supplied; implementations may vary. Typically, the creator provides the initial owner and item-specific content for each NFT, or this information is derived from the collection itself.

<Image src="/resources/images/nft/nft_deploy.svg" alt="Diagram of an NFT item deployment from a collection contract" />

Since the deployment process is not specified by the standard, logic can vary, and the recipes on this page might not apply to every contract. The [reference NFT implementation](/standard/tokens/nft/reference#deploy-single-item) and most modifications follow the same path: the collection owner sends a message with deploy parameters to the collection, and the collection deploys the item.

## Deploy an item with a wallet

To deploy an item from a [wallet](/standard/wallets/how-it-works), send a message from the wallet to the collection contract.

### Prerequisites

* [Node.js](https://nodejs.org/en/download) 22+
* Packages: [`@ton/ton`](https://github.com/ton-org/ton), [`@ton/core`](https://github.com/ton-org/ton-core), [`@ton/crypto`](https://github.com/ton-org/ton-crypto)
* A funded Testnet wallet mnemonic in the `MNEMONIC` environment variable
* The sending wallet must be the collection owner; otherwise the collection rejects deployments

<Aside type="danger" title="Funds and secrets">
  This procedure spends funds, uses a wallet mnemonic, and interacts with a collection contract. Run it on Testnet first to test the desired behavior.
</Aside>

The following example uses the `@ton/ton` stack for TypeScript. These libraries provide interfaces to work with wallet contracts and compose messages.

```ts expandable theme={"theme":{"light":"github-light-default","dark":"dark-plus"},"languages":{"custom":["/resources/grammars/tolk.tmLanguage.json","/resources/grammars/tlb.tmLanguage.json","/resources/grammars/fift.tmLanguage.json","/resources/grammars/tasm.tmLanguage.json","/resources/grammars/func.tmLanguage.json"]}}
import { Address, beginCell, internal, toNano } from "@ton/core";
import { TonClient, WalletContractV5R1, SendMode } from "@ton/ton";
import { mnemonicToPrivateKey } from "@ton/crypto";

const collectionAddress = Address.parse("<COLLECTION_ADDRESS>");
const recipientAddress = Address.parse("<RECIPIENT_ADDRESS>");
const itemContent = "<ITEM_CONTENT>";

async function main() {
    // Toncenter endpoint (Testnet)
    const client = new TonClient({
        endpoint: "https://testnet.toncenter.com/api/v2/jsonRPC",
    });

    // Obtain the next item index
    const nextItemIndex = (
        await client.runMethod(
            collectionAddress,
            "get_collection_data",
        )
    ).stack.readBigNumber();
    // Read the next item index. See the explanation after the code.

    // individual content
    const content = beginCell()
        .storeStringTail(itemContent)
        .endCell();

    const body = beginCell()
        // deploy opcode
        .storeUint(1, 32)
        // query id
        .storeUint(0, 64)
        .storeUint(nextItemIndex, 64)
        // Forwarded to the new item as its initial balance.
        // Ensure `value` >= this amount + all fees.
        .storeCoins(toNano("0.005"))
        .storeRef(
            beginCell()
                .storeAddress(recipientAddress)
                .storeRef(content)
                .endCell(),
        )
        .endCell();

    // Compose deploy message
    const msg = internal({
        to: collectionAddress,
        // Total attached to the collection. Must cover
        // the forwarded amount below (0.005) plus
        // execution/storage fees;
        // keep a safety margin (e.g., 0.01-0.02 TON)
        value: toNano("0.01"),
        bounce: true,
        body,
    });

    // Initialize wallet
    const mnemonic = process.env.MNEMONIC;
    if (!mnemonic) {
        throw new Error("Set MNEMONIC");
    }
    const keyPair = await mnemonicToPrivateKey(
        mnemonic.split(" ")
    );
    const walletContract = client.open(
        WalletContractV5R1.create({
            workchain: 0, // basechain
            publicKey: keyPair.publicKey,
        }),
    );

    // Send the mint message through the wallet
    const seqno = await walletContract.getSeqno();
    await walletContract.sendTransfer({
        seqno: seqno,
        secretKey: keyPair.secretKey,
        // Good practice to use these modes for
        // regular wallet transfers
        sendMode: SendMode.IGNORE_ERRORS |
            SendMode.PAY_GAS_SEPARATELY,
        messages: [msg],
    });
}

void main();
```

Where

* `<COLLECTION_ADDRESS>` — the collection contract address.
* `<RECIPIENT_ADDRESS>` — the initial owner address for the new item.
* `<ITEM_CONTENT>` — item-specific content path or key (for example, `0.json`).

Explanation of body cell composition:

* `.storeUint(1, 32)` — operation code `1` selects "deploy single item" in the [reference collection contract](/standard/tokens/nft/reference#deploy-single-item). [TEP-62](https://github.com/ton-blockchain/TEPs/blob/f10a373fcb9276ba92b225f294998a43af53dcbf/text/0062-nft-standard.md) does not specify this opcode, so in custom implementations, this can differ.
* `.storeUint(0, 64)` — `query_id`. Used for correlating responses with requests. It has no impact on deployment logic and `0` is a commonly used placeholder in cases where no extra logic relies on it.
* `.storeUint(nextItemIndex, 64)` — `item_index`. Index of the item to deploy, obtained from the collection's `get_collection_data` get-method. See [Return collection data](/standard/tokens/nft/reference#return-collection-data).
* `.storeCoins(toNano("0.005"))` — amount forwarded to the new item at deployment to cover its initial balance/fees. Adjust if extra item contract logic requires more.

TL-B for the reference implementation

```tlb theme={"theme":{"light":"github-light-default","dark":"dark-plus"},"languages":{"custom":["/resources/grammars/tolk.tmLanguage.json","/resources/grammars/tlb.tmLanguage.json","/resources/grammars/fift.tmLanguage.json","/resources/grammars/tasm.tmLanguage.json","/resources/grammars/func.tmLanguage.json"]}}
deploy_nft#00000001 query_id:uint64 item_index:uint64 amount:Coins content:^Cell = InternalMsgBody;
```

In the [reference contract](/standard/tokens/nft/reference#deploy-single-item), the body for `op=1` consists of `query_id`, `item_index`, `amount`, and a reference to `content`. See the [TL-B overview](/languages/tl-b/overview).

### Verify

* In a block explorer, confirm the transaction for `<COLLECTION_ADDRESS>` succeeded and inspect the transaction trace to see the internal message that deployed the item.
* To verify via code: call [`get_nft_address_by_index(<INDEX>)`](/standard/tokens/nft/reference#return-item-address-by-index) — where `<INDEX>` is the item index used in the deploy message (the `next_item_index` read from `get_collection_data`) — on the collection to obtain the item address; then call [`get_nft_data`](/standard/tokens/nft/reference#return-item-data) on the item and check that the owner is `<RECIPIENT_ADDRESS>` and the content is `<ITEM_CONTENT>`.

## Deploy an item with a smart contract

To deploy an item from a smart contract, send a message from the contract to the collection contract.

### Prerequisites

* Enough Testnet funds on the calling contract to cover fees and attached value (for example, ≥ 0.02 TON)
* `<COLLECTION_ADDRESS>`, `<RECIPIENT_ADDRESS>`, `<INDEX>`, `<ITEM_CONTENT>`
* The calling contract must be the collection owner; otherwise the collection rejects deployments

<Aside type="danger" title="Funds and secrets">
  This smart contract interacts with a collection contract. Run it on Testnet first to test the desired behavior.
</Aside>

The following example is a minimal smart contract that only implements the item deployment logic. In real deployments, this is integrated into a larger flow.

```tolk title="Tolk" theme={"theme":{"light":"github-light-default","dark":"dark-plus"},"languages":{"custom":["/resources/grammars/tolk.tmLanguage.json","/resources/grammars/tlb.tmLanguage.json","/resources/grammars/fift.tmLanguage.json","/resources/grammars/tasm.tmLanguage.json","/resources/grammars/func.tmLanguage.json"]}}
// SnakeString describes a (potentially long) string inside a cell;
// short strings are stored as-is, like "my-picture.png";
// long strings are nested refs, like "xxxx".ref("yyyy".ref("zzzz"))
type SnakeString = slice

fun SnakeString.unpackFromSlice(mutate s: slice) {
    // SnakeString can only be the last: it's "the remainder";
    // for correctness, it's better to validate it has no more refs:
    assert (s.remainingRefsCount() <= 1) throw 5;
    val snakeRemainder = s;
    s = createEmptySlice(); // no more left to read
    return snakeRemainder
}

fun SnakeString.packToBuilder(self, mutate b: builder) {
    b.storeSlice(self)
}

struct NftItemInitAtDeployment {
    recipientAddress: address
    content: Cell<SnakeString>
}

struct (0x00000001) DeployNft {
    queryId: uint64
    itemIndex: uint64
    attachTonAmount: coins
    initParams: Cell<NftItemInitAtDeployment>
}

fun onInternalMessage(in: InMessage) {
    // The whole logic will be in `onInternalMessage`
    // for demonstration purposes. In real deployments this should
    // usually be gated behind authorization and other checks.

    val deploy = DeployNft {
        queryId: 0,
        itemIndex: <INDEX>,
        // will be sent to the item contract on deployment
        attachTonAmount: ton("0.005"),
        initParams: NftItemInitAtDeployment {
            recipientAddress: address("<RECIPIENT_ADDRESS>"),
            content: ("<ITEM_CONTENT>" as SnakeString).toCell()
        }.toCell()
    };

    val msg = createMessage({
        bounce: true,
        dest: address("<COLLECTION_ADDRESS>"),
        value: ton("0.01"),
        body: deploy
    });

    msg.send(SEND_MODE_PAY_FEES_SEPARATELY);
}
```

Where

* `<COLLECTION_ADDRESS>` — the collection contract address.
* `<RECIPIENT_ADDRESS>` — the initial owner address for the new item.
* `<INDEX>` — item's index. Note that obtaining the actual index on-chain is [not possible](/from-ethereum#on-chain-get-methods), so a smart contract that performs these deployments should handle that logic itself (for example, store the latest used index and increment it on each deployment).
* `<ITEM_CONTENT>` — item-specific content path or key (for example, `0.json`).

The top of the snippet defines structs for the deploy message and can be modified depending on the NFT implementation specifics. The sending logic lives in `onInternalMessage` for simplicity. It composes a message with hard-coded example values and sends that message to the collection contract.

### Verify

* In a block explorer, confirm the transaction from the calling contract to `<COLLECTION_ADDRESS>` succeeded and inspect the transaction trace to see the internal message that deployed the item.
* To verify via code: call [`get_nft_address_by_index(<INDEX>)`](/standard/tokens/nft/reference#return-item-address-by-index) on the collection to obtain the item address, then call [`get_nft_data`](/standard/tokens/nft/reference#return-item-data) on the item and check that the owner is `<RECIPIENT_ADDRESS>` and the content is `<ITEM_CONTENT>`.
