Fablo allows you to start Hyperledger Fabric network from a single config file. It's best for local development, CI processes and experimenting with various network configurations.
Fablo supports:
- Environment: Docker
- RAFT, solo and BFT consensus protocols
- Multiple organizations and channels
- Chaincode installation and upgrade (Node, Go, Java, CCaaS)
- REST API client for CA and chaincodes (Fablo REST)
- Blockchain Explorer which can be enabled for each organization
Visit SUPPORTED_FEATURES.md to see the full list of features supported by Fablo.
curl fablo.io/install.sh | bash
./fablo init node rest
./fablo upThis will create a local Hyperledger Fabric network with a sample Node.js chaincode (using the node parameter) and a REST API client (using the rest parameter).
After a few minutes, the entire network will be set up and running.
You can check the running nodes using docker ps or docker stats. You can also query the network via the command line (fablo chaincode invoke or fablo chaincode query), use the REST API client (see Fablo REST), or view the network topology in the fablo-target/network-topology.mmd Mermaid diagram.
Fablo is distributed as a single shell script that uses a Docker image to generate the network configuration. To install it locally in your project directory:
curl fablo.io/install.sh | bash
# OR
curl fablo.io/fablo.sh > fablo && chmod +x fabloTo install it globally on your system:
sudo curl fablo.io/fablo.sh -o /usr/local/bin/fablo && sudo chmod +x /usr/local/bin/fabloTo install a given version use:
curl https://github.com/hyperledger-labs/fablo/releases/download/<version>/fablo.shTo change version of current installation:
fablo use <version>Note: If you install Fablo as a local script, you call it as ./fablo <command>.
If you install it globally, you call fablo <command>.
For the simplicity we will refer to it as fablo.
fablo up /path/to/fablo-config.jsonThe up command creates the initial configuration and starts the Hyperledger Fabric network on Docker.
The network configuration is saved in $(pwd)/fablo-target.
You can then manage the network with other commands such as stop, start, down, and prune.
The Fablo configuration file describes the network topology: root organization, other organizations, channels, and chaincodes. See the samples or Fablo config section for examples.
There are two basic use cases.
You may use Fablo to start and manage the network for development purposes, test different network topologies, run it in CI environment etc.
In this case you should keep fablo-target directory intact and out of the version control.
Fablo will manage it locally.
On the other hand you can use Fablo to generate initial network configuration, keep it in version control and tweak for specific requirements.
In this case, however, you should use the generated fabric-docker.sh instead of the fablo script.
fablo init [node] [rest] [dev] [ccaas] [gateway] [--set <path>=<value> ...]Creates a simple network configuration file (fablo-config.json) in the current directory.
This is a good starting point for your Fablo journey or to set up a quick prototype.
The generated network configuration includes an orderer organization with two BFT orderer nodes and a peer organization with two peers.
It uses Fabric version 3.1.0 with TLS enabled.
The fablo init command accepts several optional parameters (order doesn't matter):
node- copies a sample Node.js chaincode intochaincodes/chaincode-kv-nodeand adds it to the configrest- enables Fablo REST for every organization in the generated configdev- when you use it together withnode, the sample chaincode becomes a CCaaS chaincode with the source code mounted, so it reloads when you change the codeccaas- adds a sample CCaaS chaincode that runs from a prebuilt image. You cannot combine it withnodeordevgateway- copies a sample Node.js gateway app intogateway/node. It does not change the config file
Sample command:
fablo init node devfablo init fabric-x [--set <path>=<value> ...]Creates a minimal config for the experimental Fabric-X provider, with global.provider set to fabric-x.
You cannot combine fabric-x with node, rest, dev, ccaas or gateway.
# Single override
fablo init --set global.fabricVersion=2.5.0
# Multiple overrides
fablo init --set global.tls=false --set orgs[1].peer.db=CouchDb
# With positional arguments
fablo init node --set global.fabricVersion=3.0.0 --set orgs[1].peer.instances=5
# Nested paths
fablo init --set global.monitoring.loglevel=debug --set channels[0].name=my-channel2fablo generate [/path/to/fablo-config.json|yaml [/path/to/fablo/target]]Generates network configuration files in the specified directory.
Default config file path is $(pwd)/fablo-config.json or $(pwd)/fablo-config.yaml, default directory is $(pwd)/fablo-target.
If you specify a different directory, you lose Fablo support for other commands.
If you want to use Fablo only to generate the Hyperledger Fabric network configuration, you can provide a target directory parameter or copy the generated fablo-target directory content to your desired directory and add it to version control.
Note that generated files may contain variables with paths on your disk and generated crypto material for Hyperledger Fabric.
Review the files before committing to version control.
fablo up [/path/to/fablo-config.json|yaml]Starts the Hyperledger Fabric network for the given Fablo configuration file, creates channels, and installs and deploys chaincodes (package / install / approve / commit).
If the fablo-target directory is missing or empty, Fablo runs the generate command for the given config file first.
If the network is already generated and the config file has changed since then, up stops with an error and prints the difference, so you have to run prune or recreate before the change takes effect.
fablo <down | start | stop>Downs, starts, or stops the Hyperledger Fabric network for the configuration in the current directory. This is similar to the down, start, and stop commands for Docker Compose.
fablo pruneDowns the network and removes the fablo-target directory.
fablo reset
fablo recreate [/path/to/fablo-config.json|yaml]reset- combines down and up steps. Network state is lost, but the configuration is kept intact. Useful when you want a fresh network instance without any state.recreate- prunes the network, generates new config files, and starts the network. Useful when you've edited thefablo-configfile and want to start a newer network version in one command.
fablo validate [/path/to/fablo-config.json|yaml]Validates the network configuration against the schema and with extra checks across fields, and suggests necessary changes or additional tweaks.
It is a separate command, so generate and up do not run it for you.
fablo export-network-topology [/path/to/fablo-config.json|yaml [outputFile.mmd]]outputFile.mmd: (optional) Path to the output Mermaid file. Defaults tonetwork-topology.mmd.
Sample command:
fablo export-network-topology fablo-config.json network-topology.mmdYou can visualize the output using any Mermaid-compatible tool or online editor.
fablo extend-config [/path/to/fablo-config.json|yaml]Reads the Fablo config file, fills in the default and computed values, and prints the extended config as JSON on standard output. It does not write any file, so it is mostly useful for debugging.
Fablo supports saving state snapshots (backups) of the network and restoring them. It saves all network artifacts, certificates, and data from CA, orderer, and peer nodes. Note that the snapshot does not contain the Fablo config file and chaincode source code, as both can be located outside the Fablo working directory.
Snapshotting is useful if you want to preserve the current state of a network for future use (testing, sharing the network state, courses, etc.).
fablo snapshot <target-snapshot-path>To restore a snapshot into the current directory, run:
fablo restore <source-snapshot-path> [hook-command]The optional hook command is a Bash command that Fablo runs in the restored directory before it creates the containers.
Example:
- Assume you have a working network with some state.
- Run
./fablo snapshot /tmp/my-snapshot. This creates a file/tmp/my-snapshot.fablo.tar.gzwith the network state. You don't need to stop the network before making a snapshot. - Run
./fablo pruneto destroy the current network. If the network is present, Fablo won't be able to restore the new one from backup. - Run
./fablo restore /tmp/my-snapshotto restore the network. - Run
./fablo startto start the restored network. - When running external chaincodes (CCAAS), run
./fablo chaincodes installto start the CCAAS container
Typically, a snapshot of a network with little data will be less than 1 MB, making it easy to share.
The fabric-docker.sh script is generated alongside the Docker network configuration.
It supports up, down, start, stop, reset, the chaincode and chaincodes commands, the channel commands and snapshot, and they work the same way as in fablo.
Commands such as init, generate, validate, prune, recreate, restore and use are handled by the fablo script itself.
Essentially, fablo forwards the remaining commands to fabric-docker.sh.
If you want to use Fablo for network configuration setup only, the fabric-docker.sh file allows you to manage the network.
fablo chaincodes installInstalls all chaincodes. This might be useful if Fablo fails to install them automatically.
To install a single chaincode defined in the Fablo config file, run:
fablo chaincode install <chaincode-name> <version>fablo chaincode upgrade <chaincode-name> <version>Upgrades the chaincode with the given name on all relevant peers. The chaincode directory is specified in the Fablo config file.
Invokes a chaincode with the specified parameters.
fablo chaincode invoke <peer_domains_comma_separated> <channel_name> <chaincode_name> <command> [transient]
Sample command:
fablo chaincode invoke "peer0.org1.example.com" "my-channel1" "chaincode1" '{"Args":["KVContract:put", "name", "Willy Wonka"]}'
Queries a chaincode on a single peer. Transient data is optional.
fablo chaincode query <peer_domain> <channel_name> <chaincode_name> <command> [transient]
Sample command:
fablo chaincode query "peer0.org1.example.com" "my-channel1" "chaincode1" '{"Args":["KVContract:get", "name"]}'
Lists the chaincodes installed on the given peer for the given channel.
The peer is given as its full domain, for example peer0.org1.example.com, and the channel is given by name.
fablo chaincodes list <peer_domain> <channel_name>
Sample command:
fablo chaincodes list peer0.org1.example.com my-channel1
Hot reload of chaincode code is a way to speed up development. In this case, chaincodes don't need to be upgraded each time, but they are run locally.
Fablo supports two options for achieving hot code reload in chaincodes:
- Using Hyperledger Fabric peer dev mode
- Using CCaaS chaincode type with the chaincode process running inside the container
The peer dev mode approach is simpler but has some trade-offs.
| Peer dev mode | CCaaS |
|---|---|
| You run the chaincode process locally (simpler setup) | Fablo runs the process in CCaaS container with chaincode volume mounted |
| non-TLS only | supports TLS |
| global per network | set for individual chaincodes |
The simplest way to try Fablo with dev mode is as follows:
- Ensure you have
global.peerDevModeset totrueandglobal.tlsset tofalseinfablo-config.json. - Start the network with
fablo up. Because dev mode is enabled, chaincode containers don't start. Instead, Fablo approves and commits chaincode definitions from the Fablo config file. - Start the chaincode process locally. Note: If you have multiple peers you want to use, you need to start a separate chaincode process for each peer.
For Node.js chaincode:
Install npm dependencies and start the sample chaincode with:
(cd chaincodes/chaincode-kv-node && nvm use && npm i && npm run start:watch)Now, when you update the chaincode source code, it will be automatically refreshed on the Hyperledger Fabric network.
The relevant scripts in package.json look like:
"scripts": {
...
"start:dev": "fabric-chaincode-node start --peer.address \"127.0.0.1:8541\" --chaincode-id-name \"chaincode1:0.0.1\" --tls.enabled false",
"start:watch": "nodemon --exec \"npm run start:dev\"",
...
},For Java Chaincode:
Build and run the Java chaincode locally. As a sample, you can use the chaincode from the Fablo source code in the samples/chaincodes/java-chaincode directory. Ensure a proper relative path is provided in the Fablo config.
cd samples/chaincodes/java-chaincode
./run-dev.shThe run-dev.sh script will:
- Build the chaincode using Gradle's shadowJar task
- Read from Docker the host port mapped to port 7050 of the
peer0.org1.example.comcontainer - Check that the port accepts connections, and stop with an error if it does not
- Start the chaincode with debug logging enabled and connect it to that port
For local development and review:
- The chaincode runs with the name
chaincode1:0.0.1on channelmy-channel1 - Debug level logging is enabled via
CORE_CHAINCODE_LOGLEVEL=debug - You can modify the Java code and rebuild/restart to see changes
To achieve hot reload for both TLS and non-TLS setups, use the CCaaS feature in combination with chaincodeMountPath and chaincodeStartCommand parameters.
This way, you can start chaincode processes in CCaaS containers while having chaincode source code mounted, and reload when the code changes.
This approach has several benefits:
- It works for both TLS and non-TLS
- You can have only some chaincodes running in hot reload mode while others run in regular containers
- Fablo manages starting chaincode processes
You can initialize a network with a sample setup by running the fablo init command:
fablo init dev node
This produces the following chaincode configuration:
"chaincodes": [
{
"name": "chaincode1",
"version": "0.0.1",
"channel": "my-channel1",
"lang": "ccaas",
"image": "hyperledger/fabric-nodeenv:${FABRIC_NODEENV_VERSION:-2.5}",
"chaincodeMountPath": "$CHAINCODES_BASE_DIR/chaincodes/chaincode-kv-node",
"chaincodeStartCommand": "npm run start:watch:ccaas",
"privateData": []
}
],
"hooks": {
"postGenerate": "npm i --prefix ./chaincodes/chaincode-kv-node"
}You can find a full end-to-end example in one of our test scripts test-01-v3-simple.sh.
fablo channel --helpUse it to list all available channel commands. Commands are generated using fablo-config.json to cover all cases (queries for each channel, organization, and peer).
fablo channel list org1 peer0Lists all channels for the given peer.
fablo channel getinfo channel_name org1 peer0Prints channel info, such as current block height for the given peer
fablo channel fetch config channel_name org1 peer0 [file_name.json]Fetches the latest config block, decodes it, and writes it to a JSON file.
fablo channel fetch <oldest|newest|block-number> channel_name org1 peer0 [file_name]Fetches the oldest, newest, or a block with the given number, and writes it to a file.
The default file name is the block name with the .block extension.
fablo version [--verbose | -v]Prints the current Fablo version and build information as JSON.
With the optional -v or --verbose flag, it also prints the range of Fablo config versions this version supports.
fablo useLists all available Fablo versions.
fablo use <version-number>Switches the current script to the selected version.
The Fablo config is a single JSON or YAML file that describes the desired Hyperledger Fabric network topology (network settings, CA, orderer, organizations, peers, channels, chaincodes).
It must be compatible with the schema, which the fablo validate command checks.
You can generate a basic config with the ./fablo init command.
See the samples directory for more complex examples.
The basic structure of Fablo config file is as follows:
{
"$schema": "https://github.com/hyperledger-labs/fablo/releases/download/2.6.0/schema.json",
"global": { ... },
"orgs": [ ... ],
"channels": [ ... ],
"chaincodes": [ ... ]
}Example:
"global": {
"fabricVersion": "2.5.12",
"tls": false,
"peerDevMode": false,
"monitoring": {
"loglevel": "debug"
},
"tools": {
"explorer": false
}
},Available fields in the global section are:
fabricVersion- the Hyperledger Fabric version to use (required)tls- whether to enable TLS in the network (required)engine-docker(default) orkubernetesprovider-fabric(default) orfabric-x, which is experimentalpeerDevMode- whether to run peers in dev mode (default:false)monitoring.loglevel-debug,info(default) orwarntools.explorer- whether to run one Blockchain Explorer for all organizations (default:false)fabricImages- Docker image overrides, described below
global.fabricImages is optional and lets you replace the Docker images Fablo uses.
Example:
"fabricImages": {
"peer": "hyperledger/fabric-peer:3.1.0",
"orderer": "hyperledger/fabric-orderer:3.1.0",
"tools": "ghcr.io/fablo-io/fabric-tools:3.1.3"
}The supported keys are peer, orderer, ca, tools, ccenv, baseos, javaenv and nodeenv.
If you give an image without a tag or a digest, Fablo appends the tag that matches your global.fabricVersion.
For Fabric 3.x, the default tools image repository is ghcr.io/fablo-io/fabric-tools, and for older versions it is hyperledger/fabric-tools.
The other images default to the hyperledger repository, for example hyperledger/fabric-peer.
Example:
"orgs": [
{
"organization": {
"name": "Org1",
"domain": "org1.example.com"
},
"peer": {
"instances": 2,
"db": "LevelDb"
},
"orderers": [{
"groupName": "group1",
"type": "raft",
"instances": 3
}],
"tools": {
"fabloRest": true,
"explorer": true
}
},
...
],Other available parameters for entries in the orgs array are:
organization.mspName(default:organization.name + 'MSP')ca.prefix(default:ca)ca.db(default:sqlite, other:postgres,mysql)peer.prefix(default:peer)peer.anchorPeerInstances(default: the value ofpeer.instances, so all peers are anchor peers)orderers(defaults to empty:[])orderers.prefix(default:orderer)tools.explorer- whether to run Blockchain Explorer for the organization (default:false)tools.fabloRest- whether to run Fablo REST for the organization (default:false)
- Can be
LevelDb(default) orCouchDb.
- Is optional as some organizations may have orderers defined, but others don't.
- At least one orderer group is required to run the Fabric network (requirement is validated before run).
- If you want to spread orderers in a group between many organizations, use the same
groupNamein every group definition. - The property
orderers.typecan besolo,raftorBFT. We do not support the Kafka orderer.
Example:
"channels": [
{
"name": "my-channel1",
"ordererGroup": "group1",
"orgs": [
{
"name": "Org1",
"peers": [
"peer0",
"peer1"
]
},
{
"name": "Org2",
"peers": [
"peer0"
]
}
]
},
...
],- Property
ordererGroupis optional (defaults to the first orderer group found). If you want to handle a channel with a different orderer group, define it inorgsand pass itsgroupNamehere.
Example:
"chaincodes": [
{
"name": "chaincode1",
"version": "0.0.1",
"lang": "node",
"channel": "my-channel1",
"directory": "./chaincodes/chaincode-kv-node",
"privateData": [
{
"name": "org1-collection",
"orgNames": ["Org1"]
}
]
},
{
"name": "chaincode2",
"version": "0.0.1",
"lang": "java",
"channel": "my-channel2",
"directory": "./chaincodes/chaincode-java-simple"
}
]The property lang can be golang, java, node, or ccaas.
The privateData parameter is optional and holds a list of private data collections. You don't need to define any collection for the chaincode. By default, there is none (just the implicit private data collection which is default in Fabric).
The directory parameter is required for golang, java and node chaincodes, and the image parameter is required for ccaas chaincodes.
Other available parameters for entries in the chaincodes array are:
init- initialization arguments, used from Hyperledger Fabric 3.0.0 up and ignored below it (default:{"Args":[]})initRequired- whether the chaincode requires an initialization transaction, used on Hyperledger Fabric 2.x and ignored from 3.0.0 up (default:false)endorsement- the endorsement policy for the chaincode. On Hyperledger Fabric 2.x there is no default, so Fabric applies its own. From 3.0.0 up Fablo builds a policy that requires every organization on the channel, such asAND ('Org1MSP.member')chaincodeMountPath(ccaasonly) - chaincode mount path. If provided, the given directory is mounted inside the Docker container and becomes the container working directory.chaincodeStartCommand(ccaasonly) - chaincode start command. If provided, this command is used as the Docker container command.
Hooks in Fablo are Bash commands to be executed after specific events. Supported hooks:
postGenerate— executed after the network config is generated (after./fablo generate, executed separately or automatically by./fablo up).postStart— executed after the network is started (after./fablo upor./fablo start).
Example postGenerate hook that changes MaxMessageCount to 1 in generated Hyperledger Fabric config:
"hooks": {
"postGenerate": "perl -i -pe 's/MaxMessageCount: 10/MaxMessageCount: 1/g' \"./fablo-target/fabric-config/configtx.yaml\""
}Example postStart hook that waits for peers to be ready or performs any additional bootstrap actions:
"hooks": {
"postStart": "echo 'Network started' && ./fablo-target/fabric-docker.sh channel list org1 peer0"
}Generated hooks are saved in fablo-target/hooks.
---
"$schema": https://github.com/hyperledger-labs/fablo/releases/download/2.6.0/schema.json
global:
fabricVersion: 2.5.12
tls: false
orgs:
- organization:
name: Orderer
domain: root.com
orderers:
- groupName: group1
prefix: orderer
type: solo
instances: 1
- organization:
name: Org1
domain: org1.example.com
tools:
fabloRest: true
explorer: true
peer:
instances: 2
- organization:
name: Org2
domain: org2.example.com
peer:
instances: 1
channels:
- name: my-channel1
orgs:
- name: Org1
peers:
- peer0
- peer1
- name: Org2
peers:
- peer0
chaincodes:
- name: and-policy-chaincode
version: 0.0.1
lang: node
channel: my-channel1
endorsement: AND('Org1MSP.member', 'Org2MSP.member')
directory: "./chaincodes/chaincode-kv-node"
privateData:
- name: org1-collection
orgNames:
- Org1TODO
Fablo will generate connection profiles for each organization defined in the configuration.
You can find them in the fablo-target/fabric-config/connection-profiles directory in json and yaml format.
Fablo is integrated with a simple REST API for CA and chaincodes, supported by Fablo REST.
To use it, set "tools": { "fabloRest": true } for your organization.
Visit the Fablo REST project for more documentation.
Fablo can run Blockchain Explorer for you on Fabric v2. It is not supported on Fabric v3.
Set "tools": { "explorer": true } for your organization if you want to use it per organization, or set the same value in the global section of the config if you want to use one global Explorer for all organizations.
We'd love to have you contribute! Please refer to our contribution guidelines for details.
Fablo was originally created at SoftwareMill by @Hejwo and @dzikowski. In December 2021, Fablo joined Hyperledger Labs.
- Inside the LFDT Mentorship Program: Real Stories, Real Impact - @umegbewe, @dpereowei, and @OsamaRab3 among others are talking about their experiences in as mentors and mentees in 2025 LF Decentralized Trust Mentorship Program (March 2026).
- Lightning Talk: Fablo - Maintainer Days 2026 - @umegbewe (January 2026)
- Simplifying Fabric Dev: New Features in Fablo by @dzikowski, @dpereowei, and @OsamaRab3 (November 2025)
- An Introduction to FABLO: a tool to generate a Hyperledger Fabric blockchain network by @Hejwo (September 2021)
- Kick-off your Hyperledger Fabric network by @Hejwo (Feburary 2021; Fablo was called "Fabrica" at that time)