BlockchainSolidity8 min readUpdated

uint and uint256 in Solidity: The Default Number Type

By Mudassir Khan — Agentic AI Consultant & AI Systems Architect, Islamabad, Pakistan

Cover illustration for: uint and uint256 in Solidity: The Default Number Type

Section 01 · Definition

What is uint in Solidity?

A uint variable holds a whole number that cannot be negative. It is the everyday number type for almost every Solidity contract.

Quick answer

What is uint? uint is short for 'unsigned integer'. It stores a non-negative whole number. The default size is uint256, which is also called uint with no number after it. Unsigned means there is no sign bit, so it cannot represent negative values — for those you use the signed cousin int.

Every smart contract needs to count something. Tokens, votes, IDs, prices, timestamps. The number type Solidity reaches for first is uint256. You will see it on almost every line of state in production code, from ERC20 balances to Uniswap pool reserves to governance vote tallies.

solidity
uint256 public totalSupply;
uint256 public price = 0.05 ether;
uint256 public deadline;
uint256 public counter;

The keyword uint by itself is an alias for uint256. Most style guides recommend writing the explicit size so a reader does not have to remember the alias. Inside an array or a struct, you may want a smaller variant for packing — see the next section.

Section 02 · Sizes

uint8, uint16, uint32, uint64, uint128, uint256

Solidity gives you nine uint sizes in 8-bit increments. Pick uint256 by default. Pick smaller only for packing.

Bar chart comparing uint8 through uint256 with their bit width and maximum value.
Each size doubles the bit width and squares the maximum value.

The EVM word size is 256 bits. When you declare a uint8 on its own, the compiler still loads a full 32 byte slot and masks the unused bits, so the gas cost is identical to uint256. The only situation where smaller types save real gas is when several of them fit together into the same 32 byte slot:

solidity
struct PackedAccount {
    uint128 balance;   // 16 bytes
    uint64  lastSeen;  // 8 bytes
    uint64  nonce;     // 8 bytes
    // 3 fields total in ONE storage slot — saves 40 000 gas per write
}

Outside packing, prefer uint256 everywhere. It is the type the EVM works with natively, the type used by every audited OpenZeppelin contract, and the type that requires zero downcasting when interacting with mappings or events.

Section 03 · Safety

Overflow, underflow, and unchecked math

Solidity 0.8 added automatic overflow protection. Knowing how it works (and when it is safely off) is non-negotiable.

Before Solidity 0.8, an addition that exceeded the maximum value of the type silently wrapped around to zero. Subtracting from zero wrapped around to the maximum value. These two bugs caused real exploits — most famously the BeautyChain (BEC) overflow that minted unlimited tokens and crashed the price.

solidity
// Solidity 0.8+ default: this REVERTS the transaction
uint256 a = type(uint256).max;
a + 1;          // overflow → revert

uint256 b = 0;
b - 1;          // underflow → revert

// You can opt out when you have proven it is safe
unchecked {
    for (uint256 i = 0; i < array.length; i++) {
        // no overflow check on i++ — saves ~30 gas per loop
    }
}

The unchecked block is a deliberate optimisation, not a default. Use it only for loop counters, math you have proven cannot overflow, or hot paths where you have audit coverage. Leaving math checked is the safest default.

Reading legacy contracts

Anything compiled with Solidity 0.7 or earlier had to use the SafeMath library to get the same protection 0.8 gives you for free. If you see imports of SafeMath in older code, the contract is relying on it; removing it would re-introduce the silent wrap behaviour.

Section 04 · Real-world uses

Where uint shows up in production code

A short tour of the places every Ethereum developer will see uint within their first month of writing contracts.

solidity
// 1. ERC20 balance tracking
mapping(address => uint256) public balanceOf;

// 2. ERC721 token IDs
mapping(uint256 => address) public ownerOf;

// 3. Auction bid amounts
uint256 public highestBid;

// 4. Voting weights
mapping(address => uint256) public votingPower;

// 5. Time-locked withdrawals
uint256 public unlockAt = block.timestamp + 7 days;

// 6. Loop iteration
for (uint256 i = 0; i < winners.length; i++) {
    payable(winners[i]).transfer(reward);
}

Every one of those examples is non-negative by definition. A balance cannot be minus ten tokens, an NFT cannot be token minus three, and a deadline cannot be set in negative time. Whenever the value is a count or an amount, reach for uint. If you genuinely need negatives — a profit-and-loss delta, a temperature, a balance difference — the right type is int.

Section 05 · Mini contract

A complete deposit counter

A self-contained contract that uses uint256 for tracking and shows the full lifecycle of safe arithmetic.

solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

contract DepositCounter {
    uint256 public totalDeposits;
    uint256 public depositCount;
    mapping(address => uint256) public depositsByUser;

    event Deposited(address indexed user, uint256 amount, uint256 newTotal);

    function deposit() external payable {
        require(msg.value > 0, "zero deposit");

        depositsByUser[msg.sender] += msg.value;
        totalDeposits              += msg.value;

        unchecked {
            depositCount += 1; // safe — would take 10^77 deposits to overflow
        }

        emit Deposited(msg.sender, msg.value, totalDeposits);
    }
}

Three uses of uint256 in 20 lines: a running total, an individual user balance inside a mapping, and a counter that opts into unchecked because we can prove it will never wrap. This pattern shows up in every vault, staking contract, and DeFi pool you will read.

Section 07 · FAQ

Frequently asked questions

Is uint the same as uint256?

Yes. uint is an alias for uint256. They compile to identical bytecode. Most production codebases write uint256 explicitly so the size is obvious to a reader and to static analysis tools.

Why does Solidity not have a default float or decimal type?

The EVM has no native floating point unit and floats are not deterministic across architectures, which would break consensus. Decimal-style amounts are emulated by storing values in their smallest unit (wei for ether, the smallest divisible unit for a token) and tracking the decimal places off chain.

When should I use uint8 instead of uint256?

Only when several small values fit together inside one 32 byte storage slot. A bool plus a uint8 plus a uint64 plus a uint128 fit in one slot — that saves a 20 000 gas SSTORE on every write. A standalone uint8 saves nothing.

What happens if my uint overflows in Solidity 0.8?

The transaction reverts. All state changes from that transaction are rolled back and the caller pays for the gas used up to the revert. This is much safer than the silent wraparound behaviour of older Solidity versions.

Can I store ether amounts as uint?

Yes — and you should. ether amounts in Solidity are stored as uint256 in the smallest unit, wei (1 ether = 10^18 wei). msg.value, address(this).balance, and every payable transfer all use uint256 internally.

Written by Mudassir Khan

Agentic AI consultant and AI systems architect based in Islamabad, Pakistan. CEO of Cube A Cloud. 38+ agentic AI launches delivered for global founders and CTOs.

View agentic AI consulting serviceSee ChainTrust case study

Related service

Agentic AI Consulting

See scope & pricing →

Related case study

ChainTrust Compliance Engine

Read case study →

More on this topic

Need an AI systems architect?

Book a 30-minute architecture call. I will sketch the high-level design for your use case and give you an honest view of the trade-offs.

Book a strategy call →