Cron jobs
Call a path on your production app on a schedule.
A cron job sends a request to a path on your app's production deployment on a schedule, for work like sending digest emails, syncing with another service, or cleaning up old data. Your app does the work in an ordinary route handler; Clouzark only calls it.
Declare jobs in clouzark.json
Add a crons array to clouzark.json in your project's root directory (the same directory as package.json):
{
"crons": [
{ "path": "/api/cron/cleanup", "schedule": "0 3 * * *" },
{ "path": "/api/cron/digest", "schedule": "0 8 * * 1", "timezone": "Europe/Berlin", "name": "weekly-digest" }
]
}The jobs take effect when the deployment becomes production, and a rollback restores the jobs of the deployment you roll back to. Preview deployments never run cron jobs. If clouzark.json is invalid, the build fails and says why.
| Field | ||
|---|---|---|
path | required | Path on your app, starting with /. A query string is fine: /api/cron?task=cleanup |
schedule | required | 5-field cron expression (see Schedules) |
name | Unique within the project. Defaults to one made from the path, e.g. api-cron-cleanup | |
timezone | IANA time zone the schedule is read in. Default UTC | |
method | GET (default) or POST | |
timeout | Seconds to wait for the response, 1 to 300. Default 60 | |
retries | Times to retry a failed request, 0 to 3. Default 0 |
Or add them with the CLI or dashboard
Jobs can also be added without a deploy, from the project's Cron Jobs page or the CLI:
clouzark crons add cleanup /api/cron/cleanup "0 3 * * *"
clouzark crons add digest /api/cron/digest "0 8 * * 1" --tz Europe/Berlin --method POST --retries 2
clouzark crons lsJobs from clouzark.json are kept in step with the file: you can't edit or delete them from the CLI or dashboard, only switch them off and on. A paused job stays paused across deploys.
A project can have up to 20 cron jobs in total.
Secure the endpoint
Your cron path is a public URL, so check that a request really comes from Clouzark. Add a CRON_SECRET environment variable to production with a long random value; every cron request then carries it as a bearer token:
export async function GET(request: Request) {
if (request.headers.get("authorization") !== `Bearer ${process.env.CRON_SECRET}`) {
return new Response("Unauthorized", { status: 401 });
}
// ... do the work
return Response.json({ ok: true });
}Requests also send User-Agent: clouzark-cron/1.0. A new CRON_SECRET value is used from the next run; your app sees it after a redeploy.
Schedules
| Schedule | Runs |
|---|---|
*/15 * * * * | Every 15 minutes |
0 * * * * | Every hour, on the hour |
0 3 * * * | Every day at 03:00 |
0 9 * * 1-5 | Weekdays at 09:00 |
0 0 1 * * | The first of every month at midnight |
Fields are minute, hour, day of month, month, and day of week. Schedules are read in UTC unless the job has a time zone; with one, a daily job stays at the same local time across daylight saving changes. The most often a job can run is once a minute.
How requests are made
- To your production URL,
https://<project>.<apps domain><path>. If the app is asleep, it's woken first. - A 2xx response is a success. Anything else is a failure, and the run records the status code and the start of the response body.
- Redirects aren't followed. A 3xx response fails the run, so point the job at the final path.
- Retries are for 5xx responses, timeouts, and network errors, a few seconds apart. A 4xx response isn't retried.
- Never overlapping. If a job's previous run is still going when it's due again, the new run is skipped and recorded as
skipped. Still, write handlers that are safe to run twice.
Check and change jobs
clouzark crons runs cleanup # recent runs: status, HTTP code, duration, response
clouzark crons run cleanup # call it now and wait for the response
clouzark crons disable cleanup # stop scheduled runs; it can still be run by hand
clouzark crons enable cleanup
clouzark crons edit digest -s "0 9 * * 1"
clouzark crons rm digestEach job keeps its last 100 runs. Jobs are addressed by name or id. The same operations are in the Management API and available to AI agents. To run SQL against a database on a schedule instead, see database cron jobs.