Skip to content

Storing and Using Application Configuration

ConfigHub enables application configuration files to be represented in their native formats while supporting standard ConfigHub configuration functionality. Application configuration units can be operated upon by standard ConfigHub functions, filtered using ConfigHub's filter syntax, and managed as variants with upstream/downstream relationships. Values can be resolved across links via the Needs/Provides mechanism. Application configuration units can be rendered and deployed as Kubernetes ConfigMaps, mounted as ConfigMap volumes, or -- in the case of Env files -- injected as environment variables using envFrom.

Supported formats

ConfigHub supports the following ToolchainType values for application configuration:

ToolchainType Format File suffix
AppConfig/YAML YAML .yaml
AppConfig/JSON JSON .json
AppConfig/INI INI .ini
AppConfig/TOML TOML .toml
AppConfig/Properties Java Properties .properties
AppConfig/Env Environment variables .env
AppConfig/Text Text .txt

Required metadata fields

Each application configuration file must include ConfigHub metadata fields, represented consistently with its format. These fields are stripped when rendering a ConfigMap for use within a Kubernetes workload.

  • configHub.configName -- Uniquely identifies the configuration file. Required for most ConfigHub functionality. Treated similarly to Kubernetes resource names. Also used to generate the data key in the rendered ConfigMap, with the format's file suffix appended (e.g., MyApplicationConfig.ini).
  • configHub.configSchema -- Uniquely identifies the set of valid values. Required. Conceptually similar to a Kubernetes resource type (e.g., apps/v1/Deployment). Can be used with the vet-jsonschema function to validate application configuration units.

For AppConfig/Text, these metadata fields are stored as standard YAML frontmatter at the beginning of the file, delimited by ---, with the fields nested under a configHub key (see the Text example below). For all other formats, the fields use the configHub. prefix in the format's native syntax.

Example configuration files

Below are examples showing the same application configuration in each supported format.

YAML (AppConfig/YAML)

configHub:
  configName: MyApplicationConfig
  configSchema: SimpleApp
app:
  features:
    - authentication
    - logging
  name: MyApplication
  version: 1.0.0
database:
  host: localhost
  port: 5432
  ssl:
    enabled: true

JSON (AppConfig/JSON)

{
  "configHub": {
    "configName": "MyApplicationConfig",
    "configSchema": "SimpleApp"
  },
  "app": {
    "features": ["authentication", "logging"],
    "name": "MyApplication",
    "version": "1.0.0"
  },
  "database": {
    "host": "localhost",
    "port": 5432,
    "ssl": {
      "enabled": true
    }
  }
}

TOML (AppConfig/TOML)

[configHub]
configName = "MyApplicationConfig"
configSchema = "SimpleApp"

[app]
features = ["authentication", "logging"]
name = "MyApplication"
version = "1.0.0"

[database]
host = "localhost"
port = 5432

[database.ssl]
enabled = true

INI (AppConfig/INI)

[configHub]
configName = MyApplicationConfig
configSchema = SimpleApp

[app]
features.0 = authentication
features.1 = logging
name = MyApplication
version = 1.0.0

[database]
host = localhost
port = 5432

[database.ssl]
enabled = true

Properties (AppConfig/Properties)

configHub.configName=MyApplicationConfig
configHub.configSchema=SimpleApp
app.features.0=authentication
app.features.1=logging
app.name=MyApplication
app.version=1.0.0
database.host=localhost
database.port=5432
database.ssl.enabled=true

Env (AppConfig/Env)

configHub.configName=MyApplicationConfig
configHub.configSchema=SimpleApp
APP_FEATURES_0=authentication
APP_FEATURES_1=logging
APP_NAME=MyApplication
APP_VERSION=1.0.0
DATABASE_HOST=localhost
DATABASE_PORT=5432
DATABASE_SSL_ENABLED=true

Text (AppConfig/Text)

Text files use standard YAML frontmatter (delimited by ---) to store ConfigHub metadata:

---
configHub:
  configName: MyApplicationConfig
  configSchema: SimpleApp
---
# My Application Config

Valid config options are:
* Database Host
* Database Port
* Database SSL Enabled

Deploying as a Kubernetes ConfigMap

Application configuration units can be rendered as Kubernetes ConfigMaps using the ConfigMapRenderer bridge. The bridge supports two modes, controlled by the RevisionHistoryLimit option:

Immutable mode (default, RevisionHistoryLimit >= 1): Each apply produces a new immutable ConfigMap with a unique name generated by appending a content hash to the unit slug (similar to ConfigMaps generated by Kustomize). The most recent ConfigMap has the annotation confighub.com/RenderRevision: Latest. By default, the bridge retains 10 revisions to remain available to old Pods during Kubernetes rolling updates. The workload must use confighubplaceholder in its ConfigMap references, and the Needs/Provides mechanism replaces them with the generated name.

Mutable mode (RevisionHistoryLimit=0): Produces a single mutable ConfigMap with a stable, predictable name equal to the unit slug (no hash suffix). The workload can reference the ConfigMap by name directly. The ConfigMap carries a confighub.com/Hash annotation containing the content hash. This annotation is registered as a provided value on the ConfigMap and as a needed value on workload podSpec template annotations, so it is automatically propagated via the Needs/Provides mechanism. When the ConfigMap content changes, the hash annotation on the workload's pod template changes, triggering a rolling update. Mutable mode is simpler to set up but does not preserve old ConfigMap versions during rollouts.

