Node shell

The Corda shell is an embedded or standalone command line that allows an administrator to control and monitor a node. It is based on the CRaSH shell and supports many of the same features. These features include:

  • Invoking any of the node’s RPC methods.
  • Viewing a dashboard of threads, heap usage, VM properties.
  • Uploading and downloading attachments.
  • Issuing SQL queries to the underlying database.
  • Viewing JMX metrics and monitoring exports.
  • UNIX style pipes for both text and objects, an egrep command and a command for working with columnar data.
  • Shutting the node down.

There are two ways of using the Corda shell:

  • A standalone application which you can run using corda-standalone-shell.
  • A driver within your node, accessible via the corda-shell.jar. You can also use SSH to access the shell remotely using this method.

The standalone application is the only way to use the shell and keep a log of your commands.

When accessing the shell (embedded, standalone, via SSH) RPC permissions are required. This is because the shell actually communicates with the node using RPC calls.

There are several operations that are read-only in nature and granting them should have no impact on the ledger state of the node.

These permissions are:


There are also operations that allow starting/killing the flows or even stopping the node as a whole:

  • Watching flows (flow watch) requires InvokeRpc.stateMachinesFeed.
  • Starting flows requires InvokeRpc.registeredFlows and InvokeRpc.wellKnownPartyFromX500Name, as well as a permission for the flow being started.
  • Killing flows (flow kill) requires InvokeRpc.killFlow. This currently allows the user to kill any flow, so please be careful when granting it!

Description of RPC operations can be found in the RPC operations documentation.

The shell will display in the node’s terminal window. It connects to the node as shell user with password shell (which is only available in dev mode). It may be disabled by passing the --no-local-shell flag when running the node.

The standalone shell is a standalone application interacting with a Corda node via RPC calls. RPC node permissions are necessary for authentication and authorisation. Certain operations, such as starting flows, require access to the CorDapp JAR files.

You can access the standalone shell from

Run the corda-standalone-shell jar using:

 java -jar corda-standalone-shell-4.10.jar [-hvV] [--logging-level=<loggingLevel>] [--password=<password>]
    [--truststore-type=<trustStoreType>] [--user=<user>] [-a=<host>]
    [-c=<cordappDirectory>] [-f=<configFile>] [-o=<commandsDirectory>]


  • config-file=<configFile>, --f: The path to the shell configuration file, used instead of providing the rest of the command line options.
  • cordapp-directory=<cordappDirectory>, -c: The path to the directory containing CorDapp jars, CorDapps are required when starting flows.
  • commands-directory=<commandsDirectory>, -o: The path to the directory containing additional CRaSH shell commands.
  • host, -a: The host address of the Corda node.
  • port, -p: The RPC port of the Corda node.
  • user=<user>: The RPC user name.
  • password=<password>: The RPC user password. If not provided it will be prompted for on startup.
  • truststore-password=<trustStorePassword>: The password to unlock the TrustStore file.
  • truststore-file=<trustStoreFile>: The path to the TrustStore file.
  • truststore-type=<trustStoreType>: The type of the TrustStore (for example, JKS).
  • verbose, --log-to-console, -v: If set, prints logging to the console as well as to a file.
  • logging-level=<loggingLevel>: Enable logging at this level and higher. Possible values: ERROR, WARN, INFO, DEBUG, TRACE. Default: INFO.
  • help, -h: Show this help message and exit.
  • version, -V: Print version information and exit.

Install the corda-shell JAR in a node’s /drivers directory to run the shell in the same terminal that starts the node. By default, a Corda node does not run the shell.

When using cordaformation the shell can be included in generated node’s by including the following in the build.gradle file containing deployNodes:

cordaDriver "net.corda:corda-shell:4.10"

The shell is also accessible via SSH.

To enable SSH access:

  1. Enable the SSH server in your node. By default, the SSH server is disabled. To enable it, configured a port in the node’s node.conf file:
