Migrate from Dapr OSS on Kubernetes to Catalyst
Catalyst is built on Dapr OSS, so it supports the same APIs, resource types, and a selection of Dapr components*. As a result, your existing Dapr resources, such as policies and configurations, work without modification, and your application code can keep using the same Dapr SDKs.
This guide walks you through the process of migrating your workloads from Dapr OSS on Kubernetes to Catalyst.
- Components: *Catalyst supports a curated subset of Dapr OSS components — state stores, pub/sub brokers, secret stores, bindings, conversation, and so on. Check the Catalyst component specs reference and confirm that every component type you rely on is supported. Components that aren't listed won't work on Catalyst and need an alternative or an exception before you can complete the migration.
- Secret stores: Catalyst does not support
secretstores.kubernetes, the secret store most Dapr applications on Kubernetes use. See Secret stores for what to do instead — depending on how you use it, you may need no secret store at all, or you may need to provision one before you migrate. - Configuration: In Catalyst you can only configure some fields within a Dapr
Configurationresource; others are reserved for Catalyst's internal use. See Dapr configuration compatibility for the full list of editable and reserved fields.
Prerequisites
- A Kubernetes cluster running Dapr open source.
- A Diagrid Catalyst organization you have global
adminoreditoraccess to. You can sign up for free at Diagrid Catalyst. - The Diagrid CLI installed and authenticated.
- A secret store Catalyst supports — AWS Secrets Manager, Azure Key Vault or HashiCorp Vault — but only if one of your applications calls the Dapr Secrets API. See Secret stores.
Starting point: Dapr OSS on Kubernetes
A typical Dapr OSS setup looks like this:
- The Dapr control plane installed in the
dapr-systemnamespace via Helm or the Dapr CLI. - Application pods annotated with
dapr.io/enabled: "true", which get a Dapr sidecar injected by the Dapr operator. - Dapr CRDs such as Components, Configurations, Subscriptions, and Resiliency policies, stored in the Kubernetes cluster.
Two decisions shape your migration
Before you start, you need to make two decisions — one architectural, one operational:
- Where the Dapr server runs — in Catalyst (remote) or in your application Kubernetes cluster (local).
- Which tools you want to use — with Catalyst-native tooling (UI, CLI, Terraform) or with the Catalyst Kubernetes operator.
Dapr Server location: remote or local
- Remote — Catalyst's Dapr server runs in Catalyst. Your app calls the Dapr API via Catalyst's endpoint and no Dapr server runs inside your app pod.
- Local — Catalyst's Dapr server runs as a sidecar in your app pod, configured to talk to Catalyst's Dapr control plane. Your app continues to talk to the Dapr APIs over
localhostthe same as Dapr OSS.
Pick remote for zero server ops and the lowest infrastructure footprint. Pick local when the Dapr server must stay inside your network boundary or be co-located with the workload.
Local Dapr Server networking
If you choose the local location for your Dapr Server, note that it will run inside your application Kubernetes cluster and is thus subject to your cluster's networking rules and policies.
All traffic between the app, the Dapr Server sidecar, and any infrastructure is fully within your control and cannot be influenced by Catalyst. You are responsible for configuring appropriate network policies to isolate your workloads and allow access to the services and infrastructure they need.
Tooling: Catalyst-native or Kubernetes-native
You can choose the tooling that best suits your setup for migrating and managing your workloads on Catalyst. For existing Dapr apps running on Kubernetes, the Catalyst Kubernetes Operator provides a simpler migration path. Once you've migrated your workloads, you can switch to using the native Catalyst tooling if you prefer.
Select from one of the options below to see how you can use that tooling to migrate your workloads.
| Path | Best when | What it does |
|---|---|---|
| Catalyst-native | Catalyst is your source of truth and you drive infra from the UI, CLI, or Terraform | You create Catalyst resources yourself, then wire each workload to Catalyst |
| Kubernetes-native | Your platform team already manages Dapr declaratively in-cluster | The Catalyst Kubernetes operator reconciles Dapr's K8s native resources into Catalyst |
Secret stores
Catalyst supports three secret store types: aws.secretsmanager, azure.keyvault and hashicorp.vault. It does not support secretstores.kubernetes, the default secret store for a Dapr application on Kubernetes. Applying a component of that type is rejected:
invalid value of 'secretstores.kubernetes' provided for 'spec.type' field:
please use a supported type. See our docs @ https://docs.diagrid.io.
What to do about it depends on how your applications use the store, and the two cases are independent. Check both.
Components that reference a secret
A component whose metadata uses secretKeyRef needs no secret store on Catalyst. Supply the value as plaintext instead:
# Dapr OSS
- name: redisPassword
secretKeyRef:
name: redis-secret
key: password
# Catalyst
- name: redisPassword
value: "<password>"
Catalyst identifies sensitive fields from the Dapr component metadata schema and extracts them into a Catalyst-managed secret store before the resource is persisted, so the plaintext value is never stored in the control plane. See Managing secrets.
This is a change of secrets model rather than a component swap: the value moves out of your cluster and into Catalyst.
Applications that call the Secrets API
An application that calls GetSecret or GetBulkSecret needs a real secret store, so secretstores.kubernetes has to be replaced with one of the three supported types. Provision it before you migrate, because the application fails at runtime without it.
Two things to plan for:
- Move the secret data. The contents of your Kubernetes
Secretobjects have to exist in the new store before the migrated application reads them. - Keep the component name. Your application names the store in every call, so reusing the original component name — only changing
spec.typeand its metadata — means the application code does not change.
Dapr configuration compatibility
Catalyst supports the Dapr Configuration resource, but some fields are reserved for Catalyst's internal use and cannot be changed. Behavior can also differ between public (multi-tenant SaaS) regions and self-hosted (private) regions. Each field falls into one of these categories per region:
- 🔒 Locked — Catalyst manages this field. Any value you supply is ignored or overwritten.
- ✏️ Editable — You can set this field, subject to the validation noted.
| Field | Public regions | Self-hosted regions | Notes |
|---|---|---|---|
accessControl.trustDomain | 🔒 Locked | 🔒 Locked | Reserved by Catalyst; set automatically to your organization's SPIFFE trust domain. |
accessControl.policies[].trustDomain | 🔒 Locked | 🔒 Locked | Forced to your organization's trust domain. |
accessControl.policies[].namespace | 🔒 Locked | 🔒 Locked | Forced to your project namespace (prj-<namespace>). |
features | 🔒 Locked | 🔒 Locked | Preview feature toggles are managed by Catalyst. |
api.allowed | 🔒 Locked | 🔒 Locked | Restricted to the Catalyst platform API allow-list. |
metrics | 🔒 Locked | 🔒 Locked | Catalyst applies its own metric cardinality rules. |
tracing (otel / zipkin) | 🔒 Editable | ✏️ Editable | Requires otel.isSecure. Custom/internal endpoints are rejected in public regions. |
workflow.maxConcurrentWorkflowInvocations, workflow.maxConcurrentActivityInvocations | 🔒 Locked | ✏️ Editable | Concurrency limits. Managed by Catalyst in public regions; editable up to Catalyst's caps (5000 / 10000) in self-hosted regions. |
workflow.stateRetentionPolicy (anyTerminal, completed, failed, terminated) | ✏️ Editable | ✏️ Editable | Per-terminal-state retention durations (Go duration strings). Added in Dapr 1.17. |
httpPipeline / appHttpPipeline handlers (user middleware) | ✏️ Editable | ✏️ Editable | User handlers are appended after Catalyst's reserved base handler, which is always present and cannot be removed. |
accessControl.defaultAction + accessControl.policies[] (appId, defaultAction, operations with name / httpVerb / action) | ✏️ Editable | ✏️ Editable | Validated as allow/deny rules. |
Next steps
- Migrate your workloads with the Catalyst Kubernetes operator or Catalyst-native tooling.
- Cut over and decommission Dapr OSS — move traffic onto Catalyst and remove the Dapr OSS control plane.