# locking pragma versions prevents deployment with untested compiler versions
Using an exact version pragma (`pragma solidity 0.8.20;`) instead of a range (`pragma solidity ^0.8.0;`) ensures the contract compiles only with the specific compiler version that was tested and audited. Since compiler updates can introduce subtle behavioral changes — such as [[transient storage introduces new storage semantics with novel security implications|new storage semantics]], [[solidity 0.8.31 deprecates send and transfer signaling the move away from fixed gas stipend patterns|deprecated functions]], or [[solidity 0.8.0 introduced default arithmetic overflow protection making unchecked blocks the new attack surface|fundamental arithmetic behavior changes]] — deploying with an untested compiler version may change the contract's behavior in ways the audit did not cover.
This is a low-cost defensive measure that eliminates an entire class of deployment-time risk. Since [[EVM opcode incompatibility across chains causes failures when contracts assume uniform opcode support]], pragma locking is doubly important for multi-chain deployments where compiler default targets may introduce incompatible opcodes. Exception: libraries intended for downstream consumption may use floating pragmas (`^0.8.0`) to allow integrators flexibility in compiler choice. (SWC-103)
---
Relevant Notes:
- [[transient storage introduces new storage semantics with novel security implications]] — an example of compiler changes with security implications
- [[solidity 0.8.31 deprecates send and transfer signaling the move away from fixed gas stipend patterns]] — another compiler change that affects contract behavior
- [[solidity 0.8.0 introduced default arithmetic overflow protection making unchecked blocks the new attack surface]] — the most significant behavioral change between compiler versions
- [[EVM opcode incompatibility across chains causes failures when contracts assume uniform opcode support]] — compiler target affects opcode compatibility
- [[the Curve Finance Vyper compiler exploit proved that source-level reentrancy guards can be silently broken by compiler bugs invisible to auditors]] — demonstrates the limits of version pinning: affected Curve pools were pinned to a vulnerable Vyper version, and pinning alone cannot protect against bugs within the pinned version
- [[majority of solidity 0.8.x compiler bugs manifest only under specific pipeline configurations creating hidden behavioral divergence from identical source code]] — version pinning addresses compiler version risk but not compilation flag divergence, which is the broader problem
Topics:
- [[security-patterns]]