> ## Documentation Index
> Fetch the complete documentation index at: https://docs.ubiquex.io/llms.txt
> Use this file to discover all available pages before exploring further.

# sync ArgoCD Application

> Register a GitOps application with ArgoCD, wiring infrastructure outputs into app config.

ArgoCD is the dominant GitOps controller for Kubernetes — it watches a git repository, compares desired state to live cluster state, and reconciles the difference automatically. But to register an application with ArgoCD, you create an `Application` CRD in the cluster. That CRD needs to know where the application's manifests live (the git repo and path), where to deploy them (the cluster endpoint), and any runtime configuration (image tags, connection strings, environment variables) that differs per deployment. These runtime values — like an ECR repository URL — are infrastructure outputs that only exist after cloud resources are provisioned. The `sync "argocd"` block handles exactly this: it emits an ArgoCD `Application` CRD, accepts a `values` map for per-deployment config, and sequences the CRD creation after any pending infrastructure outputs it references.

## What you'll learn

* The `sync "argocd"` block syntax — repo, path, target, namespace, values
* How pending infrastructure outputs (like an ECR URL) wire into ArgoCD app config
* How `sync "argocd"` differs from `deploy "helm"` — GitOps pull vs Helm push

***

## Why this matters

<Info>
  `deploy "helm"` pushes a Helm release directly to the cluster. `sync "argocd"` tells ArgoCD where to find the manifests and what runtime values to inject — ArgoCD then pulls and reconciles continuously. Use `deploy` for imperative releases; use `sync` for GitOps-managed continuous reconciliation.
</Info>

***

## The source code

<CodeGroup>
  ```hcl main.iac theme={"theme":"css-variables"}
  # ECR repository — repositoryUrl is Pending<string>.
  unit "aws_ecr_repository" "app" {
    name = "myapp-backend"
  }

  # sync "argocd" emits an argoproj.io/v1alpha1 Application CRD.
  # The image_tag value is Pending<string> — wired from the ECR repository URL.
  # ubx sequences the Application CRD creation after the ECR repo exists.
  sync "argocd" "backend" {
    repo      = "https://github.com/myorg/app"
    path      = "k8s"
    target    = "https://kubernetes.default.svc"
    namespace = "argocd"
    values = {
      image_tag = unit.aws_ecr_repository.app.repositoryUrl  # Pending<string>
      env       = input.env                                    # Resolved<string>
      replicas  = 2                                            # Resolved<int>
    }
  }
  ```

  ```hcl inputs.iac theme={"theme":"css-variables"}
  input "env" {
    type    = "string"
    default = "dev"
  }
  ```

  ```hcl outputs.iac theme={"theme":"css-variables"}
  output "ecr_url" {
    value = unit.aws_ecr_repository.app.repositoryUrl
  }
  ```

  ```hcl ubx.iac theme={"theme":"css-variables"}
  ubx {
    name    = "sync-argocd-application"
    runtime = "typescript"
    stacks  = ["dev", "staging", "prod"]
  }

  backend "s3" {
    bucket = "my-ubx-state"
    region = "us-east-1"
    key    = "${stack}/sync-argocd.tfstate"
  }
  ```
</CodeGroup>

***

## How it works

<Steps>
  <Step title="sync emits an ArgoCD Application CRD">
    `sync "argocd"` compiles to a Pulumi `kubernetes.apiextensions.CustomResource` call that creates an `argoproj.io/v1alpha1/Application` object in the cluster. The `repo`, `path`, `target`, and `namespace` attributes map directly to ArgoCD Application spec fields.
  </Step>

  <Step title="values are passed as Helm parameters to ArgoCD">
    The `values` map compiles to ArgoCD's `spec.source.helm.parameters` array — key/value pairs that ArgoCD injects into the Helm chart when it renders manifests. Each entry becomes a `{ name, value }` parameter in the Application spec.
  </Step>

  <Step title="Pending values sequence the CRD after infrastructure">
    `unit.aws_ecr_repository.app.repositoryUrl` is `Pending<string>` — the Application CRD can't be created until the ECR repository exists and has a URL. ubx generates `.apply()` wrapping to sequence the CRD creation after the ECR resource.
  </Step>
</Steps>

***

## What ubx generates

