Skip to content

Tenant Model

The Tenant Model is the JSON document that describes a GitLab Dedicated tenant. Its schema lives in tenant-model-schema. This page describes the parts that configure Runway modules: the ModuleSchema object, and the values_override block that Runway checks on top of it.

{
"modular_features": {
"modules": {
"example-service-dedicated": {
"enabled": true,
"version": "v1.25.0",
"values_override": {
"infrastructure": {
"s3": {
"uploads": {}
},
"rds": {
"main": { "instance_type": "small" }
}
},
"helm": {
"values": {
"environment": { "LOG_LEVEL": "debug" }
}
}
}
}
}
}
}
Field Type Description
modules object Map of module name to its module configuration. The module name is the Runway service ID.
runwayctl.version string Version of runwayctl used to deploy the modules: a tag, a branch name, or latest. Defaults to latest.

Module names must match ^[a-z0-9]([-a-z0-9]{0,51}[a-z0-9])?$: 1 to 53 lowercase letters, digits, and hyphens, starting and ending with a letter or digit.

modular_features.modules.<module-name> (ModuleSchema in the Tenant Model schema) configures one module. Unknown fields are rejected.

Field Type Description
enabled boolean Required. Enables the module. Defaults to false.
version string Required. Version of the module to deploy: a release tag such as v1.2.3, or latest. A release tag must be in the Module Catalog.
values_override object Tenant-specific settings. See values_override.

The Tenant Model schema accepts any object as values_override. Runway parses the parts it reads with its own values_override definition when it provisions or deploys the module, and fails loudly on unknown fields inside them. Other top-level fields of values_override are ignored.

Field Type Description
infrastructure object The module’s infrastructure: S3 buckets, PostgreSQL and Redis instances.
helm object The module’s Helm release.
connections object The peer modules the module connects to.
secrets object The module’s private secrets: rotation and deletion.

Tenant-specific overrides of the module’s infrastructure, keyed by the AWS service that implements it, then by the logical name of the bucket or instance. Unknown fields are rejected.

Field Type Description
s3 object Overrides of the module’s S3 buckets.
rds object Overrides of the module’s PostgreSQL (Amazon RDS) instances.
elasticache object Overrides of the module’s Redis (Amazon ElastiCache for Valkey) instances.

Each field is a map from a logical name to the settings of one bucket or instance. The pages linked above list the settings, their built-in defaults, and the rules for logical names, which are at most 45 characters long.

The module sets the defaults of its buckets and instances in its module manifest, and Runway merges the Tenant Model over them, by logical name and then field by field. A tenant only sets what differs, and a tenant that is happy with the defaults needs no infrastructure block at all. Each setting comes from the first of these that sets it:

  1. The entry in the Tenant Model.
  2. The entry’s defaultConfig in the module manifest, from the Module Catalog entry.
  3. The built-in default.

An explicit false or 0 in the Tenant Model overrides a default. An entry in the Tenant Model doesn’t have to be complete, or valid on its own: it only has to parse. Runway validates the merged result of every enabled entry. A tenant can also add an entry that has no default, which must then be complete on its own.

Every entry has an enabled field. Unset means enabled. A tenant turns on an entry that the module turns off by default with enabled: true, and turns off an entry with enabled: false. Runway ignores disabled entries: it doesn’t provision them, doesn’t deploy a Secret or Helm values for them, and doesn’t check their other settings. Disabling an entry that was provisioned before has the same effect as removing it: the next provision destroys the bucket or instance. For PostgreSQL, prevent_db_deletion stops this.

The module’s Fairway manifest declares whether it needs each dependency (its presence in the Module Catalog entry). Runway checks the enabled entries of each dependency, after the merge, against it:

Presence Enabled entries, after the merge
REQUIRED At least one.
OPTIONAL Any number, including none.
UNUSED None.
Infrastructure overrides
{
"infrastructure": {
"s3": {
"uploads": { "versioning": false }
},
"rds": {
"main": { "instance_type": "large" }
},
"elasticache": {
"cache": { "enabled": true }
}
}
}

Tenant-specific settings of the module’s Helm release. Unknown fields are rejected.

Field Type Description
values object Helm values, merged over the default values from the Module Catalog entry.
registry string OCI registry and repository path of the chart, without a scheme (e.g. registry.gitlab.com/gitlab-org/charts). Replaces helm.registry from the Module Catalog entry.
chart string Name of the chart’s repository in the OCI registry. Replaces helm.chart from the Module Catalog entry.

The Helm values are documented in the Fairway values reference. Field names can be in camelCase (imagePullPolicy) or snake_case (image_pull_policy).

Runway merges values over the module’s default values (see Helm Values): objects are merged, lists are replaced. Tenants can override any value, but overrides are an escape hatch: values that every tenant needs, including templates for tenant-specific values, belong in the service repository. Runway checks the result in two steps:

  • values must match the Fairway values structure: unknown fields and wrong types are errors. It doesn’t have to be valid on its own, since it is only a partial structure.
  • The merged values must be valid.
Helm values
{
"helm": {
"values": {
"imagePullPolicy": "Always",
"environment": { "LOG_LEVEL": "debug" },
"scalability": { "minInstances": 2 }
}
}
}

registry and chart change where Runway pulls the module’s chart from: Runway installs oci://<registry>/<chart> at the version from the Module Catalog entry. Each field is optional and replaces only its own field of the catalog entry, so you can, for example, set only registry. They are an escape hatch, for example for a chart that is published to a registry the tenant can’t reach. The Module Catalog entry remains the source of truth: remove the overrides once the chart is available from its catalog location.

Chart location
{
"helm": {
"registry": "mirror.example.com/charts",
"chart": "my-chart"
}
}

Overrides the peer modules the module connects to, from the Module Catalog entry. It has the same shape as connections in the module manifest, and also accepts modules.add, which appends peers instead of replacing them. Setting both modules.set and modules.add is an error. See Connections for the cases.

Connections
{
"connections": {
"modules": { "add": [{ "name": "artifact-registry-dedicated" }] }
}
}

Tenant-specific settings of the module’s secrets, keyed by logical name. Each entry takes the secret settings and is merged over the module’s default of the same name, field by field, like infrastructure. A tenant can also add a secret that has no default. Two settings are only allowed here, not in the module manifest:

  • version rotates the secret: increase it, then provision and deploy the module. Only ever increase it. See Rotating a secret.
  • prevent_deletion protects the secret’s value, and is true unless set.
Rotate a secret
{
"secrets": {
"root-key": { "version": 2 }
}
}