Skip to main content
Non-Fungible Tokens (NFT) are unitary and therefore unique. This makes NFTs ideal to represent ownership of assets such as a piece of digital content, or a ticket for an event. Non-Fungible Tokens As with fungible tokens, NFTs are not stored in the user’s wallet. Instead, each NFT lives in an NFT contract that works as a bookkeeper, being in charge of creating, storing, and transferring NFTs.
Be mindful of not confusing an NFT contract with an NFT marketplace. NFT contracts simply store information (metadata), while NFT marketplaces are contracts where NFTs can be listed and exchanged for a price.

The Standard

NEP-171 is the blueprint for all non-fungible tokens on NEAR. It defines a common set of rules and functions that the contract MUST implement to be considered a non-fungible token contract. NEP-177 extends NEP-171 to define the metadata for both non-fungible tokens and NFT contracts.

Deploying an NFT Contract

You can deploy your own NFT contract using the reference implementation.
near deploy <account-id> --wasmFile contract.wasm --initFunction new
Deploying by hash creates an immutable contract that never changes. Deploying by account ID creates an updatable contract that changes when the referenced account’s contract is updated.

Minting an NFT

To create a new NFT (minting), you call the nft_mint method with the metadata that defines the NFT.
near call nft.primitives.near nft_mint '{
  "token_id": "1",
  "receiver_id": "bob.near",
  "token_metadata": {
    "title": "NFT Primitive Token",
    "description": "Awesome NFT Primitive Token",
    "media": "https://example.com/nft.png"
  }
}' --deposit 0.01 --accountId bob.near
See the metadata standard for the full list of TokenMetadata parameters.

Royalties

Royalties enable you to create a list of users that should get paid when the token is sold in a marketplace. For example, if anna has 5% royalties, each time the NFT is sold, anna should get 5% of the selling price.

Querying NFT Data

You can query the NFT’s information and metadata by calling nft_token.
near view nft.primitives.near nft_token '{"token_id": "1"}'

Transferring an NFT

Transferring an NFT can happen in two scenarios: (1) you ask to transfer an NFT you own, or (2) an authorized account asks to transfer the NFT. In both cases, invoke the nft_transfer method with the token ID and receiver.
near call nft.primitives.near nft_transfer '{
  "token_id": "1",
  "receiver_id": "alice.near"
}' --deposit 0.000000000000000000000001 --accountId bob.near

Attaching NFTs to a Call

Natively, only NEAR tokens can be attached to function calls. However, the NFT standard enables attaching non-fungible tokens by using the NFT contract as an intermediary. Instead of attaching tokens directly, you ask the NFT contract to do both a transfer and a function call on your behalf using nft_transfer_call.
near call <nft-contract> nft_transfer_call '{
  "receiver_id": "<receiver-contract>",
  "token_id": "<token_id>",
  "msg": "<a-string-message>"
}' --deposit 0.000000000000000000000001 --accountId <your-account>

How it Works

  1. You call nft_transfer_call in the NFT contract passing: the receiver, a message, and the token ID.
  2. The NFT contract transfers the NFT to the receiver.
  3. The NFT contract calls receiver.nft_on_transfer(sender, token-owner, token-id, msg).
  4. The NFT contract handles errors in the nft_resolve_transfer callback.
  5. The NFT contract returns true if it succeeded.
Contracts expecting to receive NFTs must implement the nft_on_transfer method:
pub fn nft_on_transfer(
  &mut self,
  sender_id: AccountId,
  previous_owner_id: AccountId,
  token_id: TokenId,
  msg: String,
) -> PromiseOrValue<bool> {
  // Your logic here
  
  // Return true to return NFT to sender, false to keep it
  PromiseOrValue::Value(false)
}

Approving Users

You can authorize other users to transfer an NFT you own. This is useful for listing your NFT in a marketplace.
near call <nft-contract> nft_approve '{
  "token_id": "<token-unique-id>",
  "account_id": "<authorized-account>",
  "msg": "<json-structure>"
}' --deposit 0.01 --accountId <your-account>
If the msg parameter is included, a cross-contract call will be made to <authorized_account>.nft_on_approve(msg), which will then make a callback to nft_resolve_transfer in your NFT contract.

Additional Resources

Build docs developers (and LLMs) love