Terraform provider

Manage cron jobs, heartbeat monitors, and alert rules as infrastructure as code with the official SteadyCron Terraform provider. Export an existing account to HCL in one command.

The SteadyCron Terraform provider lets you manage cron jobs alongside the rest of your infrastructure in HCL — no separate YAML manifests required if you are already running Terraform.

Prerequisites

  • Terraform ≥ 1.5 (required for the import {} block syntax the exporter generates)
  • A SteadyCron API key — create one in Settings → API keys with Full scope

Set the key as an environment variable:

export STEADYCRON_API_KEY=sc_...

Adopting an existing account

If you already have jobs in the SteadyCron dashboard, export your entire account as a ready-to-apply Terraform configuration in one command:

steadycron export --format terraform -o main.tf

The exported file contains:

  • A terraform {} block with the provider pinned to the current version
  • import {} blocks for every existing resource (tags, channels, jobs, alert rules)
  • resource "steadycron_*" "..." blocks with all settings filled in
  • variable "..." { sensitive = true } blocks for secrets (webhook URLs, bot tokens)

Because the file includes import {} blocks, running terraform apply will adopt all existing resources into Terraform state rather than creating duplicates.

Supply sensitive variable values

Secrets are never embedded in the exported file. The exporter declares them as sensitive Terraform variables that you must supply at apply time. Create a terraform.tfvars file (keep it out of git):

# terraform.tfvars  —  do not commit this file
sc_channel_ops_slack_webhook_url = "https://hooks.slack.com/services/..."
sc_channel_pagerduty_secret      = "your-webhook-secret"

Or pass them inline:

terraform apply -var='sc_channel_ops_slack_webhook_url=https://...'

Apply

terraform init
terraform plan    # review what will be imported / changed
terraform apply

On first apply, Terraform imports every existing resource into state. Subsequent terraform plan runs show only drift from your configuration.

Starting from scratch

If you have no existing jobs, write a configuration by hand and apply:

terraform {
  required_providers {
    steadycron = {
      source  = "steadycron/steadycron"
      version = "1.0.4"
    }
  }
}

# api_key from STEADYCRON_API_KEY env var
provider "steadycron" {}

resource "steadycron_alert_channel" "ops_email" {
  name     = "ops-email"
  kind     = "email"
  email_to = "ops@example.com"
}

resource "steadycron_http_job" "weekly_digest" {
  name   = "weekly-digest"
  method = "POST"
  url    = "https://api.example.com/jobs/digest"

  cron_expression = "0 9 * * 1"   # Monday 09:00
  timezone        = "Europe/Berlin"
  timeout_seconds = 120
  max_retries     = 2
}

resource "steadycron_alert_rule" "digest_failure" {
  job_id     = steadycron_http_job.weekly_digest.id
  channel_id = steadycron_alert_channel.ops_email.id
  trigger    = "on_failure"
}
terraform init && terraform apply

Resources

ResourceDescription
steadycron_http_jobScheduled HTTPS call
steadycron_heartbeat_monitorExpected-ping monitor with a unique ping URL
steadycron_alert_channelEmail, Slack, Discord, webhook, or Telegram channel
steadycron_alert_ruleLinks a job to a channel with a trigger condition
steadycron_tagkey=value label for grouping/filtering jobs
steadycron_template_variableNamed placeholder for server-side substitution in job fields

Data sources (data.steadycron_http_job, data.steadycron_heartbeat_monitor, data.steadycron_tag, data.steadycron_alert_channel) let you reference existing resources without managing them.

Importing individual resources

To bring a single resource under Terraform management without a full account export:

# Resource IDs are UUIDs — find them in the dashboard URL or via:
# steadycron jobs list  (shows the id column)
terraform import steadycron_http_job.weekly_digest <job_id>
terraform import steadycron_heartbeat_monitor.db_backup <job_id>
terraform import steadycron_alert_channel.ops_email <channel_id>
terraform import steadycron_alert_rule.digest_failure <rule_id>
terraform import steadycron_tag.env_prod <tag_id>

After importing, run terraform plan. Fields the API redacts on read (alert channel secrets, heartbeat tokens) will show as diffs — add their values to your configuration.

Interoperability with the CLI

Resources created via Terraform have a null manifest_namespace, so they are never pruned by steadycron apply --prune. Manage a resource with Terraform or with the YAML CLI, not both — mixing tools for the same resource is unsupported.

Rate limits

The SteadyCron API allows 120 requests per minute per key. The provider automatically retries 429 Too Many Requests responses with exponential backoff (up to 5 retries, honouring Retry-After). If you hit limits regularly, lower provider parallelism:

terraform apply -parallelism=5

CI/CD with GitHub Actions

The steadycron/action GitHub Action supports Terraform natively via tool: terraform. It handles terraform init automatically, posts a plan diff as a sticky PR comment, and uses a saved plan file when plan and apply run as separate steps in the same job.

Plan on pull request:

- uses: steadycron/action@v1
  with:
    tool: terraform
    command: plan
    working-directory: infra/steadycron
    comment-on-pr: 'true'
  env:
    STEADYCRON_API_KEY: ${{ secrets.STEADYCRON_API_KEY }}

Apply on merge:

- uses: steadycron/action@v1
  with:
    tool: terraform
    command: apply
    working-directory: infra/steadycron
  env:
    STEADYCRON_API_KEY: ${{ secrets.STEADYCRON_API_KEY }}

See CI/CD setup for complete workflow files, the remote state backend pattern, and all available action inputs.