Terraform Scheduled Scaling Alternative: ZopNight Compared
Terraform does not run schedules. It declares them, and each cloud's own scheduler does the timed work. That split is the key to this comparison.
What Terraform actually does here
Terraform’s workflow is plan and apply. Terraform “creates an execution plan”, and “on approval, Terraform performs the proposed operations” (Terraform intro). It acts when you run it. So “scheduled scaling with Terraform” means using Terraform to create a provider’s own scheduling resource, which then fires on the cloud side. The three common ones, from each provider’s registry documentation:
- AWS,
aws_autoscaling_schedule. Sets an Auto Scaling group’s min, max and desired capacity on arecurrence, “the recurring schedule … using the Unix cron syntax”, with an optionaltime_zone(AWS provider docs). - Azure,
azurerm_monitor_autoscale_setting. Profiles take either arecurrence(days, hours, a timezone defaulting to UTC) or afixed_date, and therecurrence“cannot be specified if afixed_dateblock is specified” (AzureRM provider docs). - GCP,
google_compute_resource_policy. Aninstance_schedule_policyblock withvm_start_schedule,vm_stop_scheduleandtime_zone(Google provider docs). It inherits Compute Engine’s instance-schedule limits, covered on our GCP instance schedules page.
The approach has a lot going for it. Schedules are reviewed in pull requests, versioned in Git, and applied with the rest of your infrastructure.
Where the approach strains
The limits follow from the split above.
- You get only the schedulers the provider offers. The AWS resource scales Auto Scaling groups, and the Azure resource scales through autoscale settings. None of these three stops a standalone database such as RDS or Cloud SQL. Where a provider has no native schedule for a resource type, Terraform has nothing to declare.
- Every exception is a code change. Keeping staging up for Thursday’s demo means editing the schedule, merging, and remembering to change it back.
- Timezones and syntax differ per cloud. You write cron for AWS, day-and-hour profiles for Azure, and start/stop schedules for GCP, each with its own defaults.
How ZopNight fits alongside Terraform
ZopNight does not replace Terraform. Keep Terraform for creating infrastructure, and let ZopNight own the runtime on and off decisions:
- One schedule format (cron plus an IANA timezone) across AWS, GCP and Azure, covering VMs, RDS, Cloud SQL, AKS, EKS, GKE, namespaces and more.
- Overrides for one-off exceptions that carry a reason and expire, with no pull request needed.
- Autoscaler policies for ASG, ECS, VMSS and MIG, with time-based presets such as Business Hours and Weekend Scale-Down. Before replacing a policy already in the cloud, ZopNight asks you to adopt it or replace it, and Remove restores the previous configuration.
- IaC governance on your Terraform and OpenTofu plans, with priced-plan guardrails in the pull request. It never runs
apply. See infrastructure as code.
To keep Terraform and ZopNight from fighting, have Terraform ignore the fields that ZopNight changes at runtime, such as desired capacity.
| ZopNight | Terraform scheduling resources | |
|---|---|---|
| Who fires the schedule | ZopNight scheduler | Each cloud’s native scheduler, created at apply |
| Exception handling | Expiring overrides with reasons | Edit, merge and re-apply |
| Schedule syntax | Cron plus IANA timezone everywhere | Differs per provider resource |
| Review in pull requests | Plan governance for IaC changes | Native: schedules live in code |
Questions we get a lot.
If yours isn't here, email us and we'll answer directly.
Does Terraform have its own scheduler?
Terraform acts when you run plan and apply. For timed actions it creates a provider's scheduling resource, such as aws_autoscaling_schedule, and the cloud provider fires it.
Does ZopNight replace Terraform?
No. Terraform keeps creating and changing infrastructure. ZopNight handles the runtime start, stop and scaling decisions and can gate Terraform and OpenTofu plans with policy, but it never runs apply.
Will ZopNight's changes show up as Terraform drift?
They can, for fields such as Auto Scaling desired capacity. Tell Terraform to ignore those fields, for example with a lifecycle ignore_changes block, so the next apply does not undo a scheduled change.