Library / SDK
OpenZeppelin/openzeppelin-contracts avatar
OpenZeppelin/openzeppelin-contracts

OpenZeppelin Contracts: what the library actually gives you, and how to install it

OpenZeppelin Contracts is a library for secure smart contract development.

27,254 stars12,397 forksSolidityMIT

At a glance

What is it?
OpenZeppelin Contracts is a Solidity library of audited implementations for ERC-20, ERC-721, access control and utility code. This covers how it installs under Hardhat or Foundry, how the release tags differ, and where the upgradeable storage rules bite.
Who is it for?
Adopt OpenZeppelin Contracts if you are writing Solidity and want ERC-20, ERC-721, ERC-1155, ERC-6909 or role-based permissioning that you did not write yourself; skip it if you want a minimal hand-rolled token or you are not on Solidity at all. Before you commit, check the NPM tag you installed against the tag table, confirm whether your project is upgradeable, and read the Backwards Compatibility page before crossing a major version.
Can I use it commercially?
Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 5 days ago.
What is it written in?
Mainly Solidity, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on September 27, 2026, and from our analysis. They are not legal advice.

Editorial analysis

The problem OpenZeppelin Contracts solves, and for whom

Writing an ERC-20 token from scratch is not difficult. Writing one that handles the edge cases the same way every other token does, and that has been read by people who look for reentrancy and integer problems for a living, is a different job. OpenZeppelin Contracts exists to remove that job from your critical path. The README describes it as "a library for secure smart contract development" and lists what you get: implementations of standards such as ERC20 and ERC721, a role-based permissioning scheme, and reusable Solidity components for building custom contracts.

The audience is Solidity developers building on EVM chains. If you are shipping a token, a collectible, a vesting schedule or a permissioned contract, the library gives you a starting point that other people have already deployed. The README is direct about how to treat it: use the installed code as-is, and neither copy-paste it from online sources nor modify it yourself. That single instruction shapes everything else about how the project is meant to be consumed, and it is why installation method matters more here than in a typical dependency.

One design property is worth understanding early. The README states that the library is designed so that only the contracts and functions you use are deployed, so it does not needlessly increase gas costs. Solidity's compiler discards unused code, so importing a large package does not mean paying to deploy all of it.

How the library is structured and how imports resolve

The repository root holds a contracts/ directory, and the published npm package ships "/contracts/**/*.sol" while excluding "/contracts/mocks/**/*". So the import paths you write map directly onto directories in that folder: token/ERC721/ERC721.sol, token/ERC20, access, and utils. The README's own example imports from "@openzeppelin/contracts/token/ERC721/ERC721.sol", which tells you the naming convention is stable and path-based rather than a flat barrel file.

The library is consumed by inheritance, not by composition through an interface you call out to. You write a contract that extends ERC721, call the parent constructor with a name and symbol, and inherit the standard's behaviour. Access control works the same way: the README points to a role-based permissioning scheme and to an Ownable-style owner model, both of which are mixins you add to your own contract rather than services you call.

That inheritance model is the reason the storage layout warning exists. The README states that the library uses semantic versioning to communicate backwards compatibility of its API and storage layout, and that for upgradeable contracts the storage layout of different major versions should be assumed incompatible. Its example is blunt: upgrading from 4.9.3 to 5.0.0 is unsafe. If you use proxy patterns, the order and type of inherited state variables is part of your deployed contract's ABI-level contract with storage, and a major version can reorder it.

Installing OpenZeppelin Contracts with npm or Foundry

There are two supported installation routes, and they are not equivalent. The npm route is the one the README treats as default, and it resolves to an audited release. Run it in your project root:

bash
npm install @openzeppelin/contracts

That installs the latest audited release, because latest is the default NPM tag. If you want the finalized but not yet audited build instead, the README gives a second form:

bash
npm install @openzeppelin/contracts@dev

The tag table in the README explains the difference. latest holds audited releases and is what a bare install gives you. dev holds versions that are finalized and feature-complete but not yet audited; the README says they are fully tested, can be used in production and are covered by the bug bounty. next holds release candidates that are not final and are meant for testing before a version becomes dev or latest.

