---
title: "ArgoCD Image Updater: Automatic Image Tag Updates Without Git Commits"
description: "Using ArgoCD Image Updater to automatically detect new container image versions and update running applications, including tag strategies, registry authentication, write-back methods, and filtering patterns."
url: https://agent-zone.ai/knowledge/cicd/argocd-image-updater/
section: knowledge
date: 2026-02-22
categories: ["cicd"]
tags: ["argocd","gitops","image-updater","container-registry","continuous-delivery","automation"]
skills: ["argocd-image-updater","container-image-management","deployment-automation"]
tools: ["argocd","argocd-image-updater","docker","kubectl","helm"]
levels: ["intermediate"]
word_count: 1113
formats:
  json: https://agent-zone.ai/knowledge/cicd/argocd-image-updater/index.json
  html: https://agent-zone.ai/knowledge/cicd/argocd-image-updater/?format=html
  api: https://api.agent-zone.ai/api/v1/knowledge/search?q=ArgoCD+Image+Updater%3A+Automatic+Image+Tag+Updates+Without+Git+Commits
---


# ArgoCD Image Updater

ArgoCD Image Updater watches container registries for new image tags and automatically updates ArgoCD Applications to use them. In a standard GitOps workflow, updating an image tag requires a Git commit that changes the tag in a values file or manifest. Image Updater automates that step.

## The Problem It Solves

Standard GitOps image update flow:

```
CI builds image → pushes myapp:v1.2.3 to registry
    → Developer (or CI) commits "update image tag to v1.2.3" to Git
    → ArgoCD detects Git change
    → ArgoCD syncs new tag to cluster
```

That middle step -- committing the tag update -- is friction. CI pipelines need Git write access, commit messages are noise ("bump image to v1.2.4", "bump image to v1.2.5"), and the delay between image push and deployment depends on how fast the commit pipeline runs.

With Image Updater:

```
CI builds image → pushes myapp:v1.2.3 to registry
    → Image Updater detects new tag in registry
    → Updates ArgoCD Application (or writes back to Git)
    → ArgoCD syncs new tag to cluster
```

## Installation

```bash
helm repo add argo https://argoproj.github.io/argo-helm
helm install argocd-image-updater argo/argocd-image-updater \
  --namespace argocd
```

Or with plain manifests:

```bash
kubectl apply -n argocd -f https://raw.githubusercontent.com/argoproj-labs/argocd-image-updater/stable/manifests/install.yaml
```

Image Updater runs as a separate Deployment in the ArgoCD namespace. It talks to the ArgoCD API server to read and update Application resources.

## Configuring an Application for Image Updates

Image Updater is configured entirely through annotations on ArgoCD Application resources. No changes to the Application spec itself are needed.

### Basic Example

```yaml
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: my-app
  namespace: argocd
  annotations:
    argocd-image-updater.argoproj.io/image-list: myapp=myorg/my-app
    argocd-image-updater.argoproj.io/myapp.update-strategy: semver
spec:
  source:
    repoURL: https://github.com/myorg/gitops-config.git
    targetRevision: main
    path: apps/my-app
    helm:
      parameters:
        - name: image.tag
          value: "1.0.0"
  # ... rest of spec
```

The `image-list` annotation maps an alias (`myapp`) to a container image (`myorg/my-app`). The update strategy (`semver`) tells Image Updater how to pick the latest tag.

### Annotation Reference

| Annotation | Purpose | Example |
|---|---|---|
| `image-list` | Images to track (alias=image) | `myapp=myorg/my-app` |
| `<alias>.update-strategy` | How to select new tags | `semver`, `latest`, `digest`, `name` |
| `<alias>.allow-tags` | Regex filter for allowed tags | `regexp:^v[0-9]+\.[0-9]+\.[0-9]+$` |
| `<alias>.ignore-tags` | Regex filter for ignored tags | `regexp:.*-rc.*` |
| `<alias>.helm.image-name` | Helm parameter for image name | `image.repository` |
| `<alias>.helm.image-tag` | Helm parameter for image tag | `image.tag` |
| `<alias>.helm.image-spec` | Helm parameter for full image spec | `image.name` (for `repo:tag` format) |
| `<alias>.platforms` | Filter by platform/arch | `linux/amd64,linux/arm64` |

