Why doesn't OpenZeppelin ERC721 contain setTokenURI?

Doesn’t make sense to me at all.

We all agree that setTokenURI 's costs is just storing bytes32 hash into a storage for which each user pays only for his/her part in the storage. So I don’t see much costs here.

If we need to append something in tokenURI, it still is view function right because it just appends it and doesn’t modify storage. So, no costs here at all.

What’s the real deal ?

1 Like

Hi @novaknole,

I recommend trying it out on a public testnet and calculating the cost difference between storing an IPFS hash per token ID and not storing when minting.

@abcoathup @hantuzun @frangio

Hey ,

I compared the costs for both cases : 1. without using setTokenURI and using predefined metadata vs 2. using setTokenURI.

The very vague (might be wrong with 5,000 - 10,000 Gas, not that important) I found is this:

  1. without setTokenURI, and just using predefined metadata solution costs 154920 for creating new token.
  2. with setTokenURI, it costs 221474

The difference is 67,000 approximatelly.

My question now…

Question 1 : In my opinion, using predefined metadata solution, which means, we first upload a directory which contains 1, 2, 3 ,.e.t.c named files(these are metadatas) seems a very bad solution.

  • Reason 1: It’s bad because we can’t allow users to come in the future and mint new tokens, because their metadata is not in the ipfs. One can say that we can have the functionality of updating baseURI , but what guarantee do we have that whoever can update won’t set it to malicious.com. We can double check for sure, but he wil still be able to update it. which seems to be very wrong. Even using IPNS seems a very bad hack, because, now vice versa situation happens: we update the directory with new metadatas which means we can also upload totally different metadatas(even change the old ones) and now, contract’s tokenURI will return wrong metadatas. How is this for even a second good solution ? I think the only way this could be a good solution is if we don’t use IPNS and also we don’t have the updateBASEURI functionality in the contract. This means that with whatever baseURI we deploy contract, we already have the already predefined metadatas on that baseURI and that’s it.

I’d really much appreciate your final input on this and if there’s something you don’t agree with me about this. I just wanna 100% make sure that i understand every hidden detail…

Question 2

As we found the difference in gas costs which is 67,000, do you think this difference is really noticeable and worth changing the setTokenURI solution to predefined metadata solution ? In my opinion, it’s not. So, I’d also love to hear your opinions.

I really appreciate your follow ups on this question.


Hi @novaknole,

It really depends on your use case and the value of the NFTs. If the cost of minting is significant compared with the value of each token then you should be optimizing for gas costs.

Question 1, It sounds like your use case requires metadata to be created at time of minting and cannot be determined at the time of deployment, so you can either use centralized (lower minting cost) or decentralized (higher minting cost).

Question 2, 67,000 gas, at a gas price of 150 gwei is ~0.01 ETH, ~$21 at current prices. It depends on the value of the NFT and your use case.

Would you suggest to deploy one ERC721 for every unique asset of one service or to deploy one contract and users mint against it for each unique asset? For example an art registry where users upload a PNG of their unique art and expect to have a NFT representing that artwork.

Sorry if this was mentioned, asked, or answered before. It has impact on my design under progress and want to make sure before making such a change.

1 Like

It will be prohibitively expensive to deploy one ERC721 contract for every user, let alone for every piece of artwork.

This is one of the cases where using ERC721URIStorage may make more sense.

If you want to deploy a separate ERC721 contract per user for other reasons (e.g. so that each user has their own NFT contract address) it would be cheaper to do using Clones, and in this case you would also need something like ERC721URIStorage.

The way to do this without using ERC721URIStorage would be to have an IPNS address that you update with each new minted piece. I’m not sure how well this would scale.


This is one of the most discussed topic around NTFs, There is so many angle to deal with this and my response is always the same. It’s all about use case. How you want your smart contract to deal with the data.

The way I approach this is. Do I want a Decentralized data storage system or do I want it to be centralized.

If you want to perform some kind of control over the data and filter for security. I would tend to go with a centralized process like a DB you can administer.

If you want to go towards a decentralized solution. Then the control would be basic and operated from the contract level. And it’s not as simple as calling it IPFS. You still have to make sure this data hosted on IPFS persist over time.

