Cron as Code
Cron as code,
end to end
Author every job, monitor, channel, and alert rule in YAML or Terraform. Review changes in pull requests, apply them from GitHub Actions, and watch the run from inside your app with the .NET and Python SDKs — all from one repository.
Free tier — no credit card required.
Terminal
$ steadycron validate steadycron.yaml
✓ 2 jobs · 1 channel · 1 rule — no errors
$ steadycron plan steadycron.yaml --namespace prod
~ weekly-digest update retries: 2 → 3
+ nightly-db-backup create heartbeat · 0 2 * * *
1 to update · 1 to create
$ steadycron sync steadycron.yaml --namespace prod
✓ applied — account now matches the manifest 2 · Reconcile
validate → plan → apply. No surprises.
The steadycron CLI reconciles your account to match the manifest. plan shows exactly what would change, sync applies it transactionally, and --prune deletes what you removed — scoped to a namespace so the blast radius is always explicit.
- →
exportadopts an existing account into a manifest in seconds. - →
import crontab/import vercelmigrate existing schedules. - →Using Terraform?
terraform plan / apply / importdrive the exact same loop.
3 · Ship
Plan on every PR. Apply on merge.
The steadycron/action@v1 GitHub Action posts a sticky plan comment on each pull request — reviewers see exactly which jobs, monitors, channels, and rules a change introduces — then applies on merge. Your main branch is the source of truth.
The same action drives both tools: set tool: yaml for manifests or tool: terraform for HCL.
Plan: 1 to update · 1 to create · 1 to delete
~ weekly-digest update retries: 2 → 3
+ invoice-reminder create http · 0 17 * * 5
- old-report delete (removed from manifest) # .github/workflows/cron.yml
- uses: steadycron/action@v1
with:
command: plan # 'apply' on merge to main
manifest: steadycron.yaml
comment-on-pr: "true"
env:
STEADYCRON_API_KEY: ${{ secrets.STEADYCRON_API_KEY }} 4 · Observe
The job and the code that watches it — same key, same repo.
Declare a heartbeat monitor with a stable key in YAML or Terraform. Reference that exact key from your application with the .NET or Python SDK. SteadyCron then knows when the job started, succeeded, failed, or never ran.
The SDKs never create monitors — they resolve the key with a read-only API key, and pings are fire-and-forget: a monitoring outage never takes down your job. Schedule, alert rules, and instrumentation all live as code, together.
In your manifest / HCL
key: nightly-db-backup
import steadycron
@steadycron.job("nightly-db-backup") # same key
def backup():
run_backup() # start · success · fail — automatic // same key as the manifest
await monitor.TrackAsync("nightly-db-backup", async ct =>
{
await RunBackupAsync(ct);
}); Why SteadyCron for cron as code
The whole loop as code
Schedule, monitoring, alert routing, and the in-app instrumentation — one repository, one review, one deploy.
EU-hosted, GDPR-native
Runs on Hetzner in Germany, governed by German law. No US sub-processors for cron execution or job data.
Tools you already use
YAML or Terraform, a dedicated CLI, a GitHub Action, and first-party SDKs — no bespoke DSL, no lock-in to a console.
FAQ
Common questions
YAML manifest or Terraform — which should I use?
Whichever your team already standardises on. The YAML manifest with the steadycron CLI is self-contained and needs no other tooling; the Terraform provider fits naturally if you already run Terraform. Both express the same resources and share the same plan / apply / import loop. Manage any given resource with one tool, not both.
Can I use this in my CI/CD pipeline?
Yes — that's the recommended workflow. The steadycron/action@v1 GitHub Action runs plan on pull requests (posting a sticky comment) and apply on merge — for both YAML (tool: yaml) and Terraform (tool: terraform). See the CI/CD setup guide.
Do the .NET and Python SDKs create the monitors?
No. The SDKs only send pings — they resolve a monitor by its stable key using a read-only API key. Declare the heartbeat monitor in YAML or Terraform first, then reference that same key from your application code.
Are my API keys or secrets ever stored as code?
No. In the manifest, ${ENV_VAR} placeholders are substituted by the CLI at apply time and {{template_var}} values are resolved server-side at execution time — steadycron export emits both automatically. In Terraform, secrets are declared as sensitive variables and supplied at apply time.
Does managing jobs as code replace the dashboard?
No. Namespaces let code-managed jobs and dashboard-created jobs coexist in one account. Only resources inside your manifest's namespace are touched by --prune — everything else is left alone.
What happens to my heartbeat ping URL when I rename a job?
Nothing changes. Each job's ping URL is tied to its stable id / key, not its display name — so a rename is just a rename, and your scripts and SDK references keep working.
One platform, three jobs
HTTP Execution
Run your endpoints on schedule — retries, timeouts, and full run logs.
Heartbeat Monitoring
Watch jobs you run anywhere; get alerted the moment one goes silent.
Cron as Code
You're hereDefine every job, monitor, and alert in YAML or Terraform.
Cron jobs that live in your repo
Sign up, export your current account, and commit your first manifest in minutes — in YAML or Terraform.
- Free tier — no credit card
- YAML or Terraform — equal support
- EU-hosted, GDPR-native