Skip to main content

Render and Railway Bill Per-Second for What Kubernetes CronJob Does for Free

9 min readDora NodaDora Noda
Share

Render's Cron Jobs and Railway's cron feature both do the same thing: spin up an ephemeral container on a schedule, make sure the last run finished before starting the next one, and bill you for however many seconds it was alive. Kubernetes has shipped that exact primitive — CronJob, built on top of Job — as a free, built-in API object since v1.21, half a decade ago. It costs nothing beyond the node it runs on.

So what does the hosted version of a five-year-old free primitive actually cost a team running a normal number of scheduled tasks? Below is the line-by-line math at 1, 5, 20, and 100 jobs a month, and the crossover point where "billed per second" stops being the cheap option. Spoiler: it isn't a huge, compute-hungry job that breaks the hosted pricing model — it's the ordinary habit of accumulating a lot of small ones.


The same primitive, three implementations

Strip away the marketing and all three products are doing one thing: run a container when the clock says to, and don't let two copies of it run at once. The difference is what happens when a run is still going when the next tick arrives.

Overlap handlingMinimum intervalMax run length
Render Cron JobsDelays the next scheduled run until the active one finishes (does not skip it)None documented12 hours, then force-stopped
Railway cronSkips the new run if the previous one hasn't finished5 minutesNone documented, but the platform expects services to exit promptly
Kubernetes CronJobYour choice: Allow (run concurrently), Forbid (skip, same as Railway), or Replace (kill and restart, closest to Render's queue-and-run)Whatever your cron syntax can express (practically 1 minute)Unbounded, or set your own via activeDeadlineSeconds

Kubernetes also has startingDeadlineSeconds, which controls how long a missed run is allowed to start late before it's abandoned entirely — a knob neither hosted platform exposes to you directly. None of this is exotic; it's the same scheduling logic every cron-like system needs.

The overlap-handling column isn't just trivia — it changes what "reliable" means on each platform. Render's queue-and-run means a job that occasionally runs long doesn't lose executions; it just pushes them later, which is safe for things like report generation but dangerous for things like "poll an external API every 5 minutes," where a pileup of delayed runs can eventually fire in a burst. Railway's skip-on-overlap (identical to Kubernetes Forbid) is the opposite trade: no burst risk, but a job that occasionally runs long silently loses executions, so anything that must run exactly once per period needs its own idempotency or alerting.

Railway's 5-minute floor on scheduling frequency is also a hard ceiling Kubernetes doesn't share — a CronJob can fire once a minute if the workload calls for it. The only place the three products actually diverge in the ways that show up on an invoice is the bill.

What N scheduled jobs a month actually costs

Take a realistic workload: a small task — a cache warm, a report export, a webhook retry sweep — running once a day, taking about 2 minutes, on roughly 0.5 vCPU / 512 MB. That's the Render "Starter" instance size and a proportionate Railway container. Here's what happens as the number of distinct scheduled jobs (not runs) grows.

Render Cron Jobs bills each cron job at the same per-second rate as a web service (Starter instance list price: $7/month, ≈ $0.0096/hour), but with a $1/month minimum per cron job service — a floor that applies per job, not per run. A job like the one above runs for 1 hour of total compute a month (30 runs × 2 minutes), which prices out to roughly $0.01 in actual usage. The floor swallows that immediately: every job on Render costs at least $1/month regardless of how little it runs.

Railway cron meters CPU and RAM separately and pools the result against your plan's included credit: $20/vCPU-month ($0.000463/vCPU-minute) and $10/GB-month ($0.000231/GB-minute), billed per second. The same job (0.5 vCPU, 0.5 GB, 2 minutes × 30 runs = 60 minutes/month) costs:

text
60 min × (0.5 × $0.000463 + 0.5 × $0.000231) ≈ $0.021/month in raw usage

That's billed against the Hobby plan's $5/month included credit — so unless your aggregate cron usage across every job exceeds $5, the marginal cost of adding another job is close to zero. The floor isn't per-job; it's per-account.

Kubernetes CronJob on a self-hosted fleet has no per-job billing surface at all. A single Hetzner CX22 (2 vCPU / 4 GB, ~$4.59/month as of the June 2026 repricing) has enough headroom to run dozens of jobs like this one — they're brief and staggered, not concurrent — for the price of the box you're already running other things on.

Jobs/monthRender (per-job $1 floor)Railway (pooled usage vs. $5 Hobby credit)Self-hosted CronJob on one Hetzner CX22
1$1.00$5.00 (plan floor)$4.59 (box you already run)
5$5.00$5.00 (plan floor)$4.59
20$20.00$5.00 (usage ≈ $0.42, still under credit)$4.59
100$100.00$5.00 (usage ≈ $2.10, still under credit)$4.59 (or one size up if CPU headroom gets tight)

Below 5 jobs, Render is actually the cheapest of the three — a $1 floor beats a $5 plan minimum. Past that, the lines diverge hard: Render climbs $1 for every job you add, forever, because the floor is job-scoped. Railway and a self-hosted node both stay flat, because their floors are account-scoped and infrastructure-scoped respectively, not job-scoped. At 100 lightweight scheduled jobs, Render costs 20-24x what the other two cost.

Does a heavier job change the picture? Swap the assumption: instead of 2 minutes/day at 0.5 vCPU, make it an hour a day at 1 vCPU / 2 GB — a real nightly ETL step, not a health check. That's 30 hours/month of compute:

  • Render, on a Standard instance ($25/month, ≈ $0.0343/hour), bills 30 hours × $0.0343 ≈ $1.03/month — usage-priced now, just barely past the $1 floor.
  • Railway bills 1,800 minutes × (1 × $0.000463 + 2 × $0.000231) ≈ $1.67/month — still comfortably inside the $5 Hobby credit.
  • Self-hosted CronJob stays at the same $4.59/month box, assuming the hour-long run fits the node's spare CPU/RAM window.

One heavy job barely moves any of the three numbers — a single job, however chunky, rarely crosses either hosted platform's floor by much. It's twenty single-minute jobs that costs $20/month on Render, not one twenty-minute job. The floor punishes job count, not job size, which is exactly backward from how most teams budget for compute.

Why the floors behave so differently

The mechanism is worth naming explicitly, because it's the whole story: Render's minimum charge is attached to the job definition; Railway's is attached to the account. Adding a 21st cron job on Render always adds another dollar, no matter how trivial the job is — a health-check ping, a stale-session sweep, a "did the backup finish" alert all cost the same $1 floor as a job that actually needs a Starter instance's worth of compute. Railway doesn't care how many job definitions you have; it cares how much CPU-time and memory-time they collectively burn, and light jobs simply don't move that number.

A self-hosted CronJob inherits neither constraint, because there's no billing layer between the job and the node at all — the Kubernetes control plane schedules Job pods the same way it schedules anything else, and the only thing that costs money is the node capacity you provisioned regardless of cron. Teams that accumulate a lot of small scheduled tasks — and most platform teams do, because "just add a cron job" is the path of least resistance for one-off maintenance scripts — are the ones who feel Render's per-job floor first. It's not a pricing edge case; it's the default shape of how cron jobs accumulate.

The honest caveat: self-hosted isn't literally free

Zero billing surface is not the same as zero cost. A Hetzner CX22 has 2 vCPU and 4 GB of RAM total — that's a hard ceiling, not an accounting abstraction. Pack enough concurrent or heavier jobs onto it and you'll need a bigger box or a second node, which is a real dollar increase, just a much coarser and less frequent one than "another dollar per job."

And somebody still has to keep the cluster patched, the node pool sized, and the CronJob manifests correct — that operational cost is real even when the invoice line for it is $0. What self-hosting actually buys you here isn't "free," it's "the marginal cost of one more job is zero until you hit a real capacity wall," instead of "the marginal cost of one more job is $1, always, no matter how small."

There's also a reliability trade worth stating plainly: Render and Railway run their control planes, so a scheduled job firing on time is someone else's uptime problem. A self-hosted CronJob makes that your problem — if the cluster's control plane or the kube-controller-manager has an outage window, scheduled runs during that window are missed the same way any other cluster-dependent workload would be. For a team already operating a Cluster API fleet for its regular services, that's not new risk, just the same risk cron jobs now share with everything else running there. For a team with no fleet today, "self-host CronJob to save $15/month" is not, by itself, a reason to stand one up.

Where this fleet actually runs

For a team already running a Cluster API fleet — or thinking about moving scheduled tasks off a hosted PaaS onto owned infrastructure — the CronJob object doesn't need a special product tier or a "cron jobs" line item on a pricing page. It's a standard Kubernetes resource that ships with the cluster.

Bex.co is the open-source, AI-native Render alternative — push a git repo, get a running HTTPS service on machines you own, with the full Kubernetes API (including CronJob) underneath rather than a metered wrapper around it. Star the repo on GitHub or deploy your first app today.


Sources:

Related articles

Run this on infrastructure you own

bex is the open-source, AI-native Render alternative — push a git repo and get a running HTTPS service on your own machines.

Get started with bex