They both have pros and cons, You could even mix both of them.



I wanted to bank off this thread as it is somewhat related. I wanted to take the approach of having the metadata predefined in a directory and uploaded under one hash to IPFS at the time of deployment; however, wouldn't this conflict with the concept of your typical NFT sale? The buyer of the first NFT would be able to view the metadata and IPFS hash of their token then view all subsequent ones by just changing the /1 to /2 and so on without having to mint additional tokens, then try to gain an advantage by timing the mint of a particularly rare one based on the metadata?

Yes, normally you would want the distribution/sale to be randomized so that it can't be gamed by people who know beforehand which are the rare ones.

There is a relevant conversation about that here:

1 Like

Hi @frangio thanks for your answers! One question though, if we used IPNS, wouldn't this be centralized as it is tied to a specific private key? Wouldn't this defeat the purpose of IPFS when minting NFTs, as described in https://docs.ipfs.io/how-to/mint-nfts-with-ipfs/#a-short-introduction-to-nfts?

@frangio one more question, you wrote

we think most people should try to avoid setTokenURI if possible for their use case.

but without the use of IPNS that means that for every smart contract deployed there can be only one associated static directory uploaded to IPFS which can never change and its URI must be known in advance; could you provide a use case example? I'm referring in particular to the ERC721PresetMinterPauserAutoId preset contract.

Thanks in advance!

@Cosimo_de_Medici_di Thank for your questions!

True, it would be centralized, although it would probably be possible to keep a record that the IPNS address at some point resolved to a specific IPFS file/directory. This is not what people are generally looking for though, so it's not exactly an acceptable solution.

Maybe the right way to make it decentralized is to use ENS as the gateway to an IPFS file. See IPFS Docs - Link a Domain. Disclaimer, I haven't done this myself but it looks like it would work. You can set up an ENS name, say awesomepfp.eth and create a record pointing to an IPFS directory with the NFT metadata files. The token's base URI can then be set to the ENS domain. The client needs to know how to resolve ENS domaions, and this capability is probably not universal yet, but I'd expect it to be at some point. The control of the ENS domain can be granted to a smart contract that doesn't have the ability to change the records so the NFT metadata remains immutable. You do need it to have the ability to renew the domain, you could even make it pay itself with royalties.

A limited edition NFT is a very reasonable use case as far as I can tell.

Though you're right that this contract preset is odd in that it allows minting arbitrary numbers of tokens all of them with the same base URI, so it's hard to see how that could work in a decentralized way, unless again there is a limited number of NFTs and you add a cap to the total number minted.

The present contracts are meant as examples of how to combine the different modules. Nowadays we recommend Contracts Wizard instead, which is able to generate many more combinations. It suffers the same problem if you select the auto-incrementing ids, but the idea of the Wizard is that you can then go on and add custom logic if you need it.

1 Like

what if i want to mint Dynamically NFTs and Dynamic Meta Data

The approach using base URI generally doesn't work for dynamic minting and metadata. For that case it's probably a better fit to use ERC721URIStorage and allow minters to pass in the metadata URI. This approach is implemented in Contracts Wizard when you select both Mintable and URI Storage:

Thank you So Much Man. I'm Beginner so these questions could be jokes for you.

Question 1: does IPFS allows us to use his API free of cost for life time (Is it free for LifeTime with unlimited data storage?).

Question 2: If we Delete TokenURI from contract, can we delete that Data from IPFS.

As far as I know you can't delete the data from IPFS. You could stop pinning it but someone else may have the file and still host it.

IPFS is a protocol and you can publish files on IPFS for free, but if you want those files to remain alive you need to either run a node and pin the files there, or pay for a pinning service. I only know Pinata and they offer a free tier for a small number of files.

1 Like

A post was split to a new topic: ERC721 mint with multiple URIs

@frangio Happy Xmas!

Thank you for your interesting solution! If I understand this correctly, it allows the contract to have a more user friendly baseURI, by redirecting requests to an IPFS directory (plus appending tokenURI).
Still, it wouldn't be possible to mint dynamically using this method, would it? Thanks!

Indeed dynamic minting where metadata is not known beforehand is not possible with this method unless you use IPNS, which loses the immutability that IPFS would otherwise grant.

1 Like