- Overview
- Tutorials
- How Tos
- Download
- Install
- Configure
- Secure
- TLS API Configuration
- Configure API Authentication and Authorization with JWT
- Configure API Limits
- Set Resource Limits
- Crypto key management
- Restrict key usage
- Namespace Key Management
- Key management service (KMS) configuration
- Optimize
- Observe
- Operate
- Initializing node identity manually
- Canton Console
- Synchronizer connections
- High Availability Usage
- Manage Daml packages and archives
- Participant Node pruning
- Party Management
- Party Replication
- Decentralized party overview
- Setup an External Party
- Ledger API User Management
- Node Traffic Management
- Identity Management
- Upgrade
- Decommission
- Recover
- Troubleshoot
- Explanations
- Reference
Manage Daml packages and archives¶
About¶
A package is a unit of compiled Daml code corresponding to one Daml project. This package contains compiled Daml-LF code. Every package has a unique package-id. A Daml Archive (DAR) file consists of a main package along with all other packages on which the main package depends. As the DAR only has one main package the main package-id can also be used to refer to the DAR. App providers distribute apps as a collection of DARs.
Manage DARs¶
Upload a DAR¶
To upload a DAR use the dars.upload console command.
@ participant2.dars.upload("dars/CantonExamples.dar")
res1: String = "1a42986b65cf94c458c5134c6a8c972b6c3ace7c50864c08a99f96b591b29c62"
All Participant Nodes running the app must have the app DARs loaded independently as they aren’t shared.
List DARs¶
To list DARs use the dars.list console command.
@ participant2.dars.list()
res2: Seq[DarDescription] = Vector(
DarDescription(
mainPackageId = "1a42986b65cf94c458c5134c6a8c972b6c3ace7c50864c08a99f96b591b29c62",
name = "CantonExamples",
version = "3.3.0",
description = "CantonExamples"
),
DarDescription(
mainPackageId = "28019ae57edd806f97c769f1490b3faeb3a9c3d29b676838e847331ef9c08de6",
name = "AdminWorkflows",
version = "3.3.0",
description = "System package"
)
)
Note
Please note that the package AdminWorkflows is a package that ships with Canton. It contains the Daml templates
used by the participant.health.ping
command.
To filter the list of package provide a criteria to the list
method. For example, to extract the description
of the DAR named CantonExamples, first filter by name and then use head
to extract the first element of the list:
@ val cantonExampleDar = participant2.dars.list(filterName = "CantonExamples").head
cantonExampleDar : DarDescription = DarDescription(
mainPackageId = "1a42986b65cf94c458c5134c6a8c972b6c3ace7c50864c08a99f96b591b29c62",
name = "CantonExamples",
version = "3.3.0",
description = "CantonExamples"
)
Display the contents of a DAR¶
To display the contents of a DAR use the dars.get_contents console command.
@ val darContent = participant2.dars.get_contents(cantonExampleDar.mainPackageId)
darContent : DarContents = DarContents(
main = 1a42986b65cf...,
name = CantonExamples,
version = 3.3.0,
description = CantonExamples,
packages = Seq(
54f85ebfc7df...,
b70db8369e1c...,
..
The content includes the name and version of the DAR, as well as the names and versions of the packages included in the DAR as dependencies.
Note
All DAR files include packages from the Daml standard library (prefixed with daml-), for example daml-prim.
Validate a DAR¶
Use DAR validation to ensure that the packages contained within the DAR are compatible with the packages already loaded. For example it’s invalid for a new template to redefine an existing template that has the same package, module, and template names.
By default DARs are validated on upload. To independently validate a DAR use the dars.validate console command.
@ participant2.dars.validate("dars/CantonExamples.dar")
res5: String = "1a42986b65cf94c458c5134c6a8c972b6c3ace7c50864c08a99f96b591b29c62"
Note
Validating a DAR file doesn’t change the Participant Node, no information is persisted.
Manage package vetting¶
On command submission all Participant Nodes involved in the transaction must have the packages necessary to interpret the transaction such that they come to the same conclusion. Package vetting topology information is the way that Participant Nodes communicate to other Participant Nodes what packages they support. Uploading a DAR file to a Participant Node publishes vetting information to all connected Synchronizers making it available to other Participant Nodes. Use the topology.vetted_packages.list
console command to list vetted packages.
To display the Synchronizer/Participant Node vetting state for a specific package filter the results as shown:
@ participant1.dars.upload("dars/CantonExamples.dar")
res6: String = "1a42986b65cf94c458c5134c6a8c972b6c3ace7c50864c08a99f96b591b29c62"
@ participant2.dars.upload("dars/CantonExamples.dar")
res7: String = "1a42986b65cf94c458c5134c6a8c972b6c3ace7c50864c08a99f96b591b29c62"
@ val mainPackageId = participant2.dars.list(filterName = "CantonExamples").head.mainPackageId
mainPackageId : String = "1a42986b65cf94c458c5134c6a8c972b6c3ace7c50864c08a99f96b591b29c62"
@ participant1.topology.vetted_packages.list().filter(_.item.packages.exists(_.packageId == mainPackageId)).map(r => (r.context.storeId, r.item.participantId))
res9: Seq[(TopologyStoreId, ParticipantId)] = Vector(
(Synchronizer(id = da::1220a82692ab...), PAR::participant2::1220a4d7463b...),
(Synchronizer(id = da::1220a82692ab...), PAR::participant1::12201ff69b1d...),
(Authorized, PAR::participant1::12201ff69b1d...)
)
Note
In the output the store
called Authorized
is local to the Participant Node and is not a Synchronizer store.
If all package vetting requirements aren’t satisfied by any Synchronizer, the transaction submission fails returning a FAILED_PRECONDITION/PACKAGE_SELECTION_FAILED
error message.
Unvet the main DAR package¶
To remove support for the main DAR package use the dars.vetting.disable console command.
@ participant2.dars.vetting.disable(mainPackageId)
@ participant1.topology.vetted_packages.list().filter(_.item.packages.exists(_.packageId == mainPackageId)).map(r => (r.context.storeId, r.item.participantId))
res11: Seq[(TopologyStoreId, ParticipantId)] = Vector(
(Synchronizer(id = da::1220a82692ab...), PAR::participant1::12201ff69b1d...),
(Authorized, PAR::participant1::12201ff69b1d...)
)
Warning
It’s not possible to unvet a package referenced by active contracts. Attempting this results in a FAILED_PRECONDITION/TOPOLOGY_PACKAGE_ID_IN_USE
error.
Use dars.vetting.enable console command to re-enable the vetting of a package.
Get package information¶
List packages¶
To directly list packages, use:
@ participant2.packages.list()
res12: Seq[PackageDescription] = Vector(
PackageDescription(
packageId = 9e70a8b3510d...,
name = ghc-stdlib-DA-Internal-Template,
version = 1.0.0,
uploadedAt = 2025-07-17T22:19:21.041808Z,
size = 114
),
..
Filter the list by passing a criteria to the list
method. For example, to extract the description
of the package named daml-prim, first filter by name and then use head
to extract the first element of the list:
@ val prim = participant2.packages.list(filterName = "daml-prim").head
prim : PackageDescription = PackageDescription(
packageId = 0e4a572ab1fb...,
name = daml-prim-DA-Internal-Erased,
version = 1.0.0,
uploadedAt = 2025-07-17T22:19:21.041808Z,
size = 98
)
Display the contents of a package¶
To inspect packages use the packages.get_contents console command.
@ participant2.packages.get_contents(prim.packageId)
res14: PackageDescription.PackageContents = PackageContents(
description = PackageDescription(
packageId = 0e4a572ab1fb...,
name = daml-prim-DA-Internal-Erased,
version = 1.0.0,
uploadedAt = 2025-07-17T22:19:21.041808Z,
size = 98
),
..
Find DARs that reference a package¶
To find DARs that reference a package use the packages.get_references console command.
@ participant2.packages.get_references(prim.packageId)
res15: Seq[DarDescription] = Vector(
DarDescription(
mainPackageId = "1a42986b65cf94c458c5134c6a8c972b6c3ace7c50864c08a99f96b591b29c62",
name = "CantonExamples",
version = "3.3.0",
description = "CantonExamples"
),
DarDescription(
..
Remove packages and DARs¶
Danger
Removing packages can lead to a number of issues, including:
Inability to use a contract originally created against the package, even if used in an upgraded context.
Inability perform Ledger API reporting on archived contracts in verbose mode. This is because the package is still needed to report historical contract events.
For this reason, you should not remove packages or DARs in production environments unless you are sure the package was never used or that all references to the package are pruned.
Remove a DAR¶
DAR removal only removes the main package associated with the DAR, not other packages.
You can remove a DAR only when:
There are no active contracts referencing the package.
There are no other packages that depend on the DAR package.
The main package of the DAR is unvetted.
To remove the DAR package
@ val packagesBefore = participant1.packages.list().map(_.packageId).toSet
packagesBefore : Set[String] = HashSet(
"1a42986b65cf94c458c5134c6a8c972b6c3ace7c50864c08a99f96b591b29c62",
"b70db8369e1c461d5c70f1c86f526a29e9776c655e6ffc2560f95b05ccb8b946",
"f181cd661f7af3a60bdaae4b0285a2a67beb55d6910fc8431dbae21a5825ec0f",
"bde4bd30749e99603e5afa354706608601029e225d4983324d617825b634253a",
"5aee9b21b8e9a4c4975b5f4c4198e6e6e8469df49e2010820e792f393db870f4",
"28019ae57edd806f97c769f1490b3faeb3a9c3d29b676838e847331ef9c08de6",
"0e4a572ab1fb94744abb02243a6bbed6c78fc6e3c8d3f60c655f057692a62816",
"60c61c542207080e97e378ab447cc355ecc47534b3a3ebbff307c4fb8339bc4d",
"c280cc3ef501d237efa7b1120ca3ad2d196e089ad596b666bed59a85f3c9a074",
..
@ val mainPackageId = participant1.dars.upload("dars/CantonExamples.dar")
mainPackageId : String = "1a42986b65cf94c458c5134c6a8c972b6c3ace7c50864c08a99f96b591b29c62"
@ val content = participant1.dars.get_contents(mainPackageId)
content : DarContents = DarContents(
main = 1a42986b65cf...,
name = CantonExamples,
version = 3.3.0,
description = CantonExamples,
packages = Seq(
d095a2ccf6dd...,
f181cd661f7a...,
..
Remove the DAR using the dars.remove console command:
@ participant1.dars.remove(mainPackageId)
DAR removal only removes the main package associated with the DAR, not other packages.
@ val packageIds = content.packages.map(_.packageId).toSet.intersect(participant1.packages.list().map(_.packageId).toSet)
packageIds : Set[String] = HashSet(
"b70db8369e1c461d5c70f1c86f526a29e9776c655e6ffc2560f95b05ccb8b946",
"f181cd661f7af3a60bdaae4b0285a2a67beb55d6910fc8431dbae21a5825ec0f",
"bde4bd30749e99603e5afa354706608601029e225d4983324d617825b634253a",
"5aee9b21b8e9a4c4975b5f4c4198e6e6e8469df49e2010820e792f393db870f4",
"0e4a572ab1fb94744abb02243a6bbed6c78fc6e3c8d3f60c655f057692a62816",
"60c61c542207080e97e378ab447cc355ecc47534b3a3ebbff307c4fb8339bc4d",
"52854220dc199884704958df38befd5492d78384a032fd7558c38f00e3d778a2",
"c280cc3ef501d237efa7b1120ca3ad2d196e089ad596b666bed59a85f3c9a074",
"e5411f3d75f072b944bd88e652112a14a3d409c491fd9a51f5f6eede6d3a3348",
..
To remove individual packages that where bundled with the DAR see the instructions below.
This line shows non daml- prefixed packages that aren’t referenced by any other package, and so are candidates for removal:
@ participant1.packages.list().filter(!_.name.startsWith("daml-")).filter(p => participant1.packages.get_references(p.packageId).isEmpty)
res21: Seq[PackageDescription] = Vector()
Force the removal of a package¶
Danger
Force removing of a package is a dangerous operation. For this reason do not force remove packages in production environments unless you are sure the package is unused and that all references to the package are pruned.
Canton also supports removing individual packages, giving the user more fine-grained control over the system. To remove packages ensure the following conditions are true:
The package is unused. This means that there shouldn’t be an active contract corresponding to the package.
The package is unvetted. This means there shouldn’t be an active vetting transaction corresponding to the package.
The package is not required for Participant administration (for example, the package containing the Ping template)
Attempting to remove a package that is required results in an FAILED_PRECONDITION/PACKAGE_OR_DAR_REMOVAL_ERROR
error:
@ val mainPackageId = participant1.dars.upload("dars/CantonExamples.dar")
mainPackageId : String = "1a42986b65cf94c458c5134c6a8c972b6c3ace7c50864c08a99f96b591b29c62"
@ participant1.packages.remove(mainPackageId)
ERROR com.digitalasset.canton.integration.EnvironmentDefinition$$anon$3:PackageDarManagementDocumentationIntegrationTest - Request failed for participant1.
GrpcRequestRefusedByServer: FAILED_PRECONDITION/PACKAGE_OR_DAR_REMOVAL_ERROR(9,87506901): Package 1a42986b65cf94c458c5134c6a8c972b6c3ace7c50864c08a99f96b591b29c62 is currently vetted and available to use.
Request: RemovePackage(1a42986b65cf94c458c5134c6a8c972b6c3ace7c50864c08a99f96b591b29c62,false)
DecodedCantonError(
code = 'PACKAGE_OR_DAR_REMOVAL_ERROR',
category = InvalidGivenCurrentSystemStateOther,
cause = "Package 1a42986b65cf94c458c5134c6a8c972b6c3ace7c50864c08a99f96b591b29c62 is currently vetted and available to use.",
traceId = '87506901bc94cce951b29e158163edcc',
context = Seq('participant=>participant1', 'test=>PackageDarManagementDocumentationIntegrationTest')
)
Command ParticipantAdministration$packages$.remove invoked from cmd10000062.sc:1
First unvet the package using the ForceFlag.AllowUnvetPackage
force flag:
@ import com.digitalasset.daml.lf.data.Ref.IdString.PackageId
@ participant1.topology.vetted_packages.propose_delta(participant1.id, removes = Seq(PackageId.assertFromString(mainPackageId)), force = ForceFlags(ForceFlag.AllowUnvetPackage))
Then force remove the package:
@ participant1.packages.remove(mainPackageId, force = true)