Dynamiq
Self-Hosted Deployment

Configuration Reference

How the Dynamiq chart turns values into env vars: required keys, the secret contract, catalyst provider keys, object storage, and External Secrets.

This is the reference for the Helm values that configure a self-hosted install. It assumes you have worked through Install on Kubernetes (Helm) and are now tuning or extending that setup. Every key here comes from the chart's values.yaml, its values.schema.json, or the service source — nothing is invented, and every values snippet on this page renders against chart 0.39.0.

Values are set under a top-level dynamiq block (shared settings) and one block per service — nexus, synapse, catalyst, runtime, and ui.

How configuration flows

Each backend service reads its configuration from four sources, merged in the pod as environment variables. Non-secret values go in a ConfigMap; secrets come from pre-created Secrets, an optional Helm-managed Secret, or the External Secrets Operator. The Deployment mounts them with envFrom, so later sources override earlier ones on a key collision.

SourceValues keyRendered objectRequired?
Non-secret env<svc>.configMapDataConfigMap <svc>Yes — schema-validated keys
Signing keys, provider keyspre-created Secret <svc>Secret <svc>Yes — you create it (install Step 4)
Database credentialspre-created Secret <svc>-dbSecret <svc>-dbYes for nexus, synapse, catalyst; runtime has none
Extra secrets (in-chart)<svc>.secretDataSecret <svc>-secretOptional — mounted with optional: true
All of the above, externally<svc>.externalSecrets.enabledExternalSecret <svc> / <svc>-dbOptional — replaces the pre-created Secrets

The <svc> and <svc>-db Secrets are referenced without optional: true in the Deployments, so the pods will not start until those Secrets exist. The <svc>-secret Secret is optional and is only rendered when you set secretData. Names are not release-prefixed — they follow dynamiq.namePrefix, which defaults to empty. See the install secret manifest for the exact objects.

Required keys per service

These configMapData keys are validated by the chart's JSON schema before render; a missing or invalid one fails the install with a schema error, before anything touches the cluster.

STORAGE_SERVICEenumrequired
Object-storage backend. Only "s3" is accepted (an S3-compatible endpoint also uses this). Required for nexus, synapse, catalyst, runtime.
NATS_URLstringrequired
NATS server URL, e.g. nats://nats.dynamiq.svc.cluster.local:4222. Must be non-empty. Required for nexus, synapse, catalyst, runtime.
FINE_TUNING_DOCKER_IMAGEstringrequired
nexus only. Image for fine-tuning jobs. Schema-required; the chart supplies a default (dynamiqai/fine-tuning:0.3.8).
EMAIL_PROVIDERenumrequired
nexus only. Email transport; only "smtp" is accepted.
EMAIL_FROM_ADDRESSstringrequired
nexus only. Default From address for outbound email.
EMAIL_SMTP_HOSTstring
nexus only. SMTP host. Required when EMAIL_PROVIDER=smtp.
EMAIL_SMTP_USERNAMEstring
nexus only. SMTP username. Required when EMAIL_PROVIDER=smtp (move to the nexus Secret if you treat it as sensitive).

STORAGE_S3_BUCKET is not validated by the schema but is enforced by nexus, synapse, and runtime at pod startup when STORAGE_SERVICE=s3; catalyst reads AWS-related variables (AWS_ENDPOINT_URL, AWS_DEFAULT_REGION, etc.) but does not use STORAGE_S3_BUCKET (buckets are passed per request from the agent).

So nexus requires STORAGE_SERVICE, STORAGE_S3_BUCKET, NATS_URL, FINE_TUNING_DOCKER_IMAGE, EMAIL_PROVIDER, and EMAIL_FROM_ADDRESS (plus the SMTP keys when the provider is smtp); synapse and runtime require STORAGE_SERVICE, STORAGE_S3_BUCKET, and NATS_URL (STORAGE_S3_BUCKET when STORAGE_SERVICE=s3); catalyst requires only STORAGE_SERVICE and NATS_URL. The ui has no required keys.

