What do we mean when we say "charm"?

When describing “charms” to people unfamiliar with the juju ecosystem, we often say things like:

A charmed operator (‘charm’) is an expansion and generalization of the Kubernetes notion of an operator

Software that drives other software on hybrid/multicloud environments

A package of expert knowledge in a reusable and shareable form that hugely simplifies software management and operations

But when juju admins and charm developers talk about charms, they could mean several different things, depending on context.


A “charm” is a zip file but with a .charm extension, which is the product of a charmcraft pack command inside a charm repo (project).

  • A *.charm file can be uploaded to charmhub or deployed directly.
  • A *.charm file does not include resources such as the workload image(s).
  • When we deploy *.charm files directly, we need to specify resources explicitly (if any).
  • The *.charm file is an archive of the operator code.

Charm repo (project)

A “charm” is a repository containing the entrypoints’ code (typically src/charm.py, but depends on the charm type), tests, charm libraries, metadata, CI, etc.

  • We run charmcraft pack inside a charm repo (project) to obtain a *.charm file.
  • A charm repo may be dedicated for a charm relation, in which case the charm is a dummy operator or functions as a relation tester. This is due to a current charmhub limitation that requires charm libraries to be nested under a charm.

Charmhub store item

A “charm” is a versioned item in the charmhub store, which may have charm libraries or resources (such as workload images) attached to it.

  • First, a charm name is registered on charmhub. Charm names on charmhub are unique and are not namespaced.
  • When we deploy charms from charmhub, they are deployed with the same resources they were published (released) with (unless overridden).
  • A charm without a workload is still a charm - a workloadless charm. Some can run on both machine or kubernetes, and some assume a specific platform.
  • A charm with a workload is what we call a charmed application - an application whose configuration, lifecycle etc. are driven by a charmed operator (an operator in the juju ecosysem).

Deployed unit

A “charm” is an entity in the juju model representing a set of containers and their dedicated pod. The unit is named after the pod, the pod is named after the app, and by default the app is named after the charm. For example, if we juju deploy prometheus-k8s prom, then we’d have:

Charm name App name Pod name Unit name
prometheus-k8s prom prom-0 prom/0
  • A unit is a kubernetes pod made up of a charm container and usually one or more workload containers.
  • Each unit runs its own copy of the *.charm.
  • A deployed unit is an operator-in-action.
  • juju status lists deployed units and their status
  • The unit is the subject of juju commands such as run, ssh, etc.

Deployed app

A “charm” is an entity in the juju model representing a set of deployed units of the same app (deployed from a *.charm or charmhub). For example, if we juju deploy prometheus-k8s prom --num-units 3 then we’d have one prom app (comprised of three units).

  • The app is the subject of juju commands such as deploy, relate, scale-application, refresh etc.
  • juju status lists deployed charms and their status

Charm container

A “charm” is the operator’s container that is provisioned next to the workload container.

  • A charm container that drives an application (a workload) is what we call a charmed operator - an operator (in the broad sense), but with extra powers, and that is part of the juju ecosystem.
  • Every deployed unit of a kubernetes charm always has a “charm” container.
  • The charm container makes use of pebble to (re)start/stop the workload.
  • You can ssh into the charm container of a given unit (pod) with juju ssh app/0.

Entrypoints’ code

A “charm” is the code that juju triggers to run on various event hooks. In kubernetes charms, it is typically the src/charm.py file that is packed into a *.charm file.


I’d rather say: they communicate with juju via an http API.

Nice summary, @sed-i! I’ll look for a way to incorporate it in the docs.

Related to this, something I always find very confusing, namely, the fact that “charmed” means something quite different in “charmed application” vs. “charmed operator” – in the former “charmed” means “[an application] that has been charmed” whereas in the latter it means “a fancy kind of [operator]”.

Good point @ppasotti! I added a hook tools ref. Wdyt?

Good point @tmihoc! Incorporated. Wdyt?

I always thought ‘charmed operator’ was jujuspeak for ‘the juju version of an operator, for short: a “charm”’.

So “charmed operator” is (AFAIK) the long version of “charm”

Well I think the phrasing of “they use envvars to communicate with juju” is incorrect.

They use hook tools (which are wrappers to http API calls) to communicate with juju. The hook tools, in turn, pass along some information that is exposed to the charm by means of environment variables.

I’m not sure we’re going for this level of detail in this post, so that’s why I’d rather remove the whole reference to envvars rather than say something which might give the wrong idea (if you say ‘use an envvar to communicate’ someone might think that the charm is setting an envvar to some value and juju/the hook tools somehow picks up on that – which is not what’s going on).

Maybe I’m nitpicking though, feel free to ignore.

1 Like

From what I understand, the “charmed” in “charmed operator” sets up a contrast between operators before Juju, which were only for Kubernetes, and Juju operators, which are for both Kubernetes and non-Kubernetes. So, a charmed operator is an operator with a twist, a fancier operator.

This is, of course, not the sense in which “charmed” is used in “charmed application”.

People get used to this at some point, I think, but it’s not ideal.

The envvar ref is under the “entrypoint” section so I think it makes sense to mention it. But for envvars I meant the incoming comms, not the outgoing comms. A charm is starting in a context of envvars (input) and that’s how it knows its context etc., and responds by calling hook tools (output). Please correct me if I’m wrong.

1 Like

right, ok, in this context it makes sense. Thanks for clarifying

Good point. I think in some places in the post I may had only k8s in mind.


Dont have any valuable feedback at tbis point, except that we should either preface it with making clear we are only talking about k8s, or update the rest with machine equivalent explanations as well.

In any case, I think this is excellent! Great work! :partying_face:

1 Like

I’ve never written a machine charm and I think it’s important to include that angle as well. I am happy to take edits to this post!