The word "mint" carries a lot of romance. It sounds like stamping a coin, pressing a medallion, breathing creative life into a file. The on-chain reality is narrower and, once you see it, more useful. Minting is a function call. A smart contract writes one new row into a mapping that says "token #N is owned by address X," emits a log entry, and the transaction ends. That's it. Everything else — the art, the auction, the Discord role — is scaffolding around that single state change.
This article is Part 3 of the NFTs 101 series. If you haven't read what an NFT actually is or where the metadata and image actually live, those give you the vocabulary for what follows. Here we're focused on the creation moment itself: what it costs, how it works, and why a pattern called "lazy minting" quietly reshaped the creator economy.
What minting actually is at the protocol level
The ERC-721 standard is famously terse on this point. The specification states that "Creation of NFTs ('minting') and destruction of NFTs ('burning') is not included in the specification." In other words, the standard doesn't tell you how to make a token — it only tells you what the token has to look like once it exists.
The convention is hidden in the Transfer event, which "emits when NFTs are created (from == 0) and destroyed (to == 0)." That zero address — 0x0000000000000000000000000000000000000000 — is the semantic marker. A Transfer event where the sender is the zero address means "this token did not exist before, and now it does." A block explorer sees that log and renders it as "Mint."
In practice, almost every production NFT contract reuses OpenZeppelin's implementation rather than writing its own. Two internal functions do the work. _mint "Mints tokenId and transfers it to to" — it writes the ownership slot, increments the balance counter, and emits the event. _safeMint does all of that and additionally checks for to acceptance — if to refers to a smart contract, it must implement IERC721Receiver.onERC721Received, confirming the contract actually knows how to hold an NFT. Two requirements always apply to _mint: the tokenId must not already exist, and to cannot be the zero address (the zero address is reserved for the burn sink).
The distinction between _mint and _safeMint matters because a plain _mint to a contract that doesn't implement the receiver interface will lock the token there permanently. OpenZeppelin's own documentation warns: "Usage of this method is discouraged, use ERC721._safeMint whenever possible."
Primary market vs secondary market
Minting is the primary market event. It's the first time a token exists on-chain, and the transaction that creates it is usually the same one that transfers it to its first buyer. Proceeds from that sale go to the creator or the contract treasury.
Everything after that is secondary market. When a collector sells their token to another collector, no new storage slot is created — the contract just reassigns the existing tokenId → owner row to a new address. The token is already there; only the pointer moves.
This is also where ERC-2981 royalties come in. The royalty standard lets a contract declare "on secondary sales, please send X% to this address," and marketplaces that respect the standard honor it. Royalties are marketplace-enforced, not protocol-enforced — the blockchain itself doesn't stop a peer-to-peer transfer from bypassing them. Understanding the primary/secondary split also explains a recurring pattern: mint-day gas wars on hot drops (because everyone is trying to claim scarce primary tokens at once) versus cheap, quiet resales months later (because no new storage is being written, just reassigned).
Gas anatomy of a mint
Minting costs money because writing to blockchain storage costs money. Understanding how a blockchain transaction works helps here — and why gas costs real money gives you the economic backdrop. The short version for minting:
- Every Ethereum transaction begins with a 21,000-gas base cost just for existing.
SSTORE_SET_GASis 20,000 gas for flipping a storage slot from zero to a non-zero value. That's the single largest line item in a mint.- Every new storage slot a mint touches — the
tokenId → ownermapping, the per-address balance counter, sometimes a per-token URI — is another 20,000 gas. - Calldata (the function arguments you send in) costs 16 gas per non-zero byte under EIP-2028 (reduced from 68), and 4 gas per zero byte.
- The
Transferevent itself adds a few thousand gas for the indexed topics.
Add it all up and a typical ERC-721 mint lands somewhere between 50,000 and 150,000 gas, depending on how many storage slots the contract touches and whether it's batching. A "free mint," despite the name, is not actually free: the creator just declines to charge a mint price on top of the gas. The buyer still pays the network.
Lazy minting — the gasless mint that happens on first transfer
If you squint at the above, an inefficiency becomes obvious. The creator pays gas upfront to put 10,000 tokens on-chain — but most creators have no idea how many of those tokens will actually sell. Paying to mint tokens nobody buys is pure loss. Lazy minting flips the timing: don't mint until there's a buyer, and let the buyer pay the gas.
The mechanism leans on EIP-712, which the Ethereum docs describe as "a standard for hashing and signing of typed structured data as opposed to just bytestrings." In practical terms, it lets a creator sign a structured off-chain message — a voucher containing the token ID, metadata URI, price, and eligibility rules — that a smart contract can later verify cryptographically. Wallets display the fields as human-readable text instead of a blob of hex, which is both a safety property and the reason EIP-712 became the industry default.
When a buyer decides to purchase, they call a redeem function on the mint contract and pass in the voucher plus the creator's signature. The contract verifies the signature, runs _safeMint in the same transaction, and routes the sale price to the creator. The buyer pays gas. The creator pays nothing for unsold inventory. OpenSea historically popularized this pattern for creator drops; Rarible, Zora, and many independent minting platforms use variants. (Seaport, OpenSea's newer protocol, is a trading protocol rather than a lazy-mint primitive, but it uses similar EIP-712 signed-order patterns.)
Common mint patterns
Once you understand the mechanics, the sale formats are just policy layered on top of _safeMint:
- Fixed-price: every token costs the same flat amount in ETH.
- Dutch auction: price starts high and steps down on a schedule until the supply sells out.
- Allowlist / whitelist: pre-approved addresses — often proven via a Merkle proof rather than a giant on-chain list — get to mint early, usually at a discount.
- Free mint: buyer pays only gas; the creator's revenue model depends on secondary royalties.
- Reveal-after-mint: every token initially points to a placeholder image, and the creator flips a flag once minting ends to reveal the real metadata. This prevents rarity sniping during the mint.
- Lazy mint: no tokens exist on-chain until someone buys; the "collection" is a list of signed vouchers on the creator's server.
Same _mint call underneath. Different rules about when, by whom, and at what price.
What can go wrong
Minting is one of the more failure-prone operations a new user encounters, mostly because it happens under time pressure and in public.
- Failed transactions still cost gas. If your mint reverts — sold out, you weren't on the allowlist, the contract errored — the network still charges you for the work it did before the revert.
- Front-running. On hot drops, bots watch the mempool and pay higher priority fees to squeeze in ahead of human buyers. You hit "confirm," the supply sells out, and your transaction mines a block later into an empty queue.
- Stuck mints. If you set a gas price too low relative to network demand, your transaction sits in the mempool unmined. Most wallets let you either speed it up (replace it with a higher-fee version) or cancel it (replace it with a zero-value transfer to yourself at the same nonce).
- Signature replay on lazy mints. A poorly written voucher contract might let the same signature be redeemed twice. Well-written ones track consumed vouchers via a nonce or a mapping and reject repeats.
- Wrong recipient with
_mint. If a contract uses plain_mintinstead of_safeMintand a buyer mints to a smart contract wallet that doesn't implement the ERC-721 receiver interface, the token is stranded. This is why OpenZeppelin explicitly discourages bare_mintfor public-facing flows.
None of these are exotic. They're the everyday texture of minting on a public network, and every one of them gets easier to recognize once you've seen the state change underneath.
Key takeaways
- Minting is a specific function call that writes one new row into an ownership mapping and emits a
Transferevent from the zero address. The art and the auction are scaffolding around that moment. - OpenZeppelin's
_safeMintis the production default because it refuses to strand tokens in contracts that can't hold them. Prefer it over_mint. - Primary-market mints write new storage (expensive); secondary-market transfers only reassign pointers (much cheaper). That's why mint days are gas wars and resales usually aren't.
- Lazy minting uses EIP-712 signed vouchers to defer the on-chain write to the first buyer — the creator pays nothing for unsold inventory, and the buyer pays the gas they were going to pay anyway.
- Failed mints still cost gas, stuck mints can be replaced, and front-running is a feature of public mempools, not a bug. Budget accordingly and don't mint in a panic.