## Update Strategies

### semver

Selects the highest tag that matches semantic versioning. This is the most common strategy for production.

```yaml
annotations:
  argocd-image-updater.argoproj.io/image-list: myapp=myorg/my-app
  argocd-image-updater.argoproj.io/myapp.update-strategy: semver
  argocd-image-updater.argoproj.io/myapp.allow-tags: "regexp:^[0-9]+\\.[0-9]+\\.[0-9]+$"
```

With tags `1.0.0`, `1.1.0`, `1.2.0-rc1`, `1.2.0`, and `2.0.0` in the registry, and the allow-tags filter excluding prerelease suffixes, Image Updater selects `2.0.0`.

Constrain to a major or minor version:

```yaml
annotations:
  argocd-image-updater.argoproj.io/myapp.update-strategy: semver
  argocd-image-updater.argoproj.io/myapp.allow-tags: "regexp:^1\\.2\\.[0-9]+$"
```

This only updates within the `1.2.x` range.

### latest

Selects the most recently pushed tag, regardless of tag name. Useful for development environments tracking a `main` branch:

```yaml
annotations:
  argocd-image-updater.argoproj.io/myapp.update-strategy: latest
  argocd-image-updater.argoproj.io/myapp.allow-tags: "regexp:^main-[a-f0-9]{7}$"
```

This picks the most recently pushed tag matching `main-<short-sha>`.

### digest

Tracks a mutable tag (like `latest` or `main`) by its digest. When the digest changes, Image Updater updates the Application:

```yaml
annotations:
  argocd-image-updater.argoproj.io/image-list: myapp=myorg/my-app:main
  argocd-image-updater.argoproj.io/myapp.update-strategy: digest
```

The Application image reference changes from `myorg/my-app:main` to `myorg/my-app@sha256:abc123...`, pinning to the exact image content.

### name

Selects the tag with the highest lexicographic sort. Useful for date-based tags like `20260222` or `build-1234`:

```yaml
annotations:
  argocd-image-updater.argoproj.io/myapp.update-strategy: name
  argocd-image-updater.argoproj.io/myapp.allow-tags: "regexp:^[0-9]{8}$"
```

## Registry Authentication

Image Updater needs read access to the container registry to list tags and check digests.

### Docker Hub

```bash
kubectl -n argocd create secret docker-registry dockerhub-creds \
  --docker-server=https://index.docker.io/v1/ \
  --docker-username=myuser \
  --docker-password=mytoken
```

```yaml
annotations:
  argocd-image-updater.argoproj.io/myapp.pull-secret: pullsecret:argocd/dockerhub-creds
```

### Amazon ECR

ECR tokens expire every 12 hours. Use the ECR credential helper or a CronJob that refreshes the token:

```yaml
# Image Updater config in argocd-image-updater-config ConfigMap
data:
  registries.conf: |
    registries:
      - name: ECR
        prefix: 123456789012.dkr.ecr.us-east-1.amazonaws.com
        api_url: https://123456789012.dkr.ecr.us-east-1.amazonaws.com
        credentials: ext:/scripts/ecr-login.sh
        credsexpire: 10h
```

Or use IRSA (IAM Roles for Service Accounts) to give the Image Updater pod ECR access directly.

### GitHub Container Registry (ghcr.io)

```bash
kubectl -n argocd create secret docker-registry ghcr-creds \
  --docker-server=ghcr.io \
  --docker-username=myuser \
  --docker-password=ghp_xxxxxxxxxxxx
```

## Write-Back Methods

When Image Updater finds a new image, it needs to update something. There are two approaches.

### ArgoCD API (Default)

Image Updater overrides the image parameter directly on the ArgoCD Application resource using parameter overrides. No Git commit is created. The Application shows the updated image in ArgoCD but Git still has the old tag.

