(Cron jobs · Nautilus)

Cron Jobs Beyond Your Host's Limits Recurring and one-off HTTP calls, retried and logged

Hit the limit of your platform's scheduler? Nautilus calls any public URL on a cron schedule you set, as often as once a minute. A failed call is retried, every attempt is logged, and schedules are set over an API rather than in a config file. Schedules run in UTC.

curl -X POST https://api.vernesoft.com/v1/clockwork/jobs \
  -H "Authorization: Bearer vrn_clockwork_•••" \
  -d '{"name":"billing","schedule":"0 0 1 * *","url":"https://api.yourdomain.com/billing"}'

(Where Cron Runs Out)

Where the Scheduler You Already Have Stops

A crontab is fine on one machine, and a platform scheduler is fine inside its platform. Trouble starts at the edge: the free plan that allows one run a day, the second server that fires the same job twice, the failure nobody saw.

Crontab and Platform Schedulers

  • ✕ A free platform plan with a cap: on Vercel Hobby a cron job runs once a day at most, and only to within the hour, so a 01:00 job can start any time up to 01:59 (Vercel docs, checked 3 October 2026).
  • ✕ A crontab on every instance: add a second server and the same billing run fires twice.
  • ✕ No retries: a run that fails waits for its next scheduled time, and nothing says it failed unless you built that.
  • ✕ Schedules live in a config file or a crontab, so changing one means a deploy, and your own customers cannot set theirs.

Cron Jobs in Nautilus

  • ✓ Any schedule down to once a minute, on every plan including Free.
  • ✓ Calls any public URL on any host: a route on Vercel, a VPS, another cloud.
  • ✓ A failed run is retried, up to three attempts, and every attempt is logged with the status and body it got back.
  • ✓ Schedules are created, changed and paused over an API: no deploy to change one, and your customers can have their own.

(Core Features)

How a Job Runs

(01)

One Run Per Schedule

The schedule lives with us, not in each instance of your app, so scaling your app out cannot multiply it. On our side, each due run is claimed in the database before it fires, so a second worker that sees the same job finds it already taken.

(02)

Schedules Set Over an API

Create, pause, change and delete schedules over the API, or schedule a one-off task for a set time. If your customers define their own recurring tasks in your product, your backend creates the job when they save it.

(03)

Retries That Survive Deploys

A failed run gets up to three attempts: the first, then retries one minute and five minutes later. Retry state lives with the job rather than in memory, so a pending retry survives a worker restart or a deployment.

(04)

Minute Resolution

The scheduler wakes once a minute and starts whatever is due, so a job set for 09:00 starts on the first check at or after 09:00, not somewhere inside the hour. There is no seconds field, and every schedule runs in UTC.

(05)

A Log of Every Run

Every attempt is recorded with its start time, how long it took, the HTTP status your endpoint returned and the response body, or the error if the call never connected. History is kept for your plan's window, which is on the pricing page.

(06)

Standard Cron Syntax

Standard 5-field cron expressions, resolved in UTC: there are no timezones and no shorthand macros such as daily or hourly. A schedule that restricts both day-of-month and day-of-week is rejected rather than guessed at, and so is one that can never fire.

(Part of Nautilus)

Our Own Scheduler, on the Same Account

Cron jobs are one part of Nautilus, on the same account and dashboard as sign-in and webhook delivery. The scheduler is our own code. Sign-in and webhook delivery run on open-source engines you could host yourself; this part does not come with you if you leave. What does come with you: every job and run is readable through the API.

Your scheduleNautilus calls your URLYour endpoint

(Developer Experience)

Schedule a Job via API

Give it a cron expression and a URL, through an official SDK or a plain HTTP request. A one-off task takes a UTC timestamp instead.

curl -X POST https://api.vernesoft.com/v1/clockwork/jobs \
  -H "Authorization: Bearer $VERNE_CLOCKWORK_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Monthly Billing Run",
    "schedule": "0 0 1 * *",
    "url": "https://api.yourdomain.com/billing/process",
    "method": "POST",
    "body": "{\"batch\":\"auto\"}"
  }'

(FAQ)

Frequently Asked Questions

How does Nautilus prevent duplicate executions?

The schedule lives with us, so adding instances of your app changes nothing. On our side, each due run is claimed with a conditional update in the database before anything fires: a second worker that sees the same job finds the row already advanced and does nothing. That gives you one trigger per scheduled slot. Delivery itself is at-least-once, because a failed attempt is retried, so make your endpoint idempotent and use the X-Clockwork-Attempt header to guard side effects.

What happens if the target endpoint is down when the cron fires?

Each run gets up to three attempts: the first, then retries one minute and five minutes later. Network failures, 5xx and 429 are retried; other 4xx responses are not, since an identical retry would get the same answer. Each attempt waits up to 30 seconds for a reply, and redirects are not followed, so give the final URL. Every attempt is recorded with the response it returned, and a pending retry survives a worker restart.

Can I schedule one-off tasks (delayed jobs)?

Yes. Alongside recurring expressions you can schedule a one-off task for a UTC timestamp, for example sending an email 24 hours after registration. It is picked up on the scheduler's once-a-minute check, like everything else here.

Vercel Hobby allows one cron run a day. Can Nautilus call my Vercel function more often?

Yes. A job is an HTTP call to a public URL, so it can point at a route on your Vercel deployment, with whatever headers it needs to get past your own checks, as often as once a minute. The function still runs on Vercel, so Vercel's own duration and usage limits apply; Nautilus only does the calling, and those runs do not count against your request quota. For the record, Vercel's docs (checked 3 October 2026) include cron on every plan, Hobby too, but cap Hobby at one run a day with timing only to within the hour; Pro runs per minute. The others stop at their own edges: pg_cron reaches only what your database can reach, and a GitHub Actions schedule can start late under high load, by its own documentation.

How do I test a job without waiting for its schedule?

Create a delayed job a minute out with POST /v1/clockwork/delayed and watch it in the execution log. There is no run-now button yet. A one-off run uses the same worker and the same logs as a recurring one.

Is there a free tier?

Yes, with no card. Clockwork does not use your request quota: scheduled runs and Clockwork API calls are not counted against it. What each plan limits is how many jobs are active at once: Free allows 10 recurring jobs and 100 delayed jobs waiting to run, Starter 100 and 1,000, Pro 1,000 and 10,000. Starter is €19 and Pro €79 a month, and the pricing page has the current list.

Will I be told when a job fails?

Not today. Nothing sends an alert when a run fails. Every attempt is logged with the status and body it got back, and you can read the log in the dashboard or poll the executions endpoint, so a check of your own can raise the alarm.

(Get Started)

Schedule your first job without touching your host

Cron jobs are one part of Nautilus: the same account and dashboard as sign-in and webhook delivery.

When you do not need this

If you run one application on one machine, crontab is fine and you should keep it. The same holds for work that never leaves its own platform: Vercel Cron suits a Vercel function, pg_cron suits a job that only touches your Supabase database, and a GitHub Actions schedule is fine for a nightly task that can afford to be late.

Nautilus earns its place at the boundary where those stop, and that boundary arrives sooner than people expect. The second instance, where two copies of the same crontab fire the same billing run twice. The job that has to call a service on another host. The schedule your own customers set from your dashboard. The free plan that fires a daily job somewhere inside the hour. The run that failed at 03:00 and left no trace.

Those five are what Nautilus answers: one execution per schedule however many instances you deploy, any public URL on any host, schedules created and cancelled through an API, minute-level timing on every plan, and a log of every attempt with the response it returned. Scheduled runs do not count against your request quota, and the free plan allows 10 active recurring jobs.