What is a modifier?
A modifier is a piece of code that runs before (or after) a function executes. They're used to enforce preconditions — checks that must pass before the function body runs. The _; placeholder marks where the function body is inserted.
solidity
modifier onlyOwner() {
require(msg.sender == owner, 'Not the owner');
_; // the function body runs here
}
function setFee(uint256 newFee) external onlyOwner {
fee = newFee;
// onlyOwner check runs first — if msg.sender != owner, it reverts before reaching here
}Parameterized modifiers
Modifiers can accept parameters, making them flexible enough to handle varying conditions.
solidity
modifier minimumAmount(uint256 min) {
require(msg.value >= min, 'Insufficient ETH sent');
_;
}
function premiumMint() external payable minimumAmount(0.1 ether) {
_mint(msg.sender, 1);
}Multiple modifiers
Functions can have multiple modifiers. They execute left to right, each waiting for the previous one to place its _;.
solidity
modifier onlyOwner() {
require(msg.sender == owner, 'Not owner');
_;
}
modifier whenNotPaused() {
require(!paused, 'Contract is paused');
_;
}
function withdraw(uint256 amount) external onlyOwner whenNotPaused {
// Runs: onlyOwner check → whenNotPaused check → function body
payable(msg.sender).transfer(amount);
}Post-condition modifiers
Code after _; runs after the function body. This is less common but useful for invariant checks.
solidity
modifier checkInvariant() {
_;
// Runs after the function body
assert(totalSupply == _sumOfBalances());
}
function mint(address to, uint256 amount) internal checkInvariant {
balances[to] += amount;
totalSupply += amount;
}Common modifier patterns
onlyOwner— Restrict to contract ownerwhenNotPaused/whenPaused— Emergency circuit breakernonReentrant— Prevent reentrancy attacks (OpenZeppelin's most-used modifier)onlyRole(role)— Role-based access control
Rather than reinventing these, prefer OpenZeppelin's battle-tested implementations:
solidity
import '@openzeppelin/contracts/access/Ownable.sol';
import '@openzeppelin/contracts/utils/ReentrancyGuard.sol';
contract MyContract is Ownable, ReentrancyGuard {
function sensitiveAction() external onlyOwner nonReentrant {
// ...
}
}