Step 1: Create the application configuration unit

Save your configuration file (using any of the supported formats above) and create a unit:

cub unit create --space my-space my-config app.env --toolchain AppConfig/Env

Step 2: Modify configuration values (optional)

You can use functions to modify values in the application configuration:

cub function do --space my-space --where "Slug = 'my-config'" --toolchain AppConfig/Env set-string-path SimpleApp "DATABASE_HOST" postgres.example.com
cub function do --space my-space --where "Slug = 'my-config'" --toolchain AppConfig/Env set-bool-path SimpleApp "DATABASE_SSL_ENABLED" false
cub function do --space my-space --where "Slug = 'my-config'" --toolchain AppConfig/Env set-int-path SimpleApp "DATABASE_PORT" 5433

Step 3: Create the server worker

The ConfigMapRenderer is a built-in server bridge that runs inside the ConfigHub server -- no external worker process is needed. Create a server worker if it doesn't already exist:

cub worker create --space default --allow-exists --is-server-worker server-worker

The --allow-exists flag makes the command idempotent. The worker can be placed in any space and referenced from other spaces using the space/worker syntax (e.g., default/server-worker).

Step 4: Create a Target for the ConfigMapRenderer

Create a Target with ProviderType ConfigMapRenderer and LiveStateType Kubernetes/YAML (no parameters are needed):

cub target create --space my-space my-target '' default/server-worker --provider ConfigMapRenderer --toolchain AppConfig/Env --livestate-type Kubernetes/YAML

To change the number of ConfigMap revisions retained, set the RevisionHistoryLimit bridge option:

cub target create --space my-space my-target '' default/server-worker --provider ConfigMapRenderer --toolchain AppConfig/Env --livestate-type Kubernetes/YAML --option RevisionHistoryLimit=5

To use mutable mode (a single mutable ConfigMap with a stable name), set RevisionHistoryLimit to 0:

cub target create --space my-space my-target '' default/server-worker --provider ConfigMapRenderer --toolchain AppConfig/Env --livestate-type Kubernetes/YAML --option RevisionHistoryLimit=0

For Env files that should be injected as environment variables using envFrom (where each key-value pair becomes a separate ConfigMap data entry), set the AsKeyValue bridge option:

cub target create --space my-space my-target-kv '' default/server-worker --provider ConfigMapRenderer --toolchain AppConfig/Env --livestate-type Kubernetes/YAML --option AsKeyValue=true

Step 5: Attach the Target and apply

cub unit set-target --space my-space my-config my-target
cub unit apply --wait --space my-space my-config

You can inspect the rendered ConfigMap in the unit's live state:

cub unit livestate --space my-space my-config

Step 6: Create a unit for the rendered ConfigMaps

Create a Kubernetes/YAML unit to receive the rendered ConfigMaps, and link it to the application configuration unit with UseLiveState true, UpdateType MergeUnits, and AutoUpdate true so that new ConfigMaps are propagated automatically.

Link the ConfigMap unit to a unit containing the target Kubernetes Namespace resource. The rendered ConfigMap contains a namespace placeholder that the Needs/Provides mechanism will replace with the actual namespace name:

cub unit create --space my-space my-configmap
cub link create --space my-space - my-configmap my-namespace
cub link create --space my-space --wait - my-configmap my-config --use-live-state --auto-update --update-type MergeUnits

Link the unit containing your Kubernetes workload (e.g., a Deployment) to the ConfigMap unit:

cub link create --space my-space - my-deployment my-configmap

Immutable mode workload configuration

In immutable mode, the workload should use confighubplaceholder in its ConfigMap references. Needs/Provides will replace the placeholder with the generated ConfigMap name. You may optionally use --where-resource on the link to match only the most recently generated ConfigMap:

cub link create --space my-space - my-deployment my-configmap --where-resource "metadata.annotations.confighub~1com/RenderRevision = 'Latest'"

Note: ~1 is the path escaping encoding for / (inspired by JSON Pointer) in the annotation key confighub.com/RenderRevision.

spec:
  template:
    spec:
      containers:
        - name: nginx
          volumeMounts:
            - name: config-volume
              mountPath: /etc/nginx/app.properties
              subPath: app.properties
      volumes:
        - name: config-volume
          configMap:
            name: confighubplaceholder

When the workload unit is resolved, confighubplaceholder will be replaced with the name of the latest rendered ConfigMap.

Mutable mode workload configuration

In mutable mode, the ConfigMap has a stable name equal to the unit slug, so you can reference it directly. Add a confighub.com/Hash annotation with confighubplaceholder to the pod template; Needs/Provides will replace it with the content hash, triggering a rolling update whenever the ConfigMap changes:

spec:
  template:
    metadata:
      annotations:
        confighub.com/Hash: confighubplaceholder
    spec:
      containers:
        - name: nginx
          volumeMounts:
            - name: config-volume
              mountPath: /etc/nginx/app.properties
              subPath: app.properties
      volumes:
        - name: config-volume
          configMap:
            name: my-config

Environment variable injection using envFrom

For both modes, environment variable injection works the same way (use confighubplaceholder in immutable mode or the stable name in mutable mode):

spec:
  template:
    spec:
      containers:
        - name: nginx
          envFrom:
            - configMapRef:
                name: confighubplaceholder

When a workload references multiple ConfigMaps, each ConfigMap's hash is propagated separately. Combining multiple hashes into a single annotation is not yet supported.