```yaml
annotations:
  argocd-image-updater.argoproj.io/write-back-method: argocd
```

Pros: Instant, no Git noise. Cons: Git is no longer the single source of truth for the running image tag. If the Application is re-synced from Git, the tag reverts.

### Git Write-Back

Image Updater commits the updated tag to Git. ArgoCD then syncs the Git change like any other commit.

```yaml
annotations:
  argocd-image-updater.argoproj.io/write-back-method: git
  argocd-image-updater.argoproj.io/write-back-target: helmvalues:values.yaml
  argocd-image-updater.argoproj.io/git-branch: main
```

For Kustomize applications:

```yaml
annotations:
  argocd-image-updater.argoproj.io/write-back-method: git
  argocd-image-updater.argoproj.io/write-back-target: kustomization
```

Image Updater needs Git write access. Configure credentials:

```yaml
annotations:
  argocd-image-updater.argoproj.io/write-back-method: git:secret:argocd/git-creds
```

Where `git-creds` is a Secret containing the Git credentials.

Git write-back maintains the GitOps principle of Git as the single source of truth. The tradeoff is commit noise and a slight delay while the Git commit propagates.

### Write-Back to a Different Branch

Write image updates to a separate branch to keep the main branch clean of automated commits:

```yaml
annotations:
  argocd-image-updater.argoproj.io/write-back-method: git
  argocd-image-updater.argoproj.io/git-branch: image-updates
```

The Application's `targetRevision` must point to the `image-updates` branch for the changes to take effect.

## Multiple Images

Track multiple container images in a single Application:

```yaml
annotations:
  argocd-image-updater.argoproj.io/image-list: frontend=myorg/frontend, backend=myorg/backend, worker=myorg/worker
  argocd-image-updater.argoproj.io/frontend.update-strategy: semver
  argocd-image-updater.argoproj.io/frontend.helm.image-tag: frontend.image.tag
  argocd-image-updater.argoproj.io/backend.update-strategy: semver
  argocd-image-updater.argoproj.io/backend.helm.image-tag: backend.image.tag
  argocd-image-updater.argoproj.io/worker.update-strategy: latest
  argocd-image-updater.argoproj.io/worker.helm.image-tag: worker.image.tag
  argocd-image-updater.argoproj.io/worker.allow-tags: "regexp:^main-[a-f0-9]{7}$"
```

Each image can have its own update strategy, tag filters, and Helm parameter mapping.

## Checking Image Updater Status

```bash
# View Image Updater logs
kubectl logs -n argocd -l app.kubernetes.io/name=argocd-image-updater --tail=100

# Check which images are being tracked
kubectl get applications -n argocd -o json | jq '.items[] | select(.metadata.annotations["argocd-image-updater.argoproj.io/image-list"] != null) | {name: .metadata.name, images: .metadata.annotations["argocd-image-updater.argoproj.io/image-list"]}'

# Force an immediate check
kubectl rollout restart deployment/argocd-image-updater -n argocd
```

The default check interval is 2 minutes. Configure it in the Image Updater deployment:

```yaml
env:
  - name: IMAGE_UPDATER_INTERVAL
    value: "5m"
```

## Common Mistakes

1. **Using the `argocd` write-back method in production.** If the Application is ever hard-refreshed or recreated from Git, the image tag reverts to whatever is in Git. Use `git` write-back for production to keep Git as the source of truth.
2. **Not filtering tags with `allow-tags`.** Without filters, Image Updater considers every tag in the registry, including test builds, debug images, and broken releases. Always restrict to a known tag format.
3. **Forgetting that ECR tokens expire.** Static Docker credentials work for Docker Hub and ghcr.io. ECR requires a credential refresh mechanism. Image pulls silently fail after 12 hours without rotation.
4. **Setting the check interval too low for large registries.** Listing tags on a registry with thousands of images every 30 seconds generates significant registry API traffic. Start at 2-5 minutes.
5. **Not accounting for multi-arch images.** If you build for both amd64 and arm64, ensure the tag exists for all required platforms before Image Updater picks it up. Use the `platforms` annotation to filter.

