Skip to main content

App & global configuration

This article refers to SDK version v0.5.0. The current SDK version is N/A.

Overview

Application configuration is a free-form JSON document, typically read by a workload at startup or at runtime to adjust its behavior without rebuilding it. This is the same concept documented from the Panel side in Application configuration types, which lists five mechanisms in total; the SDK exposes the two JSON-based ones at three scopes: node (what Panel calls Global Config), workload (a single deployed app, what Panel calls App Config), and a reusable, named config document from the Config Repository you can attach to many nodes, clusters, or workloads without duplicating it. Secrets and Compose Config, the other configuration types in that reference, are covered separately in Node & cluster secrets and Marketplace workload deployment.

Every set_*_config/get_*_config method below shares the same two-parameter shape: an inline config dict, or a config_id referencing a reusable entry. Passing both is allowed, but config_id takes precedence, so the inline config is silently ignored in that case.

Concept

Config Repository. A library in Barbara Panel of reusable JSON documents an operator writes once and attaches to many nodes, clusters, or workloads, instead of pasting the same configuration into each one by hand.

Learn more

Configure a node's Global Config

Applies to every workload on the node unless a workload overrides it, the same JSON payload managed from the Global Config card in Panel and delivered to every container as /appconfig/global.json.

client.nodes.set_global_config(node.id, config={"threshold": 5})
config = client.nodes.get_global_config(node.id)

set_global_config(node_id, *, config=None, config_id=None) on client.nodes: config is any JSON-serializable Dict[str, Any]; the SDK JSON-encodes and base64-encodes it before sending, the same encoding convention used for secrets and docker credentials. get_global_config(node_id) returns the decoded dict directly, symmetric with what you sent; the real API response wraps it in a sent/current/status propagation envelope so Panel can show whether a node has actually applied the latest push, but the SDK unwraps that for convenience; use client.request(...) directly if you need to inspect the envelope itself, for example to check whether sent and current still disagree after a push.

Configure a workload's App Config

Scoped to one deployed app, overrides the node-level config for that workload only, the same JSON payload behind the workload card's App Config segment and delivered to that one container as /appconfig/appconfig.json.

client.nodes.workloads.set_app_config(node.id, "<workload-id>", config={"threshold": 10})
config = client.nodes.workloads.get_app_config(node.id, "<workload-id>")

Same config/config_id pair as the node-level call, with a workload_id added after node_id on client.nodes.workloads. A workload without its own App Config falls back to reading only the node's Global Config; setting one here doesn't merge with the node-level document, the workload's container sees both files (appconfig.json and global.json) separately and is responsible for reading whichever one it needs, exactly as documented for Docker apps reading /appconfig/appconfig.json in Docker apps.

Reuse a config from the Config Repository

In the product, the Config repository is where a JSON document you'd otherwise have to paste into every node's Global Config or every workload's App Config lives in one place instead: searchable, reusable, and traceable to the nodes and workloads running it. The SDK's resource for this is client.configs. Create an entry once, reference it by id anywhere set_global_config/set_app_config accepts a config_id instead of an inline config, useful when the same document needs to be attached to many nodes, clusters, or workloads.

config_doc = client.configs.create(
name="sensor-thresholds",
description="Per-node alert thresholds",
config={"temperature_max": 80},
)

create(name, description, config, *, is_global=False):

ParameterTypeWhat it is
namestrA label for this reusable config, shown as Config Name in the repository view when you look it up later with client.configs.list()
descriptionstrFree text describing what the config is for
configDict[str, Any]The JSON document itself, same shape as an inline config above
is_globalboolWhether this document is a Global-typed config (applies at node level, no single application) or an application-typed one; default False, meaning application-scoped

is_global is what drives the Config Type column in the repository view: Panel shows Global for a config meant to configure a whole node, and the specific application name for one meant for a single workload's App Config. This is surfaced back to you on the returned object as config_type, see the table below.

Unlike client.nodes.set_global_config, create returns the created Config object directly, so config_doc.id is available immediately without a follow-up lookup:

FieldTypeWhat it is
idstrThe internal identifier, what config_id expects everywhere else in this guide
namestrThe name you gave it
config_typestrThe Config Type Panel shows in the repository view: an application-scoped or global-scoped document
rawDict[str, Any]The full untyped API response, including which application and how many nodes currently apply this config, when set
client.nodes.set_global_config(node.id, config_id=config_doc.id)

config_id here is the id field of the Config object just created, not its name; passing the name fails, since the API expects the internal identifier.

client.configs.update("<config-id>", config={"temperature_max": 85})
client.configs.delete("<config-id>")

update(config_id, *, name=None, description=None, config=None, is_global=None) only changes the fields you pass; unlike client.applications.update, this one supports a genuine partial update, so passing just config=... leaves name, description, and is_global untouched. delete(config_id) removes the reusable entry; any node or workload still referencing it by config_id needs to be re-pointed at a different config or an inline config, or it keeps whatever value was last successfully propagated.

Applied configs can't be overwritten

Panel enforces one rule the SDK doesn't check ahead of time: a config currently Applied on one or more nodes can't be overwritten in place from the repository UI, only saved as a new config, so that the applied record stays accurate. client.configs.update calls straight through to the API, so whether an in-use config can be updated in place through the SDK depends on the API's own enforcement of that rule, not on anything the SDK adds. If you hit a rejection updating a config you know is in use, create a new one with create and re-point your nodes/workloads at its id instead.

Configure at cluster scope

Clusters and cluster workloads accept the exact same config=/config_id= pair, mirroring the Global Config (cluster) card:

client.clusters.set_global_config("<cluster-id>", config={"threshold": 5})

client.clusters.set_global_config(cluster_id, *, config=None, config_id=None) behaves like the node-level call above, just synchronized to every node in the cluster rather than one. client.clusters.workloads.set_app_config(cluster_id, workload_id, *, config=None, config_id=None) is the cluster-workload equivalent of a node workload's App Config, scoped to a single workload rather than the whole cluster.

Summary

Three scopes, one shape: pass config for an inline document, or config_id to reference a reusable one from the Config Repository, at node, workload, or cluster level.

Reach for the Config Repository as soon as you're repeating the same document across more than a couple of nodes, it keeps a single source of truth instead of drifting copies, and Panel's own Applied on tracking tells you exactly which nodes would be affected by a change.

For the full method list, see client.configs in the Reference.