The Foundry route installs from git and carries two warnings the README prints in full. First, using the master branch is a common error; it is a development branch that should be avoided in favor of tagged releases, and the release process involves security measures master does not guarantee. Second, Foundry installs the latest version initially, but subsequent forge update commands will use the master branch. The install command is:

bash
forge install OpenZeppelin/openzeppelin-contracts

After that you add a remapping so the import path resolves. The README gives the exact line for remappings.txt:

text
@openzeppelin/contracts/=lib/openzeppelin-contracts/contracts/

With either route done, the first real use is an import and an inheritance. The README's example is an ERC-721 collectible:

solidity
pragma solidity ^0.8.20;

import {ERC721} from "@openzeppelin/contracts/token/ERC721/ERC721.sol";

contract MyCollectible is ERC721 {
    constructor() ERC721("MyCollectible", "MCO") {
    }
}

Compile it and you should get a contract that satisfies the ERC-721 interface with the name and symbol you passed. If you are new to the toolchain, the README points to a Developing Smart Contracts guide rather than repeating setup steps here.

Picking a release tag is a security decision, not a version preference

Most libraries treat the difference between a stable tag and a pre-release tag as a matter of taste. Here the README frames it as the boundary between audited and non-audited code, and publishes a table so you cannot miss it. A bare npm install lands on latest, which the table marks as audited. Adding @dev lands on code the README describes as fully tested and production-usable but not yet audited. The next tag is explicitly not final.

The Foundry path is the one that catches people. forge install pulls the latest version at first, but the README warns that later forge update commands will use the master branch. So a project that installed cleanly against a tagged release can silently move onto development code the next time someone updates dependencies. The README's own remedy is to avoid master in favor of tagged releases, which means pinning rather than tracking. If your team runs forge update as routine maintenance, that routine is the risk.

The same logic applies to the upgradeable question. The README's warning about storage layout is not about API breakage in the ordinary sense; it is about the fact that a proxy's storage slots are laid out by inheritance order, and a major version may change that order. Treating a major bump as a normal dependency update is the failure mode the documentation is trying to prevent.

Where OpenZeppelin Contracts is the wrong choice

The library is opinionated about being used unmodified, and that is a real constraint rather than a slogan. If your design requires altering the internals of ERC20 or ERC721 to fit a bespoke accounting model, you are working against the project's stated guidance, and you lose the main reason to depend on it. The README's instruction to use the installed code as-is and not modify it yourself means the value proposition and the flexibility trade off against each other.

It is also a Solidity library. Nothing here helps if your contracts are written in another language. The repository is Solidity throughout, the package name is openzeppelin-solidity, and the description is "Secure Smart Contract library for Solidity". If you are on Vyper, this package is not a candidate at all, and the question of which is better is a separate one the documentation does not address.

There is a scale question too. For a throwaway test token or a contract with no external value at stake, pulling in a full standards implementation and its inheritance chain may be more machinery than the job needs. The library does not force unused code into your deployment, but it does force you into its structure. A twenty-line token that you fully understand can be the better artifact when nothing depends on it.

Finally, the audits/ directory and the Security Center link tell you what has been reviewed, not what your contract does with it. An audited ERC-20 implementation says nothing about whether your minting logic, your access control wiring or your upgrade path is sound. The library removes one class of bug from your plate. It does not remove the rest.

Alternatives and the difference in approach

The most direct alternative is Solmate, which takes the opposite position on almost every design question here. Solmate is deliberately minimal and gas-oriented, and it expects you to read and adapt the code rather than inherit from a large, audited, versioned surface. Where OpenZeppelin Contracts maintains a semantic-versioning contract over API and storage layout, a minimal library has far less surface to keep compatible, and correspondingly less review behind each function. The trade is audit coverage and upgrade discipline against size and gas.