<CodeGroup>
  ```typescript index.ts theme={"theme":"css-variables"}
  // Generated by ubx — do not edit
  import * as pulumi from "@pulumi/pulumi";
  import * as aws from "@pulumi/aws";
  import * as k8s from "@pulumi/kubernetes";

  const config = new pulumi.Config();
  const env = config.get("env") || "dev";

  const app = new aws.ecr.Repository("app", { name: "myapp-backend" });

  // Sequenced after app.repositoryUrl resolves
  const backend = app.repositoryUrl.apply(repoUrl =>
      new k8s.apiextensions.CustomResource("backend", {
          apiVersion: "argoproj.io/v1alpha1",
          kind: "Application",
          metadata: { name: "backend", namespace: "argocd" },
          spec: {
              source: {
                  repoURL: "https://github.com/myorg/app",
                  path: "k8s",
                  helm: {
                      parameters: [
                          { name: "image_tag", value: repoUrl },
                          { name: "env",       value: env },
                          { name: "replicas",  value: "2" },
                      ],
                  },
              },
              destination: { server: "https://kubernetes.default.svc" },
              syncPolicy: { automated: { prune: true, selfHeal: true } },
          },
      })
  );

  export const ecrUrl = app.repositoryUrl;
  ```

  ```python __main__.py theme={"theme":"css-variables"}
  # Generated by ubx — do not edit
  import pulumi
  import pulumi_aws as aws
  import pulumi_kubernetes as k8s

  config = pulumi.Config()
  env = config.get("env") or "dev"

  app = aws.ecr.Repository("app", name="myapp-backend")

  backend = app.repository_url.apply(lambda repo_url:
      k8s.apiextensions.CustomResource("backend",
          api_version="argoproj.io/v1alpha1", kind="Application",
          metadata={"name": "backend", "namespace": "argocd"},
          spec={
              "source": {
                  "repoURL": "https://github.com/myorg/app", "path": "k8s",
                  "helm": {"parameters": [
                      {"name": "image_tag", "value": repo_url},
                      {"name": "env",       "value": env},
                      {"name": "replicas",  "value": "2"},
                  ]},
              },
              "destination": {"server": "https://kubernetes.default.svc"},
              "syncPolicy": {"automated": {"prune": True, "selfHeal": True}},
          },
      )
  )

  pulumi.export("ecr_url", app.repository_url)
  ```

  ```go main.go theme={"theme":"css-variables"}
  // Generated by ubx — do not edit
  package main

  import (
      "github.com/pulumi/pulumi-aws/sdk/v6/go/aws/ecr"
      "github.com/pulumi/pulumi-kubernetes/sdk/v4/go/kubernetes/apiextensions"
      "github.com/pulumi/pulumi/sdk/v3/go/pulumi"
      "github.com/pulumi/pulumi/sdk/v3/go/pulumi/config"
  )

  func main() {
      pulumi.Run(func(ctx *pulumi.Context) error {
          cfg := config.New(ctx, "")
          env := cfg.Get("env")
          if env == "" { env = "dev" }

          app, err := ecr.NewRepository(ctx, "app", &ecr.RepositoryArgs{Name: pulumi.String("myapp-backend")})
          if err != nil { return err }

          _ = app.RepositoryUrl.ApplyT(func(repoUrl string) (*apiextensions.CustomResource, error) {
              return apiextensions.NewCustomResource(ctx, "backend", &apiextensions.CustomResourceArgs{
                  ApiVersion: pulumi.String("argoproj.io/v1alpha1"),
                  Kind:       pulumi.String("Application"),
                  Metadata:   pulumi.Map{"name": pulumi.String("backend"), "namespace": pulumi.String("argocd")},
                  OtherFields: pulumi.Map{
                      "spec": pulumi.Map{
                          "source": pulumi.Map{
                              "repoURL": pulumi.String("https://github.com/myorg/app"),
                              "path":    pulumi.String("k8s"),
                              "helm":    pulumi.Map{"parameters": pulumi.MapArray{
                                  pulumi.Map{"name": pulumi.String("image_tag"), "value": pulumi.String(repoUrl)},
                                  pulumi.Map{"name": pulumi.String("env"),       "value": pulumi.String(env)},
                              }},
                          },
                          "destination": pulumi.Map{"server": pulumi.String("https://kubernetes.default.svc")},
                      },
                  },
              })
          })

          ctx.Export("ecrUrl", app.RepositoryUrl)
          return nil
      })
  }
  ```
</CodeGroup>

***

## Common mistakes

<Warning>
  `sync "argocd"` requires the ArgoCD CRD (`Application`) to already be installed in the cluster before `ubx apply` runs. If ArgoCD is not installed, the apply will fail with a CRD-not-found error. Install ArgoCD first (e.g. via a `deploy "helm"` block for the ArgoCD chart itself) and ensure it's a dependency of this sync block.
</Warning>

<Tip>
  ArgoCD Application `values` are passed as Helm parameters — key/value pairs injected at render time. They override values in the chart's `values.yaml`. Make sure the keys match the parameter names your Helm chart expects, not arbitrary strings.
</Tip>

***

## Run it

```bash theme={"theme":"css-variables"}
ubx validate   # type-checks Pending<T> references
ubx plan       # requires AWS + Kubernetes credentials with ArgoCD installed
ubx apply      # creates ECR repo, then registers ArgoCD Application
```

***

## What you learned

<Check>`sync "argocd"` emits an ArgoCD `Application` CRD with repo, path, target, and Helm parameters</Check>
<Check>Pending infrastructure outputs wire into ArgoCD `values` with the same bare reference syntax as `deploy "helm"`</Check>
<Check>ArgoCD must be installed in the cluster before the Application CRD can be created</Check>

***

## Next steps

<CardGroup cols={2}>
  <Card title="sync Flux kustomization" href="/v1/tutorials/27-sync-flux-kustomization">
    GitOps with Flux instead of ArgoCD
  </Card>

  <Card title="sync block reference" href="/v1/language/sync">
    Full sync block syntax for both ArgoCD and Flux
  </Card>
</CardGroup>

***

<Info>
  Full runnable example: [github.com/ubiquex/ubx-examples/26-sync-argocd-application](https://github.com/ubiquex/ubx-examples/tree/main/26-sync-argocd-application)
</Info>