The secret contract

The pre-created Secrets are the load-bearing part of the install — the pods reference them directly and non-optionally. Create them with the exact keys below (the install page Step 4 has the full manifest; don't duplicate it, just match the keys).

SecretKeysNotes
nexusAUTH_ACCESS_TOKEN_KEY, AUTH_VERIFICATION_TOKEN_KEY, AUTH_INTERNAL_TOKEN_KEY, FIRECRAWL_API_KEY, EMAIL_SMTP_PASSWORDSigning keys plus the Firecrawl and SMTP secrets.
synapseAUTH_INTERNAL_TOKEN_KEYMust match nexus's value.
catalystAUTH_INTERNAL_TOKEN_KEY and provider keysSee Catalyst provider API keys below.
runtimeAUTH_INTERNAL_TOKEN_KEYMust match nexus's value.
nexus-db, synapse-db, catalyst-dbDATABASE_HOST, DATABASE_PORT, DATABASE_NAME, DATABASE_USERNAME, DATABASE_PASSWORD, DATABASE_SCHEMA, DATABASE_SSLMODEOne per service with a database. runtime has no -db Secret.

AUTH_INTERNAL_TOKEN_KEY is the shared internal-auth key and must be identical across nexus, synapse, catalyst, and runtime. Generate it once and reuse it.

Catalyst provider API keys

catalyst validates its settings at startup with pydantic: every field declared as a SecretStr with no default must be present as an environment variable, or the pod fails to start. Beyond the shared AUTH_INTERNAL_TOKEN_KEY, these are the startup-required provider keys (source: app/core/config.py in the catalyst service):

KeyPowers
OPENAI_API_KEY, ANTHROPIC_API_KEY, TOGETHER_API_KEYLLM gateway providers
EXA_API_KEYSearch tool
JINA_API_KEY, FIRECRAWL_API_KEYWeb scraping (WEB_SCRAPER_PROVIDER selects jina or firecrawl)
BROWSERBASE_API_KEY, BROWSERBASE_PROJECT_IDBrowser tool
ELEVEN_API_KEYVoice
E2B_API_KEYCode sandboxes
DYNAMIQ_API_KEYInternal platform calls back to nexus

catalyst also needs NATS_URL (in configMapData) and the DATABASE_* credentials (in the catalyst-db Secret) — both covered elsewhere on this page.

Deliver the provider keys through the catalyst Secret (alongside AUTH_INTERNAL_TOKEN_KEY) or through catalyst.secretData, which the chart renders into the catalyst-secret Secret:

catalyst:
  secretData:
    OPENAI_API_KEY: '<openai-key>'
    ANTHROPIC_API_KEY: '<anthropic-key>'
    TOGETHER_API_KEY: '<together-key>'
    EXA_API_KEY: '<exa-key>'
    JINA_API_KEY: '<jina-key>'
    FIRECRAWL_API_KEY: '<firecrawl-key>'
    BROWSERBASE_API_KEY: '<browserbase-key>'
    BROWSERBASE_PROJECT_ID: '<browserbase-project-id>'
    ELEVEN_API_KEY: '<eleven-key>'
    E2B_API_KEY: '<e2b-key>'
    DYNAMIQ_API_KEY: '<dynamiq-internal-key>'

The service checks only that each key is present, not that it is valid. Provide real keys for the providers your platform uses; for providers you don't use, contact Dynamiq support before relying on placeholder values — the platform feature backed by a placeholder key will fail at call time even though the pod starts.

Object storage

STORAGE_SERVICE is fixed to s3, but the S3 client works against either AWS S3 or any S3-compatible endpoint (MinIO, IBM COS, Ceph, and so on). nexus, synapse, and runtime read the same storage configuration; catalyst reads the region and endpoint but does not use a bucket name (passed per request from the agent). Apply whichever pattern you choose to every service.

Pattern A — AWS S3 with pod identity (recommended on EKS). Set only the bucket and attach an IAM role to each service's ServiceAccount via IRSA or EKS Pod Identity. No access keys live in your values:

nexus:
  configMapData:
    STORAGE_SERVICE: s3
    STORAGE_S3_BUCKET: dynamiq-prod
  serviceAccount:
    annotations:
      eks.amazonaws.com/role-arn: arn:aws:iam::111122223333:role/dynamiq-nexus

Repeat the serviceAccount.annotations block (with the appropriate role) for synapse, catalyst, and runtime.

Pattern B — S3-compatible endpoint. Point the services at your endpoint and supply static credentials. The endpoint and region go in configMapData; the access keys go in each service's Secret. These are exactly the env vars the platform's own local stack passes to nexus and synapse against LocalStack:

nexus:
  configMapData:
    STORAGE_SERVICE: s3
    STORAGE_S3_BUCKET: dynamiq-prod
    AWS_ENDPOINT_URL: https://minio.example.com
    AWS_REGION: us-east-1
synapse:
  configMapData:
    STORAGE_SERVICE: s3
    STORAGE_S3_BUCKET: dynamiq-prod
    AWS_ENDPOINT_URL: https://minio.example.com
    AWS_REGION: us-east-1

Provide AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY through each service's Secret (or secretData), not the ConfigMap.

catalyst reads the region from AWS_DEFAULT_REGION (not AWS_REGION); nexus, synapse, and runtime use AWS_REGION. When you configure an S3-compatible endpoint, set AWS_DEFAULT_REGION on catalyst and AWS_REGION on the Go services — AWS_ENDPOINT_URL and the two access-key vars are identical across all four.

Email

nexus is the only service that sends email. It uses SMTP (EMAIL_PROVIDER accepts only smtp). The non-secret fields go in nexus.configMapData; the password is a secret and lives in the nexus Secret as EMAIL_SMTP_PASSWORD.

nexus:
  configMapData:
    EMAIL_PROVIDER: smtp
    EMAIL_FROM_NAME: Dynamiq
    EMAIL_FROM_ADDRESS: noreply@dynamiq.example.com
    EMAIL_SMTP_HOST: smtp.example.com
    EMAIL_SMTP_PORT: "587"
    EMAIL_SMTP_USERNAME: postmaster@example.com

Optional address validation is available through EMAIL_VALIDATION_ENABLED, EMAIL_VALIDATION_PROVIDER (user_check or static), and EMAIL_VALIDATION_USER_CHECK_API_KEY (secret) — see Optional integrations.

Feature namespaces and workload identity

nexus schedules user workloads — inferences, managed databases, fine-tuning jobs, and (when enabled) user services — into dedicated feature namespaces. The dynamiq.features block names those namespaces and their ServiceAccounts and controls whether the chart creates the namespaces:

dynamiq:
  features:
    createNamespaces: false            # true = chart creates the namespaces
    namespaceAnnotations:
      helm.sh/resource-policy: keep     # keep chart-created namespaces on uninstall
    namespaceLabels: {}
    inferences:
      namespace: dynamiq-inferences
      serviceAccount: inference
    databases:
      namespace: dynamiq-databases
      serviceAccount: database
    fineTuning:
      namespace: dynamiq-fine-tuning
      serviceAccount: fine-tuning
    services:
      enabled: false                    # true also requires image-builder config
      namespace: dynamiq-services
      serviceAccount: service
      imageBuilder:
        namespace: dynamiq-image-builder
        serviceAccount: image-builder

nexus references those ServiceAccounts by name, but the chart creates them separately, governed by nexus.workloadServiceAccounts:

nexus:
  workloadServiceAccounts:
    create: true
    automount: false
    annotations:
      eks.amazonaws.com/role-arn: arn:aws:iam::111122223333:role/dynamiq-workload
    imagePullSecrets:
      - name: docker-registry

workloadServiceAccounts.imagePullSecrets must reference Secrets that exist in each feature namespace, not the release namespace — workload pods run in the feature namespaces. Fine-tuning jobs instead use FINE_TUNING_IMAGE_PULL_SECRET from nexus.configMapData when it is set. See the install page's registry-credentials step.

Enabling user services (dynamiq.features.services.enabled: true) additionally requires SERVICES_IMAGE_REPOSITORY and SERVICES_IMAGE_BUILDER_DOCKER_IMAGE in nexus.configMapData. FINE_TUNING_DOCKER_IMAGE and FINE_TUNING_IMAGE_PULL_SECRET configure the fine-tuning image and its pull secret.

External Secrets Operator

Instead of pre-creating the <svc> and <svc>-db Secrets, the chart can generate ExternalSecret resources that a ClusterSecretStore named dynamiq reconciles from your external secret manager. Enable it per service:

nexus:
  externalSecrets:
    enabled: true
synapse:
  externalSecrets:
    enabled: true
catalyst:
  externalSecrets:
    enabled: true
runtime:
  externalSecrets:
    enabled: true

This renders seven ExternalSecret objects: a <svc> for each of the four services (pulling remote key DYNAMIQ), plus a <svc>-db for nexus, synapse, and catalyst (pulling remote key DYNAMIQ-DB). runtime has no database Secret. Each references kind: ClusterSecretStore, name: dynamiq and refreshes hourly.

The <svc> ExternalSecret extracts the whole DYNAMIQ payload as-is. The <svc>-db ExternalSecret maps specific properties from DYNAMIQ-DB and hard-codes the rest:

# Rendered nexus-db ExternalSecret (abridged)
spec:
  secretStoreRef:
    kind: ClusterSecretStore
    name: dynamiq
  target:
    name: nexus-db
    template:
      data:
        DATABASE_PORT: "5432"
        DATABASE_SSLMODE: "require"
        DATABASE_SCHEMA: "public"
        DATABASE_NAME: "{{ .database }}"
        DATABASE_HOST: "{{ .server_name }}"
        DATABASE_USERNAME: "{{ .username }}"
        DATABASE_PASSWORD: "{{ .password | urlquery }}"
  dataFrom:
    - extract:
        key: DYNAMIQ-DB

So your DYNAMIQ-DB secret must expose the properties database, server_name, username, and password; port, SSL mode, and schema are fixed by the template. DATABASE_PASSWORD is URL-encoded, so store the raw password.

Optional integrations

These toggles are off by default. Set the _ENABLED flag plus its companions; non-secret values go in configMapData, secrets go in the service Secret (or secretData). Keys the chart's values.schema.json documents are validated; the rest are forwarded to the service as-is.

GroupKeysWhere
Google / Microsoft SSO loginAUTH_GOOGLE_OAUTH2_{ENABLED,CLIENT_ID,REDIRECT_URL}, AUTH_MICROSOFT_OAUTH2_{ENABLED,CLIENT_ID,REDIRECT_URL,TENANT_ID}configMapData
SSO client secretsAUTH_GOOGLE_OAUTH2_CLIENT_SECRET, AUTH_MICROSOFT_OAUTH2_CLIENT_SECRETSecret
Sign in with Slack (login)AUTH_SLACK_OAUTH2_{ENABLED,CLIENT_ID,REDIRECT_URL} (+ AUTH_SLACK_OAUTH2_CLIENT_SECRET as a secret) — nexusconfigMapData / Secret
Token TTLsAUTH_{ACCESS,REFRESH,VERIFICATION}_TOKEN_TTL_SECONDS (+ AUTH_REFRESH_TOKEN_KEY as a secret)configMapData
Connection OAuthCONNECTIONS_{GOOGLE,MICROSOFT,BOX,DROPBOX,NOTION,GITHUB}_OAUTH2_{ENABLED,CLIENT_ID,REDIRECT_URL} (+ _CLIENT_SECRET as a secret)configMapData / Secret
CORSCORS_ALLOW_CREDENTIALS, CORS_ALLOWED_ORIGINS, CORS_ALLOWED_ORIGINS_REGEXESconfigMapData
Chat over NATSCHAT_NATS_ENABLED, CHAT_NATS_STREAM_NAME, CHAT_NATS_SUBJECT_PREFIXconfigMapData
Wilson (Slack coworker)catalyst SLACK_{ENABLED,CLIENT_ID,DEFAULT_MODEL_SLUG,WORKSPACE_REDIRECT_URL,USER_REDIRECT_URL} (requires CHAT_NATS_ENABLED; + SLACK_CLIENT_SECRET, SLACK_SIGNING_SECRET as secrets)catalyst configMapData / Secret
ComposioCOMPOSIO_{ENABLED,PROJECT_ID} (+ COMPOSIO_API_KEY as a secret)configMapData / Secret
PipedreamPIPEDREAM_{ENABLED,CLIENT_ID,PROJECT_ID,ENVIRONMENT,WEBHOOK_URL} (+ PIPEDREAM_CLIENT_SECRET as a secret)configMapData / Secret
Code sandboxesSANDBOXES_{ENABLED,PROVIDER} (+ SANDBOXES_E2B_API_KEY as a secret — on nexus and synapse)configMapData / Secret
Email validationEMAIL_VALIDATION_{ENABLED,PROVIDER} (+ EMAIL_VALIDATION_USER_CHECK_API_KEY as a secret)configMapData / Secret
CAPTCHACAPTCHA_{ENABLED,PROVIDER}, CAPTCHA_TURNSTILE_SITE_KEY (+ CAPTCHA_TURNSTILE_SECRET_KEY as a secret)configMapData / Secret
BillingBILLING_ENABLED (+ BILLING_STRIPE_* as secrets; off on self-host)configMapData / Secret
ObservabilityOTEL_ENABLED, OTEL_EXPORTER_OTLP_METRICS_{ENDPOINT,PROTOCOL}, OTEL_METRICS_EXPORTER, OTEL_METRIC_EXPORT_INTERVAL, SENTRY_{ENABLED,DSN}, USER_TRACKING_{ENABLED,SEGMENT_WRITE_KEY}configMapData (SENTRY_DSN, USER_TRACKING_SEGMENT_WRITE_KEY as secrets)
synapse apps over NATSAPPS_NATS_{ENABLED,STREAM_NAME,BUCKET_NAME,SUBJECT_PREFIX}synapse configMapData
Fine-tuningHUGGING_FACE_ACCESS_TOKENSecret

Toggles not listed in the chart's values.schema.json are forwarded to the service unvalidated — confirm their exact semantics with Dynamiq support before relying on them in production.

Sizing, scheduling, autoscaling

Every service block accepts the same scheduling and sizing keys. This pattern (shown for catalyst) applies unchanged to nexus, synapse, runtime, and ui:

catalyst:
  replicaCount: 3
  resources:
    requests:
      cpu: "1"
      memory: 1Gi
    limits:
      cpu: "2"
      memory: 2Gi
  autoscaling:
    enabled: true          # renders an HPA; overrides replicaCount when on
    minReplicas: 3
    maxReplicas: 12
    targetCPUUtilizationPercentage: 70
    # targetMemoryUtilizationPercentage: 80
  nodeSelector:
    workload: dynamiq
  tolerations:
    - key: dedicated
      operator: Equal
      value: dynamiq
      effect: NoSchedule
  affinity: {}
  podAnnotations:
    prometheus.io/scrape: "true"

When autoscaling.enabled is true the chart renders a HorizontalPodAutoscaler and drops the static replicas field so the HPA owns the replica count. catalyst and runtime ship the heaviest defaults (512Mi/500m requests, 2Gi/2000m limits) because they run the execution workloads; nexus, synapse, and ui are lighter. The System Requirements sizing baseline lists every default, and these are starting points — size for your real workload before production. For node counts and instance types to provision before you set any of this, see Cluster sizing starting points.

Next steps

On this page