System Channel and Application Channel in Hyperledger Fabric


It begins with a question I have been asked several times in the past few months. Some have completed the tutorial Add an Org to a Channel, successfully adding a new organization to a channel. When they try to add this organization to a new channel, they encounter problems. The cause drives me to some system design of Hyperledger Fabric, in particular, on system channel.

Test Network: Modified for Demonstration

In this demonstration, we are using the Test Network (v2.0+). It is a two-peer-org setup, one peer on each org, plus a Solo-based ordering service. It comes with good scripts ( to bring up containers, create channels and deploy sample chaincode (fabcar). Besides it also provides scripts to implement the tutorial Adding an Org to a Channel.


We use the cryptogen (not Fabric CA Server) for simplicity. In the original directory structure organizations/cryptogen/, we have

  • crypto-config-org1.yaml
  • crypto-config-org2.yaml

channel artifacts

The configuration file is configtx/configtx.yaml.

docker compose file

The only docker compose file we are using is docker/docker-compose-test-net.yaml. Inside we add The container setup is largely similar to other peers, except for the correct crypto material and port number to be used.


With these configuration files modified, we have generated certain material for our demonstration. Detail is skipped here. The material we have generated in the repository are

  • genesis block, configuration update transactions for mychannel, and configuration transaction for channel1–3.
  • the content to be inserted into configuration in JSON, named org3.json, is generated and kept in peersOrganization/

Tutorial Replay

Here we follow the tutorial Adding an Org to a Channel. Instead of repeating every command, here we just showed the screenshots of the results on main steps. join mychannel join mychannel not joining mychannel yet
Signing from Org1 (
Signing from Org2 ( and submit to ordering service (new block committed) (new block committed)
Fetch channel genesis block from
Join with genesis block file gets the blockchain from other peers
After completing the tutorial, peer0.org3 is now a member of mychannel.

Simulating the Problem

Create the genesis block file for channel1–3. Remember that in channel1–3 we have defined Org3 as a channel member.

peer channel create -o localhost:7050 -c channel1-3 --ordererTLSHostnameOverride -f ./channel-artifacts/channel1-3.tx --outputBlock ./channel-artifacts/channel1-3.block --tls --cafile $ORDERER_CA

Observation: System Channel and Application Channel

As we mentioned before, there is one system channel when the consortium network is up and running. Inside the system channel we find two main configuration settings: orderers and consortium members. This system channel needs to be updated when any change of ordering service (e.g. one more orderer added to a cluster) or new consortium member (organization) is added.

Configuration file: configtx.yaml

We first take a look at the configuration file configtx.yaml. The part we are interested in is the profiles.

The original configtx.yaml only has these two profiles defined.
configtxgen -profile TwoOrgsOrdererGenesis -channelID system-channel -outputBlock ./system-genesis-block/genesis.block
configtxgen -profile TwoOrgsChannel -outputCreateChannelTx ./channel-artifacts/mychannel.tx -channelID mychannel

Configuration Block captured in System Channel

We use Terminal for Orderer in order to fetch the system channel.

source terminalordererpeer channel fetch config config_block_sys.pb -o localhost:7050 --ordererTLSHostnameOverride -c system-channel --tls --cafile $ORDERER_CA
Extract from the configuration block from system-channel

Configuration Block captured in Application Channel

We use Terminal for Org1 to capture the latest configuration update (should be block #3).

Extract from the configuration block from mychannel (application channel)


Even though Org3 is being added in an application channel (mychannel), it is not yet in consortium and therefore we cannot create a new channel in which Org3 is a member. What we need is to add it back to the system channel.

block file for channel1–3 cannot be created as Org3 is not yet in consortium

Add Org3 to System Channel and then Create Channel with Org3

Now we understand that, in order to allow new channels to be created for a new organization, this organization must be added in consortium first. Here we demonstrate how to add organization to the consortium (system channel) such that we can add a new channel.

Fetch configuration block from system channel

Note: all commands here is done in terminal for Orderer.

source terminalordererpeer channel fetch config config_block_sys.pb -o localhost:7050 --ordererTLSHostnameOverride -c system-channel --tls --cafile $ORDERER_CA

Construct configuration update

With this, we go through the similar process of adding Org3 to Application Channel as before. But now this process is acting upon the configuration block from the system channel.

configtxlator proto_decode --input config_block_sys.pb --type common.Block | jq[0] > config.jsonjq -s '.[0] * {"channel_group":{"groups":{"Consortiums":{"groups":{"SampleConsortium":{"groups": {"Org3MSP":.[1]}}}}}}}' config.json ./organizations/peerOrganizations/ > modified_config.jsonconfigtxlator proto_encode --input config.json --type common.Config --output config.pbconfigtxlator proto_encode --input modified_config.json --type common.Config --output modified_config.pbconfigtxlator compute_update --channel_id system-channel --original config.pb --updated modified_config.pb --output org3_update.pbconfigtxlator proto_decode --input org3_update.pb --type common.ConfigUpdate | jq . > org3_update.jsonecho '{"payload":{"header":{"channel_header":{"channel_id":"'system-channel'", "type":2}},"data":{"config_update":'$(cat org3_update.json)'}}}' | jq . > org3_update_in_envelope.jsonconfigtxlator proto_encode --input org3_update_in_envelope.json --type common.Envelope --output org3_update_in_envelope.pb

Sign the update with orderer admin

Keep working in the Terminal for Orderer as orderer admin is needed to sign and submit the transaction.

peer channel update -f org3_update_in_envelope.pb -o localhost:7050 --ordererTLSHostnameOverride -c system-channel --tls --cafile $ORDERER_CA
peer channel fetch config config_block_sys_update.pb -o localhost:7050 --ordererTLSHostnameOverride -c system-channel --tls --cafile $ORDERER_CA
We see Org3MSP is already included in the Consortium.

Create Channel with Org3

Now create new channel channel1–3, which includes Org3 as a channel member.

peer channel create -o localhost:7050 -c channel1-3 --ordererTLSHostnameOverride -f ./channel-artifacts/channel1-3.tx --outputBlock ./channel-artifacts/channel1-3.block --tls --cafile $ORDERER_CA
Block file for channel1–3 is now created successfully
Terminal for Org1
Terminal for Org3
  • channel1–3: Org1 and Org3
Top: Org1, Middle: Org2, Bottom: Org3
block file for channel1–3 is created after Org3 is added in consortium


We begin with a problem we meet: according to the tutorial, we can add an organization to a channel, but we cannot add new channels with this newly added organization. The reason behind is that an organization needs to be in consortium before we can create new channels with this newly added organization. We find that we are in fact dealing with two different types of channels: one system channel, keeping the consortium configuration, and one or more application channels, which is the “channel” we always refer to, where shared ledger and business logic is enforced among selected consortium members. In this article we have deep-dived into configuration files, blocks captured on the system channel and application channel. We also demonstrated how to add a new organization into a consortium, such that this organization can later be added into another application channel. Hope this provides a good reference when you study Hyperledger Fabric.

Visit for all my works. Reach me on or follow me @kctheservant in Twitter.

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store