Skip to main content
Flux and ArgoCD solve the same problem — continuous GitOps reconciliation from a git repository to a Kubernetes cluster — with different architectures and different operator communities. Flux uses a Kustomization CRD from the kustomize.toolkit.fluxcd.io/v1 API; ArgoCD uses an Application CRD from argoproj.io/v1alpha1. In ubx, the difference is just the type label on the sync block: sync "flux" instead of sync "argocd". The attribute shapes are identical — repo, path, target, namespace, values — because ubx’s sync abstraction treats both controllers as implementations of the same interface. Switch your GitOps controller, change one word in your .iac file.

What you’ll learn

  • How sync "flux" emits a Flux Kustomization CRD
  • How sync "flux" and sync "argocd" share the same attribute shape
  • When to choose Flux vs ArgoCD (and why ubx makes the switch trivial)

Why this matters

ubx’s sync abstraction is controller-agnostic. A team that starts with ArgoCD and later migrates to Flux changes one word in each sync block. The infrastructure provisioning, the Pending type wiring, the sequencing — nothing else changes.

The source code

# sync "flux" emits a kustomize.toolkit.fluxcd.io/v1 Kustomization CRD.
# Attributes are identical to sync "argocd" — only the type label differs.
sync "flux" "platform" {
  repo      = "https://github.com/myorg/platform"
  path      = "./clusters/${input.env}"
  namespace = "flux-system"
}

How it works

1

sync 'flux' emits a Flux Kustomization CRD

The type label "flux" tells ubx to generate a kustomize.toolkit.fluxcd.io/v1/Kustomization object instead of an ArgoCD Application. The repo, path, and namespace attributes map to the corresponding Flux Kustomization spec fields.
2

The attribute model is identical to sync 'argocd'

Both sync types use the same repo, path, target, namespace, and values attributes — ubx normalises the differences between the two CRD schemas. The values map compiles to Flux’s spec.postBuild.substitute substitution variables rather than ArgoCD’s Helm parameters.
3

Pending values sequence the CRD exactly as with ArgoCD

If any value in values is Pending<T>, the Kustomization CRD creation is sequenced after the pending dependency — identical behaviour to sync "argocd". The Pending type system is controller-agnostic.

sync “argocd” vs sync “flux” — side by side

# ArgoCD
sync "argocd" "platform" {
  repo      = "https://github.com/myorg/platform"
  path      = "./clusters/prod"
  target    = "https://kubernetes.default.svc"
  namespace = "argocd"
}

# Flux — one word changes
sync "flux" "platform" {
  repo      = "https://github.com/myorg/platform"
  path      = "./clusters/prod"
  namespace = "flux-system"
}
The target attribute is optional for Flux (defaults to the in-cluster endpoint). Otherwise the blocks are identical.

What ubx generates

// Generated by ubx — do not edit
import * as pulumi from "@pulumi/pulumi";
import * as k8s from "@pulumi/kubernetes";

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

const platform = new k8s.apiextensions.CustomResource("platform", {
    apiVersion: "kustomize.toolkit.fluxcd.io/v1",
    kind: "Kustomization",
    metadata: { name: "platform", namespace: "flux-system" },
    spec: {
        interval: "10m",
        sourceRef: {
            kind: "GitRepository",
            name: "platform",
        },
        path: `./clusters/${env}`,
        prune: true,
    },
});

Common mistakes

sync "flux" requires Flux to be installed in the cluster and a GitRepository source object to already exist with the same name as the Kustomization. The repo attribute in ubx’s sync block is a convenience — Flux actually reads from its GitRepository CRD, not directly from the URL. Ensure your Flux bootstrap has created the GitRepository source before applying this sync block.
The path attribute supports string interpolation — "./clusters/${input.env}" is valid and useful for environment-specific manifest paths. This is one of the few places in ubx where an interpolated string goes directly into a CRD field rather than a resource attribute.

Run it

ubx validate   # type-checks the sync block
ubx plan       # requires Kubernetes credentials with Flux installed
ubx apply      # creates the Flux Kustomization CRD

What you learned

sync "flux" emits a kustomize.toolkit.fluxcd.io/v1/Kustomization CRD
The attribute shape is identical to sync "argocd" — switching controllers is a one-word change
Flux requires a GitRepository source object to exist before the Kustomization can reconcile

Next steps

exec block

Run a command at apply time as part of the resource graph

sync block reference

Full sync block syntax for both ArgoCD and Flux