Upgrading Hyperledger Fabric components replaces peer, orderer, Fabric CA, CouchDB, and client binaries while keeping existing ledger and MSP material intact. Network administrators perform this work before enabling newer channel capabilities or rolling out version-specific features across a channel.
Fabric treats a component upgrade as a binary or container replacement, not as a ledger migration. Ordering nodes should move first, peers follow in rolling order, and channel capability updates stay separate until every required node has the target binaries.
The sample flow uses a Docker CLI deployment with environment files and mounted ledger or MSP directories. Replace the container names, mounted paths, image tags, CA database backup command, and chaincode smoke test with values from the network being upgraded.
$ export FABRIC_IMAGE_TAG=3.1.5 $ export FABRIC_CA_IMAGE_TAG=1.5.21 $ export COUCHDB_IMAGE_TAG=3.4.2 $ export LEDGERS_BACKUP=/var/backups/fabric-components
Use the Fabric, Fabric CA, and CouchDB versions approved for the network. Do not update channel capabilities until all required peers, orderers, and client tools are already on compatible binaries.
$ mkdir -p "$LEDGERS_BACKUP"
$ docker exec orderer.example.com orderer version orderer: Version: v2.5.16 Commit SHA: f871cf9 Go version: go1.26.4 OS/Arch: linux/amd64
$ docker exec peer0.org1.example.com peer version peer: Version: v2.5.16 Commit SHA: f871cf9 Go version: go1.26.4 OS/Arch: linux/amd64 Chaincode: Base Docker Label: org.hyperledger.fabric Docker Namespace: hyperledger
$ docker exec ca.org1.example.com fabric-ca-server version fabric-ca-server: Version: v1.5.17 Go version: go1.25.7 OS/Arch: linux/amd64
$ docker stop orderer.example.com orderer.example.com
Upgrade orderers one node at a time. Stopping enough orderers to lose quorum interrupts ordering service availability for every channel that depends on the ordering cluster.
$ docker cp orderer.example.com:/var/hyperledger/production/orderer "$LEDGERS_BACKUP/orderer.example.com"
If the orderer already stores ledger data on a host volume, also take the normal host-volume or storage-layer backup before replacing the container.
$ docker rm orderer.example.com
orderer.example.com
$ docker run --detach \ --name orderer.example.com \ --env-file ./env-orderer.example.com.list \ --volume /opt/fabric/orderer.example.com/msp:/etc/hyperledger/fabric/msp \ --volume /opt/fabric/orderer.example.com/tls:/etc/hyperledger/fabric/tls \ --volume /opt/fabric/orderer.example.com/production:/var/hyperledger/production/orderer \ hyperledger/fabric-orderer:"$FABRIC_IMAGE_TAG" orderer 6d10a8e8f086d3b7190d7a1cfd8a5e5d8935efb0e8bb0f404c1d7c71e8d47c83
Use the same environment file, MSP, TLS material, listen ports, and ledger volume that the previous orderer used unless the upgrade plan intentionally changes them.
$ docker exec orderer.example.com orderer version orderer: Version: v3.1.5 Commit SHA: 86c1172 Go version: go1.26.4 OS/Arch: linux/amd64
$ docker stop peer0.org1.example.com peer0.org1.example.com
$ docker cp peer0.org1.example.com:/var/hyperledger/production "$LEDGERS_BACKUP/peer0.org1.example.com"
A peer with CouchDB also needs the matching CouchDB data backup before the peer returns to service.
$ docker container ls --all --filter "name=dev-peer0.org1.example.com" CONTAINER ID IMAGE COMMAND CREATED STATUS NAMES a9dc7b1c0d2e dev-peer0.org1.example.com-basic_1.0 "chaincode -peer.add…" 2 months ago Exited (0) dev-peer0.org1.example.com-basic_1.0-a9dc7b1c
$ docker rm --force dev-peer0.org1.example.com-basic_1.0-a9dc7b1c dev-peer0.org1.example.com-basic_1.0-a9dc7b1c
Remove only chaincode containers that belong to the peer being replaced. Other peers continue endorsing while this peer is offline.
$ docker rm peer0.org1.example.com
peer0.org1.example.com
$ docker run --detach \ --name peer0.org1.example.com \ --env-file ./env-peer0.org1.example.com.list \ --volume /opt/fabric/peer0.org1.example.com/msp:/etc/hyperledger/fabric/msp \ --volume /opt/fabric/peer0.org1.example.com/tls:/etc/hyperledger/fabric/tls \ --volume /opt/fabric/peer0.org1.example.com/production:/var/hyperledger/production \ hyperledger/fabric-peer:"$FABRIC_IMAGE_TAG" peer node start 25d7d61c3f67cc02379d1ee167b5a2ab6fa66d0c5dc6ee9f1bd9a3d7df5a9ad0
Repeat the peer stop, backup, chaincode-container cleanup, remove, start, and version check for each peer in the organization before moving to the next organization.
$ docker exec peer0.org1.example.com peer version peer: Version: v3.1.5 Commit SHA: 86c1172 Go version: go1.26.4 OS/Arch: linux/amd64 Chaincode: Base Docker Label: org.hyperledger.fabric Docker Namespace: hyperledger
$ docker stop couchdb0.org1.example.com couchdb0.org1.example.com
$ docker cp couchdb0.org1.example.com:/opt/couchdb/data "$LEDGERS_BACKUP/couchdb0.org1.example.com"
$ docker rm couchdb0.org1.example.com
couchdb0.org1.example.com
$ docker run --detach \ --name couchdb0.org1.example.com \ --env-file ./env-couchdb0.org1.example.com.list \ --volume /opt/fabric/couchdb0.org1.example.com/data:/opt/couchdb/data \ couchdb:"$COUCHDB_IMAGE_TAG" 1dbd0f9180ff4a4a7f1dc33d24de1e177d6d14c7c3f7dd5ef5c8759a5fbb0fc1
Keep the peer offline while its CouchDB data store is being replaced. A peer and its state database must return as a matched pair.
$ curl -u "$COUCHDB_USER:$COUCHDB_PASSWORD" http://couchdb0.org1.example.com:5984/ {"couchdb":"Welcome","version":"3.4.2","git_sha":"690552d","uuid":"0d37f8c7f977f02e"}
$ docker stop ca.org1.example.com ca.org1.example.com
$ docker cp ca.org1.example.com:/etc/hyperledger/fabric-ca-server "$LEDGERS_BACKUP/ca.org1.example.com"
Use the deployment's database backup tool when the CA server stores identities in PostgreSQL, MySQL, or another external database instead of the default local database file.
$ docker rm ca.org1.example.com
ca.org1.example.com
$ docker run --detach \ --name ca.org1.example.com \ --env-file ./env-ca.org1.example.com.list \ --volume /opt/fabric/ca.org1.example.com:/etc/hyperledger/fabric-ca-server \ hyperledger/fabric-ca:"$FABRIC_CA_IMAGE_TAG" fabric-ca-server start c280b36f23030d89732709514c7a5a7ed0a0c1a76f0f79596b125dd62729a3e9
$ docker exec ca.org1.example.com fabric-ca-server version fabric-ca-server: Version: v1.5.21 Go version: go1.26.4 OS/Arch: linux/amd64
Renew or reenroll identities only when the upgrade plan also changes certificate material or when certificates are near expiry.
Related: How to renew a Hyperledger Fabric certificate
$ npm install @hyperledger/fabric-gateway@latest changed 3 packages, and audited 104 packages in 2s found 0 vulnerabilities
Use the package manager for the application language, such as npm, Go modules, Maven, or pip. Keep the client SDK change in a separate application release if the node upgrade needs a fast rollback path.
$ peer chaincode query -C mychannel -n basic -c '{"Args":["ReadAsset","asset1"]}' {"ID":"asset1","color":"blue","size":5,"owner":"Tomoko","appraisedValue":300}
The query confirms that the upgraded peer, orderer path, state database, and client binary can still read committed ledger state. Use a write transaction as the final smoke test when the maintenance plan allows a harmless test update.
Related: How to query Hyperledger Fabric chaincode