Diff two contract ABIs and get the breaking changes + a semver bump — like semver, but for your smart contract's interface. Zero dependencies, runs with
npx.
You redeploy a contract, or cut a new version of an SDK, and its ABI changes — a
function gets removed, a parameter type changes, an event's indexed layout shifts. Every
one of those quietly breaks the apps and indexers calling your contract, and today most
teams find out by eyeballing two JSON files or, worse, in production.
abidiff treats your ABI like the public API it is. Point it at the old and new ABI and it
tells you what changed, what's breaking, and the semver bump you should ship:
$ abidiff old.json new.json
● 5 breaking change(s):
function balanceOf(address)
function removed
function transfer(address,uint256)
return type changed (bool -> void)
function deposit()
stateMutability changed (payable -> nonpayable)
event Transfer(address,address,uint256)
event `indexed` layout changed — log decoding will break
error Unauthorized()
error removed
● 1 addition(s):
function approve(address,uint256)
function added
suggested semver bump: MAJOR (5 breaking · 1 added)
Exit code 1 on any breaking change — so it drops into CI to gate a contract/SDK release.
- a function / event / error is removed or its signature changes
- a function's return type changes
- a function becomes more restrictive (
payable→nonpayable) - an event's
indexedlayout changes (breaks log/topic decoding)
New functions, events, or errors are additions (backward compatible) → a minor bump.
Nothing changed → none.
There are plenty of tools to extract an ABI (forge inspect, hardhat exporters) and
plenty of semver tools for npm packages and TypeScript types — but nothing dedicated to
answering "did my contract's interface break?" Teams do it by hand or with one-off
scripts. abidiff is that missing check, and it needs no chain, no RPC, no keys — just two
JSON files.
npx abidiff old.json new.json # no install
# or
npm i -g abidiffZero runtime dependencies; needs Node ≥ 18.
abidiff old.json new.json # human report + semver bump
abidiff old.json new.json --json # machine-readableIt accepts a raw ABI array or a Hardhat/Foundry artifact ({ "abi": [...] }), so
you can point it straight at your build output.
# GitHub Actions — fail the release PR on a breaking ABI change
- run: npx abidiff artifacts/old/Token.json artifacts/Token.json- It compares interfaces (ABIs), not behavior — it can't tell you a function's logic changed, only that its shape did.
- Breaking-ness is from a caller/consumer perspective (removed/changed = breaking).
Whether a change matters for your consumers is still your call;
--jsonlets you wire your own policy. - Overloads are compared by full signature, so an added overload reads as an addition.
MIT — see LICENSE.