sshd {
    port = 2222
  1. Ensure the corda-shell.jar is installed as a driver within your node.

Users log in to shell via SSH using the same credentials as they would use for RPC. No RPC permissions are required to allow the connection and log in.

The host key is loaded from the <node root directory>/sshkey/hostkey.pem file. If this file does not exist, it is generated automatically. In dev mode, the seed may be specified to give the same results on the same computer in order to avoid host-checking errors.

Only RSA key is currently supported as a host key. If hostkey.pem is not RSA, it will be replaced by the newly generated RSA key.

Run the following command from the terminal:

ssh -p [portNumber] [host] -l [user]


  • [portNumber] is the port number specified in the node.conf file.
  • [host] is the node’s host (for example, localhost if running the node locally).
  • [user] is the RPC username.

The RPC password will be requested after a connection is established.

Windows does not provide a built-in SSH tool. An alternative such as PuTTY should be used.

This is a new mode added in the Enterprise 4.3 release to prevent the CRaSH shell embedded commands (for example, java, system) from being executed by a user with insufficient privilege. This is part of a general security-tightening initiative.

When a shell is running in unsafe mode, the shell behaviour will be the same as before and will include CRaSH built-in commands. By default the internal shell will run in safe mode but will still be have the ability to execute RPC client calls as before based on existing RPC permissions. No Corda functionality is affected by this change; only the ability to access to the CRaSH shell embedded commands.

When running an SSH shell, it will run in safe mode for any user that does not explicitly have permission ‘ALL’ as one the items in their RPC permission list, see Working with the CordaRPCClient API for more information about the RPC Client API. These shell changes arealso applied to the Stand Alone shell which will now run in safe mode (Enterprise 4.3 onwards). It may be possible that, in the future, the CRaSH shell embedded commands may become deprecated. Where possible, please do not write any new code that depends on them as they are technically not part of Corda functionality.

You can type help in the shell to list the available commands, and man to get interactive help on many commands. You can also pass the --help or -h flags to a command to get info about what switches it supports.

Commands may have subcommands, in the same style as git. In that case, running the command by itself will list the supported subcommands.

You can use the shell to:

  • Issue RPCs.
  • Upload and download attachments.
  • Extract information about attachments from the node.
  • Output information about the flows running on the node.
  • Work with flows.
  • Check if a transaction is recorded on the node.
  • View and change run command output format.
  • Shut down the node.

The shell interacts with the node by issuing RPCs (remote procedure calls). You make an RPC from the shell by typing run, followed by the name of the desired RPC method.

You can find a list of the available RPC methods here.

Some RPCs return a stream of events that will be shown on screen until you press Ctrl-C.

Query the vault for CashState states with the following command:

run vaultQuery contractStateType:$State

This breaks down as follows:

  • run is the shell command for making an RPC call.
  • vaultQuery is an RPC call that queries the vault for vault states.
  •$State is the fully-qualified name of the state type we are querying for.

An example of the output for run vaultQuery contractStateType:$State is shown below:

- state:
    data: !<$State>
      amount: "200.00 USD issued by O=BankOfCorda, L=London, C=GB[01]"
      owner: "GfHq2tTVk9z4eXgyNkbxxXPps9MWrSaKeKs3jyh3QJeg7DdewnP468emNA9K"
    contract: ""
    notary: "O=Notary Service, L=Zurich, C=CH"
    encumbrance: null
    constraint: !<net.corda.core.contracts.SignatureAttachmentConstraint>
      key: "aSq9DsNNvGhYxYyqA9wd2eduEAZ5AXWgJTbTEw3G5d2maAq8vtLE4kZHgCs5jcB1N31cx1hpsLeqG2ngSysVHqcXhbNts6SkRWDaV7xNcr6MtcbufGUchxredBb6"
    txhash: "2524B8C9D1D0A7695175465358AAB17809E65A3DC23D6C1393F4167C105D2815"
    index: 0
- state:
    data: !<$State>
      amount: "300.00 GBP issued by O=BankOfCorda, L=London, C=GB[01]"
      owner: "GfHq2tTVk9z4eXgyUUZVN63pZ88HnfX7CKBDUaRAzDhehzB5CbRPhFuJtaXX"
    contract: ""
    notary: "O=Notary Service, L=Zurich, C=CH"
    encumbrance: null
    constraint: !<net.corda.core.contracts.SignatureAttachmentConstraint>
      key: "aSq9DsNNvGhYxYyqA9wd2eduEAZ5AXWgJTbTEw3G5d2maAq8vtLE4kZHgCs5jcB1N31cx1hpsLeqG2ngSysVHqcXhbNts6SkRWDaV7xNcr6MtcbufGUchxredBb6"
    txhash: "C438CE336B62D0D8BF731D96566D93DBEACFADF18864C030A1D871C8B15F6978"
    index: 0
- ref:
    txhash: "2524B8C9D1D0A7695175465358AAB17809E65A3DC23D6C1393F4167C105D2815"
    index: 0
  contractStateClassName: "$State"
  recordedTime: "2020-11-11T14:39:47.609Z"
  consumedTime: null
  status: "UNCONSUMED"
  notary: "O=Notary Service, L=Zurich, C=CH"
  lockId: null
  lockUpdateTime: "2020-11-11T14:39:47.642Z"
  relevancyStatus: "RELEVANT"
      key: "aSq9DsNNvGhYxYyqA9wd2eduEAZ5AXWgJTbTEw3G5d2maAq8vtLE4kZHgCs5jcB1N31cx1hpsLeqG2ngSysVHqcXhbNts6SkRWDaV7xNcr6MtcbufGUchxredBb6"
- ref:
    txhash: "C438CE336B62D0D8BF731D96566D93DBEACFADF18864C030A1D871C8B15F6978"
    index: 0
  contractStateClassName: "$State"
  recordedTime: "2020-11-11T14:41:35.103Z"
  consumedTime: null
  status: "UNCONSUMED"
  notary: "O=Notary Service, L=Zurich, C=CH"
  lockId: null
  lockUpdateTime: "2020-11-11T14:41:35.117Z"
  relevancyStatus: "RELEVANT"
      key: "aSq9DsNNvGhYxYyqA9wd2eduEAZ5AXWgJTbTEw3G5d2maAq8vtLE4kZHgCs5jcB1N31cx1hpsLeqG2ngSysVHqcXhbNts6SkRWDaV7xNcr6MtcbufGUchxredBb6"
totalStatesAvailable: -1
stateTypes: "UNCONSUMED"
otherResults: []

The shell can be used to upload and download attachments from the node. To learn how, see the Working with attachments tutorial.

Use the attachments shell command to extract information about attachments from the node. This commands allows you to examine installed and uploaded attachments as well as those that were received over the network.

attachments trustInfo

The output will contain the following information:

  • If an attachment is installed locally.
    • True if the attachment is installed in the CorDapps directory or uploaded via RPC.
    • False in all other scenarios, including attachments received from a peer node or uploaded via any means other than RPC.
  • If an attachment is trusted.
  • Which other attachment, if any, provided trust to an attachment.

Below is an example of the commands’s output:

Name                                          Attachment ID                                                        Installed             Trusted                Trust Root
net.corda.dummy-cordapp-contracts-states      654CDFD0F195269B1C839DD9D539592B4DE7DD09BF29A3762EF600F94AE45E18     true                  true                   net.corda.dummy-cordapp-contracts-states
Corda Finance Demo                            71154836EBE54C0A60C6C5D9513EE015DB722EED57034B34428C72459CF133D7     true                  true                   Corda Finance Demo
Received from: O=PartyA, L=London, C=GB       CDDDD9A5C97DBF839445FFD79F604078D9D9766D178F698780EA4F9EA7A02D5F     false                 true                   net.corda.dummy-cordapp-contracts-states

The output above shows that two CorDapps have been installed locally and are therefore trusted. The third record is an attachment received from another node, hence the Name field containing Received from: O=PartyA, L=London, C=GB. The CorDapp is also trusted as another CorDapp has been signed by a common key; the Trust Root field is filled in to highlight this.

Use the checkpoints command to output information about the flows running on a node. This is useful for diagnosing the causes of stuck flows. Using the generated output, corrective actions can be taken to resolve the issues flows are facing.

checkpoints dump

The command will create a zip and generate a JSON file for each flow. Each file follows the naming format <flow name>-<flow id>.json - for example, CashIssueAndPaymentFlow-90613d6f-be78-41bd-98e1-33a756c28808.json.

The .zip file is placed into the logs directory of the node and is named checkpoints_dump-<date and time>.zip - for example, checkpoints_dump-20190812-153847.

You can find the following useful fields in the output:

  • flowId: The id of the flow.
  • topLevelFlowClass: The name of the original flow that was invoked (by RPC or a service).
  • topLevelFlowLogic: Detailed view of the top level flow.
  • flowCallStackSummary: A summarised list of the current stack of subflows along with any progress tracker information.
  • suspendedOn: The command that the flow is suspended on (for example, SuspendAndReceive) which includes the suspendedTimestamp.
  • flowCallStack: A detailed view of the current stack of subflows.
  "flowId" : "90613d6f-be78-41bd-98e1-33a756c28808",
  "topLevelFlowClass" : "",
  "topLevelFlowLogic" : {
    "amount" : "10.00 USD",
    "issueRef" : "MTIzNA==",
    "recipient" : "O=BigCorporation, L=New York, C=US",
    "anonymous" : true,
    "notary" : "O=Notary, L=London, C=GB"
  "flowCallStackSummary" : [
      "flowClass" : "",
      "progressStep" : "Paying recipient"
      "flowClass" : "",
      "progressStep" : "Generating anonymous identities"
      "flowClass" : "net.corda.confidential.SwapIdentitiesFlow",
      "progressStep" : "Awaiting counterparty's anonymous identity"
  "suspendedOn" : {
    "sendAndReceive" : [
        "session" : {
          "peer" : "O=BigCorporation, L=New York, C=US",
          "ourSessionId" : -5024519991106064492
        "sentPayloadType" : "net.corda.confidential.SwapIdentitiesFlow$IdentityWithSignature",
        "sentPayload" : {
          "identity" : {
            "class" : "net.corda.core.identity.PartyAndCertificate",
            "deserialized" : "O=BankOfCorda, L=London, C=GB"
          "signature" : "M5DN180OeE4M8jJ3mFohjgeqNYOWXzR6a2PIclJaWyit2uLnmJcZatySoSC12b6e4rQYKIICNFUXRzJnoQTQCg=="
    "suspendedTimestamp" : "2019-08-12T15:38:39Z",
    "secondsSpentWaiting" : 7
  "flowCallStack" : [
      "flowClass" : "",
      "progressStep" : "Paying recipient",
      "flowLogic" : {
        "amount" : "10.00 USD",
        "issueRef" : "MTIzNA==",
        "recipient" : "O=BigCorporation, L=New York, C=US",
        "anonymous" : true,
        "notary" : "O=Notary, L=London, C=GB"
      "flowClass" : "",
      "progressStep" : "Generating anonymous identities",
      "flowLogic" : {
        "amount" : "10.00 USD",
        "recipient" : "O=BigCorporation, L=New York, C=US",
        "anonymous" : true,
        "issuerConstraint" : [ ],
        "notary" : "O=Notary, L=London, C=GB"
      "flowClass" : "net.corda.confidential.SwapIdentitiesFlow",
      "progressStep" : "Awaiting counterparty's anonymous identity",
      "flowLogic" : {
        "otherSideSession" : {
          "peer" : "O=BigCorporation, L=New York, C=US",
          "ourSessionId" : -5024519991106064492
        "otherParty" : null
  "origin" : {
    "rpc" : "bankUser"
  "ourIdentity" : "O=BankOfCorda, L=London, C=GB",
  "activeSessions" : [ ],
  "errored" : null

Use the different flow commands available to make changes on the ledger. You can start, kill, watch, or list flows. You may also find it useful to query flow data.

The shell can be used to query flow data. For more information on the types of data that can be queried and instructions for doing so, see the documentation on Querying flow data.

Use this command to start a flow. The flow start command takes the name of a flow class, or any unambiguous substring thereof, as well as the data to be passed to the flow constructor.

If there are several matches for a given substring, the possible matches will be printed out. If a flow has multiple constructors then the names and types of the arguments will be used to try and automatically determine which one to use. If the match against available constructors is unclear, the reasons each available constructor failed to match will be printed out. In the case of an ambiguous match, the first applicable constructor will be used.

Start the CashIssueFlow flow:

flow start CashIssueFlow amount: $1000, issuerBankPartyRef: 1234, notary: "O=Controller, L=London, C=GB"

This breaks down as follows:

  • flow start is the shell command for starting a flow.
  • CashIssueFlow is the name of a flow.
  • Each name: value pair after that is a flow constructor argument.

If you are unsure of the parameters a specific flow takes, enter flow start with the flow name. The missing constructor will be returned. See the example with CashIssueFlow below:

$>>>flow start CashIssueFlow
No matching constructor found:
- [amount: Amount<Currency>, issuerBankPartyRef: OpaqueBytes, notary: Party]: missing parameter amount
- [request: CashIssueFlow.IssueRequest]: missing parameter request
- [amount: Amount<Currency>, issuerBankPartyRef: OpaqueBytes, notary: Party, progressTracker: ProgressTracker]: missing parameter amount

The above command for CashIssueFlow invokes the following CashIssueFlow constructor:

class CashIssueFlow(val amount: Amount<Currency>,
                    val issuerBankPartyRef: OpaqueBytes,
                    val recipient: Party,
                    val notary: Party) : AbstractCashFlow(progressTracker)

Use this command to kill a single flow, as identified by its UUID.

Kill a flow with a given UUID as follows:

flow kill f6e08ab5-7a79-4225-a62d-1da910ce269e

  • flow kill is the shell command for killing the flow.
  • f6e08ab5-7a79-4225-a62d-1da910ce269e is an example flow UUID.

This command only works for running flows. The following will be returned if you attempt to kill a flow (identified by its UUID) that is not running:

Failed to kill flow [f6e08ab5-7a79-4225-a62d-1da910ce269e]

When a flow is successfully killed, the following output (with the corresponding flow UUID) will be returned:

Killed flow [f6e08ab5-7a79-4225-a62d-1da910ce269e]

Use this command to display all flows currently running on the node with result (or error) information. When this command is run, the shell waits for flows and logs them as they are run.

flow watch

The output will show results listed with flow Id, Flow name, Initiator, and Status.

Id                                Flow name                                                          Initiator                        Status
27fc3a53-5fc3-4c30-a872-a2f282291 Cash Payment Receiver                                              O=BankOfCorda, L=London, C=GB    No return value
Waiting for completion or Ctrl-C ...

Use this command to list all flows available on the node. You can start all flows listed.

flow list

This will return an output similar to the output shown below:


Use the hashLookup command to check if a transaction matching a specified Id hash value is recorded on the node. If you do not have the needed transaction Id at hand, run vaultQuery to find the Id.

The hashLookup command is constructed as shown below, with a hexadecimal SHA-256 hash value representing the hashed transaction Id.

hashLookup F69A7626ACC27042FEEAE187E6BFF4CE666E6F318DC2B32BE9FAF87DF687930C

If the transaction is not recorded on the node, the following will be returned:

No matching transaction found

If the transaction is recorded on the node, this will be confirmed as below:

Found a matching transaction with Id: F69A7626ACC27042FEEAE187E6BFF4CE666E6F318DC2B32BE9FAF87DF687930C

You can view and choose the format in which the output of run commands will be shown. Valid formats are json, yaml. The default format is yaml.

To see the format currently used run:

output-format get

To update the format run:

  • output-format set json to set the output format to JSON.

  • output-format set yaml to set the output format to YAML.

You can shut the node down via shell:

  • run gracefulShutdown will put the node into draining mode, and shut down when there are no flows running.
  • run shutdown will shut the node down immediately.

Parameters are passed to RPC or flow commands using a syntax called Yaml (yet another markup language), a simple JSON-like language. The key features of Yaml are:

  • Parameters are separated by commas.
  • Each parameter is specified as a key: value pair.
    • There MUST be a space after the colon, otherwise you’ll get a syntax error.
  • Strings do not need to be surrounded by quotes unless they contain commas, colons, or embedded quotes.
  • Class names must be fully-qualified (for example java.lang.String).
  • Nested classes are referenced using $. For example, the class is referenced as$State (note the $).

Class instances are created using curly-bracket syntax. For example, if we have a Campaign class with the following constructor:

data class Campaign(val name: String, val target: Int)

Then we could create an instance of this class to pass as a parameter as follows:

newCampaign: { name: Roger, target: 1000 }

Where newCampaign is a parameter of type Campaign.

In addition to the types already supported by Jackson, several parameter types can automatically be mapped from strings. We cover the most common types here.

A parameter of type Amount<Currency> can be written as either:

  • A dollar ($), pound (£) or euro (€) symbol followed by the amount as a decimal.
  • The amount as a decimal followed by the ISO currency code (for example, “100.12 CHF”).

A parameter of type SecureHash can be written as a hexadecimal string: F69A7626ACC27042FEEAE187E6BFF4CE666E6F318DC2B32BE9FAF87DF687930C

A parameter of type OpaqueBytes can be provided as a UTF-8 string.

A parameter of type PublicKey can be written as a Base58 string of its encoded format: GfHq2tTVk9z4eXgyQXzegw6wNsZfHcDhfw8oTt6fCHySFGp3g7XHPAyc2o6D. net.corda.core.utilities.EncodingUtils.toBase58String will convert a PublicKey to this string format.

A parameter of type Party can be written in several ways:

  • By using the full name: "O=Monogram Bank,L=Sao Paulo,C=GB".
  • By specifying the organisation name only: "Monogram Bank".
  • By specifying any other non-ambiguous part of the name: "Sao Paulo" (if only one network node is located in Sao Paulo).
  • By specifying the public key (see above).

A parameter of type NodeInfo can be written in terms of one of its identities (see Party above).

A parameter of type AnonymousParty can be written in terms of its PublicKey (see above).

A parameter of type NetworkHostAndPort can be written as a “host:port” string: "localhost:1010".

A parameter of Instant and Date can be written as an ISO-8601 string: "2017-12-22T00:00:00Z".

The shell can be extended using commands written in either Java or Groovy (a Java-compatible scripting language). These commands have full access to the node’s internal APIs and thus can be used to achieve almost anything.

A full tutorial on how to write such commands is out of scope for this documentation. To learn more, please refer to the CRaSH documentation. New commands are placed in the shell-commands subdirectory in the node directory. Edits to existing commands will be used automatically, but currently commands added after the node has started won’t be automatically detected. Commands must have names all in lower-case with either a .java or .groovy extension.

The shell will be enhanced over time. The currently known limitations include:

  • Flows cannot be run unless they override the progress tracker.
  • If a command requires an argument of an abstract type, the command cannot be run because the concrete subclass to use cannot be specified using the YAML syntax.
  • There is no command completion for flows or RPCs.
  • Command history is not preserved across restarts.
  • The jdbc command requires you to explicitly log into the database first.
  • Commands placed in the shell-commands directory are only noticed after the node is restarted.
  • The jul command advertises access to logs, but it doesn’t work with the logging framework used in Corda.

Was this page helpful?

Thanks for your feedback!

Chat with us

Chat with us on our #docs channel on slack. You can also join a lot of other slack channels there and have access to 1-on-1 communication with members of the R3 team and the online community.

Propose documentation improvements directly

Help us to improve the docs by contributing directly. It's simple - just fork this repository and raise a PR of your own - R3's Technical Writers will review it and apply the relevant suggestions.

We're sorry this page wasn't helpful. Let us know how we can make it better!

Chat with us

Chat with us on our #docs channel on slack. You can also join a lot of other slack channels there and have access to 1-on-1 communication with members of the R3 team and the online community.

Create an issue

Create a new GitHub issue in this repository - submit technical feedback, draw attention to a potential documentation bug, or share ideas for improvement and general feedback.

Propose documentation improvements directly

Help us to improve the docs by contributing directly. It's simple - just fork this repository and raise a PR of your own - R3's Technical Writers will review it and apply the relevant suggestions.