Control when ArgoCD may sync with Sync Windows: cron-based allow and deny schedules, maintenance windows, change freezes, and manual overrides for emergency deployments.

In episode 13 we mastered Resource Hooks to control what happens during a sync. But there's a more basic question: when is a sync itself allowed to happen? Late at night when all users are active? A release freeze a week before an audit? High-risk maintenance hours? ArgoCD provides an answer called Sync Windows — scheduled time windows that allow or forbid sync operations, both automatic and manual.
Why does this matter? GitOps spoils us with auto-sync, but not every change is safe at every time. Sync Windows is a governance mechanism that moves the "what time to deploy" decision from human memory into deterministic configuration — part of the change management culture we'll dig into in episode 15.
A Sync Window is a rule on the AppProject with three main components:
kind — allow (permit sync) or deny (forbid sync).schedule — when the window is active, in 5-field cron format (minute, hour, day, month, weekday).duration — how long the window lasts after the schedule is reached.A window can be scoped to specific applications, namespaces, and clusters, with wildcard support.
allow window exists → sync is only allowed while that allow window is active.deny window is active → sync is rejected, even if an allow window is also active. deny always wins.apiVersion: argoproj.io/v1alpha1
kind: AppProject
metadata:
name: billing-prod
spec:
syncWindows:
- kind: allow
schedule: "0 9 * * *"
duration: 2h
applications:
- "*-prod"
namespaces:
- billing-prod
clusters:
- in-cluster
manualSync: true
- kind: deny
schedule: "0 22 * * *"
duration: 2h
timeZone: Asia/Jakarta
applications:
- "*-prod"The example above: *-prod applications may auto-sync every day from 09:00–11:00 (and manually anytime, thanks to manualSync: true), but are forbidden from syncing from 22:00–24:00 — a period usually used for maintenance or to minimize late-night release risk.
Note
Windows are project-level: every Application in the project follows the rules. Filtering by applications, namespaces, and clusters is a way to limit scope — not to create per-application windows. There is no native sync window at the Application level.
All window operations are available in the CLI:
argocd proj windows add billing-prod \
--kind deny --schedule "0 22 * * *" --duration 2h \
--applications "*-prod"
argocd proj windows list billing-prod
argocd proj windows delete billing-prod <ID>The argocd proj windows list output shows the ID, STATUS, KIND, SCHEDULE, DURATION, and even MANUALSYNC and SYNCOVERRUN columns — useful for verifying schedules before a big release.
A deny schedule during maintenance hours (e.g. 0 2 * * Sun, 3-hour duration) prevents auto-sync from interfering with database maintenance work. Combined with syncOverrun: true, an already-running sync won't be forcibly cut off mid-way.
An allow pattern only during office hours, e.g. 0 9 * * 1-5 with an 8-hour duration — outside that, applications can't change without explicit approval.
Before a big launch or audit, set a deny for a full week:
- kind: deny
schedule: "0 0 * * *"
duration: 24h
applications:
- "*-prod"
clusters:
- eks-prodAn allow + syncOverrun combination enables a scheduled deployment window — the production team only receives changes within an agreed window, making coordination with on-call easier.
timeZone field (e.g. Asia/Jakarta) sets the base for interpreting the schedule. Without this field, the schedule follows the ArgoCD server's timezone (recommended to be set to UTC).allow and deny windows; all are evaluated together with the rules above.applications and namespaces), they default to OR. Enable useAndOperator: true when all conditions must be satisfied together.When a deny window is active, sync is blocked — including manual. For emergency scenarios, ArgoCD provides an explicit override:
argocd proj windows list billing-prod
argocd proj windows enable-manual-sync billing-prod <ID>
argocd proj windows disable-manual-sync billing-prod <ID>manualSync: true on a window (or enable-manual-sync via the CLI) keeps manual sync allowed even while the deny window is active — ideal for emergency hotfixes, while auto-sync stays locked.
Warning
A manual override is a risky decision usually made for emergency reasons. Restrict who has sync and update permission on the project, and document in a runbook when overrides are allowed — don't let "emergency" become the daily default flow.
deny overrides allow. An allow window does not override an active deny; this wrong expectation often leaves teams puzzled why sync is still blocked.0 22 * * * = 22:00 every day. Test with argocd proj windows list to see the STATUS.timeZone.manualSync active on every window. If the goal is to prevent production changes, don't set manualSync: true — emergency overrides must be explicit and temporary.syncOverrun, a long sync can be forcibly cut when the window ends, leaving a strange state.This episode gave you full control over when changes may happen: the allow/deny concept, cron schedules and durations, per-application/namespace/cluster filtering, use cases for maintenance windows, business hours, change freezes, and scheduled deployments, timezone and multiple window handling, and manual overrides for emergency deployments.
The points you should take with you:
deny always overrides allow when both are active.manualSync: true is an emergency override mechanism — use it wisely.timeZone matters so schedules match the team's working timezone.syncOverrun prevents a running sync from being cut short by a window change.Managing when to deploy is only half of governance; the other half is how changes flow through Git. In the next episode 15 we discuss GitOps Workflow & Branch Strategies: trunk-based vs GitFlow, environment directory structures, branch/tag promotion strategies, and PR-based change management. See you in episode 15!