Use a Matrix Generator and a RollingSync strategy in a single ApplicationSet to enforce both environment sequencing (dev before staging) and within-environment dependency ordering (app1 before app2).
Background
When you deploy a web application with interdependent components — such as a database, backend, and frontend — you must deploy them in a specific order: Database > Backend > Frontend. In ACK One GitOps, each component maps to a separate Argo CD Application, so controlling deployment order across multiple Applications requires additional orchestration.
ApplicationSet automates this by generating multiple Argo CD Applications from a single template, making it well-suited for multi-cluster or multi-environment setups. Managing application dependencies _and_ multi-environment sequencing simultaneously requires a more advanced pattern.
This guide shows how to combine two ApplicationSet features in a single resource:
-
A Matrix Generator generates Argo CD Applications for each environment (dev and staging) and attaches labels that identify the application name and environment.
-
A RollingSync strategy (from Progressive Syncs) reads those labels to enforce the deployment order:
dev-app1→dev-app2→staging-app1→staging-app2.
Progressive Syncs
Progressive Syncs controls the creation and update order of Argo CD Applications based on their dependencies and health status. Define a steps list; the ApplicationSet controller monitors each Application's health and moves to the next step only after all Applications in the current step reach Healthy status.
Supported resources
Progressive Syncs watches for the Progressing state reported by an Argo CD Application during a pod rollout. DaemonSet, StatefulSet, and Argo Rollouts are supported. Any resource type that has a health check and can report a Progressing state also works.
Progressive Syncs requires high availability mode. Enable this mode before proceeding.
RollingSync matching behavior
Before writing the ApplicationSet YAML, review how rollingSync.steps works:
-
Applications are grouped using labels and
matchExpressions. -
All
matchExpressionsin a step must be true for an Application to be selected (AND logic). -
The
InandNotInoperators match if at least one value is true (OR logic within a single expression). -
All Applications in a step must become
Healthybefore the controller moves to the next step.
Example application structure
This guide uses this example repository, which contains two applications, app1 and app2. app2 depends on app1, and both must be deployed to dev and staging. Both applications are managed by Kustomize, and each environment can contain multiple regions (this example uses only the bj region).
manifests
└── apps
├── env
│ ├── dev
│ │ └── config.json
│ └── staging
│ └── config.json
├── app1
│ ├── base
│ │ ├── deployment.yaml
│ │ ├── kustomization.yaml
│ │ └── service.yaml
│ └── overlay
│ ├── dev
│ │ └── bj
│ │ ├── deployment.yaml
│ │ └── kustomization.yaml
│ └── staging
│ └── bj
│ ├── deployment.yaml
│ └── kustomization.yaml
└── app2
├── base
│ ├── deployment.yaml
│ ├── kustomization.yaml
│ └── service.yaml
└── overlay
├── dev
│ └── bj
│ ├── deployment.yaml
│ └── kustomization.yaml
└── staging
└── bj
├── deployment.yaml
└── kustomization.yaml
-
manifests/apps/env: Per-environment configuration. Theconfig.jsonfile in each directory sets thecluster_addressmapping used to route Applications to the correct cluster. -
manifests/apps/app1andmanifests/apps/app2: Application manifests, each with abasedirectory and environment-specific overlays.
To use this example, fork the repository to your own account and update the cluster_address in each config.json to your associated cluster's API Server endpoint.
Prerequisites
Before you begin, ensure that you have:
Step 1: Enable Progressive Syncs
Progressive Syncs is disabled by default. Enable it by adding a key to the argocd-cmd-params-cm ConfigMap and restarting the controller.
-
Edit the ConfigMap using the Fleet kubeconfig.
kubectl edit cm -n argocd argocd-cmd-params-cmAdd the following key under
data:apiVersion: v1 data: applicationsetcontroller.enable.progressive.syncs: "true" ... kind: ConfigMap metadata: name: argocd-cmd-params-cm namespace: argocd ... -
Restart the
argocd-application-controllerto apply the change.kubectl rollout restart deployment argocd-application-controller -n argocd
Step 2: Create the ApplicationSet
-
Log in to the ACK One console. In the left navigation pane, choose Fleet > Multi-cluster GitOps.
-
Click Create Multi-cluster Application > GitOps. On the Create Multi-cluster Application - GitOps page, click Create from YAML and apply the following YAML.
When
pathParamPrefixis set, all variables from that generator must use the prefix. For example,{{.path.basename}}becomes{{.env.path.basename}}when the prefix isenv.Parameter Description Example values {{.env.path.basename}}Base name of the environment directory dev,staging{{.target.path.path}}Full path to the app overlay directory manifests/apps/app2/overlay/dev/bj{{index .target.path.segments 2}}App name extracted from path segments app1,app2apiVersion: argoproj.io/v1alpha1 kind: ApplicationSet metadata: name: dependency-apps namespace: argocd spec: goTemplate: true goTemplateOptions: ["missingkey=error"] generators: - matrix: generators: - git: repoURL: https://github.com/AliyunContainerService/gitops-demo.git revision: main pathParamPrefix: env files: - path: "manifests/apps/env/*/config.json" - git: repoURL: https://github.com/AliyunContainerService/gitops-demo.git revision: main pathParamPrefix: target directories: - path: "manifests/apps/app1/overlay/{{.env.path.basename}}/*" - matrix: generators: - git: repoURL: https://github.com/AliyunContainerService/gitops-demo.git revision: HEAD pathParamPrefix: env files: - path: "manifests/apps/env/*/config.json" - git: repoURL: https://github.com/AliyunContainerService/gitops-demo.git revision: HEAD pathParamPrefix: target directories: - path: "manifests/apps/app2/overlay/{{.env.path.basename}}/*" strategy: type: RollingSync rollingSync: steps: - matchExpressions: - key: app.kubernetes.io/instance operator: In values: - app1 - key: environment operator: In values: - dev - matchExpressions: - key: app.kubernetes.io/instance operator: In values: - app2 - key: environment operator: In values: - dev - matchExpressions: - key: app.kubernetes.io/instance operator: In values: - app1 - key: environment operator: In values: - staging - matchExpressions: - key: app.kubernetes.io/instance operator: In values: - app2 - key: environment operator: In values: - staging template: metadata: name: '{{.env.path.basename}}-{{index .target.path.segments 2}}-{{.target.path.basename}}' labels: app.kubernetes.io/instance: '{{index .target.path.segments 2}}' environment: '{{.env.path.basename}}' spec: project: default source: repoURL: https://github.com/AliyunContainerService/gitops-demo.git targetRevision: HEAD path: '{{.target.path.path}}' destination: server: '{{index .cluster_address .target.path.basename}}' namespace: demo syncPolicy: automated: prune: true selfHeal: true retry: limit: 5 backoff: duration: 5s maxDuration: 3m0s factor: 2 syncOptions: - CreateNamespace=trueThis ApplicationSet uses a Matrix Generator to generate four Argo CD Applications (two for
app1, two forapp2) and aRollingSyncstrategy from Progressive Syncs to enforce the deployment order. How the Matrix Generator works Each matrix block combines two Git generators: one that readsconfig.jsonfiles to discover environments, and one that scans overlay directories to discover app variants. ThepathParamPrefixparameter namespaces the variables from each generator to avoid conflicts. Why labels must be explicit TherollingSync.stepsmatcher reads labels on the generated Argo CD Application resources. Labels are not set automatically — they must be defined in.spec.template.metadata.labels. If a label is missing, the step matcher cannot select the Application, and the deployment will not proceed.
Keep production and non-production (development, testing, and staging) environments in separate ApplicationSet resources. This limits the blast radius of any misconfiguration and lets you enforce an explicit promotion gate for production by using manual sync.
Step 3: Verify the deployment order
The ApplicationSet generates four Application instances. Each starts only after the previous one finishes syncing and reaches Healthy status, following the order dev-app1 → dev-app2 → staging-app1 → staging-app2.
Console
-
Log in to the ACK One console. In the left navigation pane, choose Fleet > Multi-cluster GitOps.
-
Find the target multi-cluster application and click its name to see the Application instances. The applications deploy in sequence. After each step completes, the next application starts syncing.
-
Deploy
dev-app1.
-
Deploy
dev-app2.
-
Deploy
staging-app1.
-
Deploy
staging-app2.

-
CLI
Run the following command with the Fleet kubeconfig to check Application status.
kubectl -n argocd get app
The table below shows the expected status at each deployment stage. Each Application moves from OutOfSync / Missing to Synced / Progressing while deploying, and then to Synced / Healthy when complete.
| Application | Stage 1: dev-app1 deploying | Stage 2: dev-app2 deploying | Stage 3: staging-app1 deploying | Stage 4: staging-app2 deploying |
|---|---|---|---|---|
dev-app1-bj |
Synced / Progressing | Synced / Healthy | Synced / Healthy | Synced / Healthy |
dev-app2-bj |
OutOfSync / Missing | Synced / Progressing | Synced / Healthy | Synced / Healthy |
staging-app1-bj |
OutOfSync / Missing | OutOfSync / Missing | Synced / Progressing | Synced / Healthy |
staging-app2-bj |
OutOfSync / Missing | OutOfSync / Missing | OutOfSync / Missing | Synced / Progressing |