Cron jobs
Call a path in your app automatically on a schedule.
A cron job sends a GET request to a path in your app on a schedule, such as "call /api/cleanup every day at 5 AM". Register jobs in the console, through the Cron jobs API, or declare them in nitroship.json (or vercel.json) at the deployment root.
{
"crons": [
{"path": "/api/cron?source=scheduled", "schedule": "0 5 * * *"}
]
}This example calls /api/cron?source=scheduled every day at 05:00 UTC.
Runs on production only
Cron jobs only call the current ready production deployment; previews never run them. Changes to nitroship.json require a production deploy. Console/API changes apply immediately without deploying.
Managing crons from the console
Open your app's App Settings > Cron Jobs section to add, edit, or remove jobs, then save the list. Changes apply immediately to the current production deployment. You can also replace the complete list with PUT /v1/apps/{appId}/crons; sending {"crons": []} removes all jobs.
Console/API editing is always allowed, even when nitroship.json declares crons. The saved list wins until the next production deployment that declares crons. On every such deploy, the file's list overrides console/API settings again; redeploying, promoting, or rolling back to a deployment that declares crons also restores its list.
- An explicit
"crons": []declares an empty list and overrides console jobs too. - A deployment that does not declare
cronsuses the saved console list. - To hand control back to the console, remove the
cronskey fromnitroship.jsonand deploy. Removing a job from the console alone does not remove it from the file.
The same rules apply to vercel.json. You can save jobs before your first production deployment, but they will not run until a ready production deployment exists.
Writing a schedule
The time zone is always UTC, and a schedule has five fields: minute, hour, day of month, month, day of week.
| Example | Meaning |
|---|---|
0 5 * * * | Every day at 05:00 |
*/10 * * * * | Every 10 minutes |
0 9 * * 1-5 | Weekdays at 09:00 |
0 0 1,15 * * | The 1st and 15th of every month at 00:00 |
- You can use numbers,
*, ranges (1-5), lists (1,15), and steps (*/10). - Names such as
MONorJAN, aliases such as@daily, and six-field formats with seconds are not supported. - You cannot restrict day of month and day of week at the same time; one of them must be
*.
path must start with / and may include a query string. Each app can declare up to 100 cron jobs.
When a run fails
If a run cannot happen at its scheduled time, that run is skipped and not retried automatically. If a job must not be missed, make your app catch up on missed work itself.
Accept only cron requests
Cron paths are public addresses that anyone can call. To confirm a request came from cron:
- Add
CRON_SECRETto your production environment variables. - Deploy again.
- Cron requests now carry
Authorization: Bearer <CRON_SECRET>. Check this value in your endpoint.
Requests use User-Agent: nitroship-cron/1.0, but anyone can fake that, so do not use it for authentication.
See registered schedules
The GET /v1/apps/{appId}/crons API lists the effective schedules, their next run times and last runs, and whether their source is "config", "console", or "none". configDeclared tells you whether the current production deployment declares crons, even if a console edit currently overrides them. See Cron jobs API.