A second comparison is OpenZeppelin's own Contracts Wizard, which the README offers as the answer to "not sure how to get started". The Wizard is an interactive smart contract generator: you select the standard and the features, and it emits a contract. That is a different workflow from installing the library and importing from it, and for a standard token it may be the faster path to a first draft. It does not replace the dependency, because the generated contract still imports the library underneath.

A third option is writing the standard yourself from the EIP. This is defensible for ERC-20, which is small, and much less defensible for ERC-721, where the interface surface and the receiver-callback rules are easy to get subtly wrong. The honest framing is that the library is not competing on features. It is competing on the claim that the code has been reviewed and that its compatibility rules are documented.

Maintenance, licensing and what to verify before adopting

The repository is not archived, and the most recent push recorded is 2026-07-29, which is also the date of the v5.7.0 release. Before that, v5.7.0-rc.0 arrived on 2026-07-15 and v5.6.1 on 2026-02-27. The pattern shows release candidates being published ahead of final versions, which matches the tag table's description of next as pre-release versions used for testing and validation. The presence of a .changeset/ directory and a RELEASING.md at the repository root is consistent with a project that manages version bumps as an explicit process rather than ad hoc.

The licence is MIT. For most teams that is the permissive end of the spectrum and imposes few obligations beyond carrying the notice, but it is worth reading the LICENSE file rather than inferring terms from the SPDX identifier, and none of this is legal advice. The README does not document a paid tier, a commercial exception or a contributor licence agreement, so there is nothing suggesting the terms differ for commercial use.

The upgrade cost is where the real budget sits. Because semantic versioning covers storage layout, a major version bump is a migration project for any upgradeable deployment, not a dependency refresh. The README's own example of an unsafe path, 4.9.3 to 5.0.0, is the shape of the work: you re-verify storage, not just compilation. For non-upgradeable contracts the cost is much lower, because there is no persisted layout to preserve.

What to verify first depends on your route. If you installed with npm, confirm which tag you actually got, since latest and dev are one character apart in the command and represent audited versus unaudited code. If you installed with Foundry, check that your remapping points at a tagged release and that your update process does not drift onto master. If your contracts are upgradeable, read the Backwards Compatibility page the README links before planning any major version move.

Editorial conclusion

Adopt OpenZeppelin Contracts if you are writing Solidity and want ERC-20, ERC-721, ERC-1155, ERC-6909 or role-based permissioning that you did not write yourself; skip it if you want a minimal hand-rolled token or you are not on Solidity at all. Before you commit, check the NPM tag you installed against the tag table, confirm whether your project is upgradeable, and read the Backwards Compatibility page before crossing a major version.

Frequently asked questions

What are OpenZeppelin Contracts?

They are a Solidity library for secure smart contract development, maintained by OpenZeppelin. The README lists implementations of standards such as ERC20 and ERC721, a role-based permissioning scheme, and reusable components for building custom contracts.

Is OpenZeppelin safe?

The project publishes an audit history in its audits/ directory and maintains a Security Center page, and its NPM tags separate audited releases from unaudited ones. The README also warns that using the master branch is a common error because the release process applies security measures that branch does not guarantee.

How do I install OpenZeppelin Contracts?

With npm, run npm install @openzeppelin/contracts for the latest audited release, or append @dev for the latest unaudited one. With Foundry, run forge install OpenZeppelin/openzeppelin-contracts and add the remapping line the README gives for remappings.txt.

How do I install OpenZeppelin Contracts in Foundry?

Run forge install OpenZeppelin/openzeppelin-contracts, then add @openzeppelin/contracts/=lib/openzeppelin-contracts/contracts/ to remappings.txt. The README warns that later forge update commands will use the master branch, so pin to a tagged release instead.

How do I use OpenZeppelin Contracts?

Import the contract you need and inherit from it. The README's example imports ERC721 from @openzeppelin/contracts/token/ERC721/ERC721.sol and declares a contract that extends it, passing a name and symbol to the parent constructor.

Official sources

  1. Official documentation
  2. Official README
  3. Project repository
  4. Release notes
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/openzeppelin-openzeppelin-contracts.svg)](https://hysenlabs.com/projects/openzeppelin-openzeppelin-contracts)