# Schedule Recurring Deployments

Source: https://docs.ops0.com/docs/how-to/schedule-deployments

Deploy Terraform changes automatically on a schedule — whether that's a one-off maintenance window or a nightly recurring apply.

---

## Scenario

Your team applies Terraform changes to production during a nightly maintenance window (2–4 AM UTC) to avoid business hours impact. You also want to automatically sync a dev environment every morning so developers start with a clean, known-good state.

**Two scheduling modes:**

| Mode | Use Case | Example |
|------|----------|---------|
| **Scheduled (one-off)** | Deploy at a specific future date/time | Production release Tuesday 2 AM UTC |
| **Recurring (cron)** | Deploy on a repeating schedule | Dev environment reset every weekday 6 AM UTC |

---

## Prerequisites

- IaC project with Terraform code ready — [Create an IaC project](https://docs.ops0.com/docs/how-to/first-iac-deployment)

- Cloud integration connected with deploy permissions

- Code pushed to GitHub (recommended for recurring applies — ensures the latest code is always used)

---

## Part 1: Schedule a One-off Deployment (Maintenance Window)

Use a one-off scheduled deployment when you want to queue a specific deployment for a future date and time — for example, a production release during an approved maintenance window.

1. Open your IaC project

2. Click **Deploy**

3. Under **Timing**, select **Scheduled**

4. Set the date and time — **all times are UTC**

5. Confirm the deployment — ops0 queues it and shows status: **Scheduled** with the fire time

### What happens at the scheduled time

1. **Plan runs automatically** — ops0 fetches the latest code and runs Terraform plan

2. If plan passes policy checks → proceeds to apply (or waits for approval if required)

3. If plan fails → apply is skipped, an incident is created, and your team is notified

4. Apply runs and completes — notification sent to configured alert channels

**Cancel before the fire time**

You can cancel a queued scheduled deployment at any point before it fires. Click the deployment card → **Cancel**. After the scheduled time passes, the deployment cannot be cancelled.

---

## Part 2: Set Up a Recurring Deployment

Use a recurring deployment when you want the same deployment to run automatically on a repeating schedule — for example, a nightly dev environment refresh.

1. Open your IaC project

2. Click **Deploy**

3. Under **Timing**, select **Recurring**

4. Enter a cron expression or choose a preset from the dropdown

5. Click **Save** — the project card shows a **Recurring** badge with next run time

### Cron expression presets

| Preset | Expression | When |
|--------|-----------|------|
| Every weekday morning | `0 6 * * 1-5` | Mon–Fri at 6:00 AM UTC |
| Nightly | `0 2 * * *` | Every day at 2:00 AM UTC |
| Weekly (Sunday) | `0 0 * * 0` | Sunday midnight UTC |
| Every 6 hours | `0 */6 * * *` | 00:00, 06:00, 12:00, 18:00 UTC |
| First of month | `0 0 1 * *` | 1st of each month at midnight UTC |

**Cron times are always UTC**

ops0 evaluates all cron expressions in UTC. Convert your local maintenance window time to UTC before saving the schedule.

---

## Part 3: Combine with Approval Gates

If your project has **approval required** enabled, scheduled deployments integrate with the approval flow automatically.

| Step | What happens |
|------|-------------|
| Plan | Runs at the scheduled time as usual |
| Apply | **Waits for approval** — does not auto-apply |
| Approval window | Approver has until the next scheduled run to approve |
| Expiry | If the window closes without approval, the deployment expires and the next run creates a fresh plan |

For recurring applies that should run fully automated with no human gate, you have two options:
- Disable the approval requirement on the project under **Settings → Approvals**
- Use a service account API key to auto-approve via the ops0 API, and trigger it from a CI/CD pipeline

---

## Part 4: Managing Scheduled Deployments

### View and monitor

1. View all scheduled and recurring deployments: **IaC → Deployments** → filter by **Scheduled**

2. Cancel a queued deployment: click the deployment → **Cancel**

3. Disable a recurring schedule: project **Settings → Scheduling** → toggle off

4. View run history: each recurring run creates a separate deployment record in the **Deployments** tab

### Real-world example — Dev environment nightly reset

```
Project:   dev-environment
Schedule:  0 6 * * 1-5  (weekdays 6 AM UTC)
Approval:  Disabled
Branch:    main

Result: Dev environment is refreshed each morning with the latest Terraform
        code from the main branch. Developers arrive to a clean, known-good
        state without manual intervention.
```

---

## Verification

- After saving, the project card shows the **next run time**

- After the first run, the **Deployments** tab shows the run with a timestamp and status

- Notification sent to configured alert channels on completion

---

## Troubleshooting

Scheduled deployment didn't run

Check that the cloud integration credentials haven't expired. Scheduled runs use the same integration as manual deployments — if the IAM role session or service account key has rotated, update it under **Integrations** before the next run.

Recurring deployment keeps failing plan

The code may have a dependency that returns different values between runs (e.g. a `data` source fetching a dynamic value). Check the plan output for the specific error. Consider pinning the data source or switching to a static variable.

Can't find scheduled deployments in history

Filter the Deployments list by date range — scheduled runs appear as normal deployments with a **Scheduled** badge. If you recently enabled the schedule, no history exists until the first run fires.

---

## Next Steps

[Automate deployments → Set up event-driven pipelines triggered by GitHub PRs and webhooks](https://docs.ops0.com/docs/how-to/automate-deployments)
[Approval workflows → Require human sign-off before scheduled deploys reach production](https://docs.ops0.com/docs/how-to/approval-workflows)
[IaC deployments reference → Full reference for deployment options, states, and configuration](https://docs.ops0.com/docs/iac/deployments)
[Set up GitOps → Deploy automatically when Terraform code is merged to main](https://docs.ops0.com/docs/how-to/setup-gitops)
