OpenZeppelin ships three npm tags, and only one of them has been audited
OpenZeppelin Contracts is a library for secure smart contract development.
At a glance
- What is it?
- OpenZeppelin Contracts is a Solidity library of token standards, role-based access control and utilities, published under MIT and installed with a single npm command. What the release tags actually promise, what `forge update` does to a Foundry checkout, and why storage layouts of different major versions must be assumed incompatible are the three things that decide whether it is safe to depend on.
- Who is it for?
- OpenZeppelin Contracts is the right default for ERC20, ERC721, ERC1155, access control and the utility primitives, and the npm tag system lets you choose how much review you want. Do not treat the audit as covering your contract, and do not install it through a Foundry git dependency without pinning a tag, because `forge update` moves you onto the development branch.
- 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 1 day 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 November 14, 2026, and from our analysis. They are not legal advice.
Star history
- OpenZeppelin/openzeppelin-contracts27,361 ★ · +159
| Repository | 2026-07-28 | 2026-11-14 |
|---|---|---|
| OpenZeppelin/openzeppelin-contracts | 27.2k | 27.4k |
159 Stars in the last 109 days, measured from the daily GitHub snapshot. Compare with other projects
Editorial analysis
Three npm tags, and the difference between them is audit status alone
The distribution channels are not interchangeable, and the project is explicit about which is which.
`latest` is the default. Running `npm install @openzeppelin/contracts` with no version gets it, and it contains stable, audited versions.
`dev` contains versions that are finalized and feature-complete but have not yet been audited. The description goes further and says this version is fully tested, can be used in production and is covered by the bug bounty. So the distinction is not test coverage and not stability. It is audit, and nothing else.
`next` holds release candidates that are not final, used for testing and validation before a version becomes a final `dev` or `latest` release.
That gives you three honest choices rather than a good one and two bad ones. Take `dev` when you need a fix or a feature that has not been audited yet and your own review will cover the delta. Stay on `latest` when the audit is the thing you are buying.
Getting this wrong is easy to do silently, because `@dev` is a one-word change to an install command and nothing about the resulting code announces its review status.
forge update walks your checkout onto the master branch, which the README warns about twice
The Foundry install path has two warnings attached, and both are about the same failure.
The first says that when installing via git it is a common error to use the `master` branch, that this is a development branch which should be avoided in favor of tagged releases, and that the release process involves security measures the `master` branch does not guarantee.
The second says Foundry installs the latest version initially, but subsequent `forge update` commands will use the `master` branch.
Read those together and the hazard is specific. The install command is fine:
$ forge install OpenZeppelin/openzeppelin-contractsbut the first time you run `forge update` in a normal dependency-update routine, your dependency moves from a tagged release onto the development branch. Nothing errors. The build continues, tests pass, and your lock state now points at unreviewed code that the project has told you not to use.
The import path then needs a remapping in `remappings.txt`:
@openzeppelin/contracts/=lib/openzeppelin-contracts/contracts/If you take the git route, pin the dependency to a tag in your Foundry manifest and check after every `forge update` that the reference still names a release.
A major version bump rewrites storage layout, which makes 4.9.3 to 5.0.0 unsafe
The Important notice at the top of the README is about storage, not about code. OpenZeppelin Contracts uses semantic versioning to communicate backwards compatibility of its API and storage layout. For upgradeable contracts, the storage layout of different major versions should be assumed incompatible, and the given example is that it is unsafe to upgrade from 4.9.3 to 5.0.0.
The reason is that an upgradeable proxy keeps reading the old layout. If a base contract gains, loses or reorders a state variable, every slot after it shifts, and a proxy that has not been migrated will read one field as another. The function bodies may compile cleanly while the stored data means something different.
That is a category of bug that a compiler cannot catch and that a test suite written against fresh state will not catch either, because the damage only appears against a proxy that already holds data.
The practical rule follows from it. Treat a major version as a migration project with its own storage plan, not as a dependency bump. Note also that the same compatibility promise covers the API and the layout, so a minor or patch release inside a major is the only upgrade you can make without thinking about this.
The security guarantee covers the installed artifact, which is why copy-pasting defeats it
The usage section carries an instruction that sounds like housekeeping and is not: to keep your system secure, you should always use the installed code as-is, and neither copy-paste it from online sources nor modify it yourself.
The reason is visible in the tag structure. What carries an audit is a published release, not a snippet. Paste a function body into your own file and what you deploy is your file, carrying whatever edits, omissions and typos came with the paste, and it is outside anything the project's review process looked at.
The same paragraph makes the opposite point about size. The library is designed so that only the contracts and functions you use are deployed, so you don't need to worry about it needlessly increasing gas costs. In Solidity that means unused code in an inheritance chain is not shipped, so there is no reason to avoid inheriting a larger base for fear of the bytecode.
Those two claims pull in opposite directions and both hold. Size is not a reason to hand-copy, and hand-copying is what voids the review.
Two build systems and a formal verification harness in one repository
The repository builds with both of the toolchains it tells you to install. `hardhat.config.ts` and a `hardhat/` directory cover the npm path, and `foundry.toml` covers the git path. The repository root also carries `slither.config.json` and `solhint.config.cjs`, so static analysis and Solidity linting are configured in-tree rather than left to the consumer.
Formal verification gets its own directory. `fv/` holds harnesses, `fv-requirements.txt` records the requirements, and there is a dedicated script that builds them:
compile:harnesseswhich sets `SRC=./fv/harnesses` and runs `hardhat build --noExpose`. A separate `audits/` directory sits at the root.
Two other scripts handle packaging and versioning: `prepack` runs `scripts/prepack.sh`, and `version` runs `scripts/release/version.sh`.
The message is that the review story is mechanical and repeatable rather than a matter of individual vigilance.
Inheritance ordering and pragma ranges are machine-checked, not reviewer-checked
Three of the npm scripts exist to enforce conventions that would otherwise be caught by a human reading a diff.
`test:inheritance` builds with `--noExpose` and then runs `scripts/checks/inheritance-ordering.js` against `artifacts/build-info/*.output.json`. Base constructor call ordering in Solidity has to match the inheritance linearization, and getting it wrong is confusing to debug, so the project checks it against compiler output on every run.
`test:pragma` does the same for version pragmas, running `scripts/checks/pragma-validity.js` over the build artifacts. Related to that is the `pragma` script itself, which builds and then pipes `artifacts/build-info/*` through `scripts/minimize-pragma.js`, so every contract declares the narrowest version range it actually compiles under.
`test:generation` runs `scripts/checks/generation.sh`, which exists because parts of the tree are generated by `scripts/generate/run.js` and generated code drifts from handwritten code unless something compares them.
The pattern is consistent across the project: whatever could be a review comment becomes a script that fails. `lint` covers JavaScript through prettier and eslint, and Solidity through prettier and solhint, and `prepare` runs husky.
The npm tarball ships contracts only, so the mocks and the docs are not in node_modules
The `files` array in `package.json` is short enough to read in full:
/contracts/**/*.sol
!/contracts/mocks/**/*Two things follow. The published package is Solidity sources under `contracts/` and essentially nothing else, with `contracts/mocks/**` explicitly excluded. And the documentation under `docs/` is not part of the tarball.
The mock exclusion is deliberate and reasonable, since mock contracts exist for testing and are not something you want to import by accident in production code. The practical consequence is that if you were planning to use the project's mocks from an npm install, they are in the git repository and not in the package, so you would need the git route.
The missing docs matter more day to day. The NatSpec comments in the source are not sitting in your `node_modules` copy in a convenient form, so reading the API detail for a contract means going to docs.openzeppelin.com, or reading the source you already have installed.
For reference while reading source, the documentation site splits into Access Control for deciding who can perform each action, Tokens for the ERC standards including ERC-20, ERC-721, ERC-1155 and ERC-6909, and Utilities for non-overflowing math, signature verification and trustless paying systems. One caveat the project raises itself: several of the background articles on its blog reference tools that have since changed, because the tooling keeps moving.
Editorial conclusion
OpenZeppelin Contracts is the right default for ERC20, ERC721, ERC1155, access control and the utility primitives, and the npm tag system lets you choose how much review you want. Do not treat the audit as covering your contract, and do not install it through a Foundry git dependency without pinning a tag, because `forge update` moves you onto the development branch. Before your first deployment, verify two things: that your installed version came from `latest` rather than `dev` if audit status matters to you, and, for anything upgradeable, that you are not crossing a major version, since the storage layout of different majors should be assumed incompatible. The current release is v5.7.0, published 2026-07-29.
Frequently asked questions
What are OpenZeppelin Contracts?
It is a library for secure smart contract development, written in Solidity and licensed under MIT. It provides implementations of standards such as ERC20 and ERC721, a flexible role-based permissioning scheme, and reusable Solidity components, with its documentation at docs.openzeppelin.com/contracts.
Is OpenZeppelin safe to use?
The npm latest tag carries audited releases, while dev carries finalized versions that are not yet audited, so audit status is something you select rather than something you inherit. The README instructs you to always use the installed code as-is, neither copy-pasting from online sources nor modifying it, which is what keeps a deployment inside the reviewed artifact.
How do I install OpenZeppelin Contracts?
With npm, run npm install @openzeppelin/contracts for the latest audited release, or npm install @openzeppelin/contracts@dev for the latest unaudited one. Under Hardhat that is all; the contracts are then imported by path, for example from @openzeppelin/contracts/token/ERC721/ERC721.sol.
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 subsequent forge update commands will use the master branch, which is a development branch that should be avoided in favor of tagged releases.
How do I use OpenZeppelin Contracts in my own contract?
Import the contract you need and inherit from it, setting the Solidity pragma to at least ^0.8.20. The example in the README inherits ERC721 and passes the name and symbol to its constructor as ERC721("MyCollectible", "MCO"). Only the contracts and functions you use are deployed, so inheriting a larger base does not inflate gas costs.
Official sources
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.
[](https://hysenlabs.com/projects/openzeppelin-openzeppelin-contracts)Star history chart for your README
[](https://hysenlabs.com/projects/openzeppelin-openzeppelin-contracts)Was this useful?