Scheduled jobs
Run commands on a schedule (cron), once, or on demand, on your servers or inside one of your app's containers, and tune the built-in maintenance jobs Synq runs for you.
Jobs are tasks that run on a schedule on your install: the maintenance Synq does for you, and commands you want to run yourself, such as a nightly database dump, a cache warm-up or a cleanup script. Open Jobs in the sidebar (under Infrastructure).
The page has three sections:
- System jobs: built-in maintenance on this instance.
- Custom jobs: commands you run on your servers or in your apps' containers.
- Backup schedules: the automatic backups of your projects and services, listed read-only. They are managed on each project's Backups tab (Manage in Backups).
At a glance counts all jobs and how many are running, failed, scheduled or disabled. Every run is recorded with its trigger (schedule or manual), result, duration and output.
Built-in jobs
Synq keeps these running for you. Each row shows its Schedule, Next run and Last run, with Run now, Edit schedule, Enable / Disable and Logs. Changing a built-in job needs an instance administrator. You can't delete a built-in job; disable it instead.
| Job | What it does | Default schedule |
|---|---|---|
| SSL certificate renewal | Renews Let's Encrypt certificates before they expire | daily at 03:17 |
| Orphaned resource cleanup | Reclaims leftovers from a failed teardown | hourly |
| Deployment artifact cleanup | Removes old release images beyond each project's retention | daily at 04:23 |
| Docker build-cache garbage collection | Keeps the build cache on each Docker host within about 10 GB | daily at 04:37 |
| Docker cleanup | Removes unused Docker images, containers, build cache and (if chosen) volumes. Off by default; set it up on a server's Docker tab | Sundays at 03:41 |
| Panel database backup | Backs up the control-plane database to a backup destination. Off by default; set it up in Settings, Instance | daily at 02:11 |
| Backup retention prune | Deletes backups past their retention | hourly |
| Audit log prune | Deletes audit entries older than the workspace's retention | daily at 04:07 |
| Deployment reconcile | Settles deploys interrupted by a connection blip | every 10 minutes |
| Domain DNS verification | Re-checks domains still waiting for DNS | every 13 minutes |
| Update scan, Native-module update scan, Managed-container update scan | Look for new versions of Synq's parts and of the edge and mail containers | every 6 hours |
| Resource usage sampling, Traffic analytics collection, Container health watch | Collect the numbers behind monitoring | from every minute to twice an hour |
| One-time job dispatcher | Starts custom jobs scheduled to run once | every minute |
| Job run history prune | Deletes old job runs | daily at 04:23 |
There are a few more housekeeping jobs (prunes of analytics, usage samples, incidents, webhook events and pending grants). The exact list depends on your install; the page shows all of them.
Turn Docker cleanup and panel backups on where they are configured
Both need settings the Jobs page doesn't have (what to remove and on which servers; where to store the backup). Turn them on from their own screens, then use Jobs to watch their runs. The Docker cleanup card on a server's Docker tab has an Open in Jobs link that leads here; for panel backups, find the Panel database backup row on this page.
Create a custom job
Start a new job
In Jobs, press New job (or Create job when you have none).
Basics
Give it a Name (for example "Nightly DB vacuum") and the Command to run. Then choose Run inside:
- Host: the command runs over SSH on the Target servers you tick. It can also start a throwaway container,
for example
docker run --rm postgres:16 pg_dump .... - A project's service: the command runs inside that service's running container. See below.
Schedule
Pick When to run:
| Choice | Meaning |
|---|---|
| On a schedule | A 5-field cron in Schedule (cron). Synq checks it when you save and shows the next run. |
| Once | At the date and time in Run at. |
| Manual | Only when triggered: Run now, a job it depends on, or an event. |
Reliability, environment and triggers (optional)
| Section | Fields |
|---|---|
| Reliability | Timeout (s) stops the command after that long (up to 24 hours). Max attempts (1 to 10) and Backoff (s) retry a failed run; all attempts land in one run. |
| Environment | Environment variables (Add variable, Paste .env or Upload .env) and Secrets, which are encrypted and only decrypted when the job runs. Both are exported before your command. |
| Dependencies & triggers | Run after: start when the chosen jobs succeed. Event triggers: start on Deploy succeeded, Deploy failed, Backup succeeded, Backup failed, Restore completed, SSL renewal failed or Domain verification failed. |
| Notifications | Which channels hear about running, success or failed, overriding your global notification settings for this job. |
Create it
Check the Summary and press Create job. Open the job to see its Overview and Runs, press Run now, Edit or Delete it. Logs streams a run's output live while it runs.
Run a job inside an app's container
Choose Run inside, A project's service, then the Project and the Service. The command runs with
docker exec in that service's running container, on the server the project is deployed to. Use it for tasks
that need the app's own code, tools and environment:
# A Laravel scheduler tick
php artisan schedule:run
# A Django management command
python manage.py clearsessions
# A Node script shipped with the app
node scripts/send-digest.jsThings to know:
- The server is taken from the project; you don't pick one. A container job always targets exactly one server.
- The service must be running when the job fires, or the run fails.
- The output appears when the command finishes (a host job streams it line by line).
- Without a Timeout, a container job is stopped after 1 hour.
- Saving, running or deleting it needs write access to that project, on top of the server access every job needs.
- To move a job back to the host, edit it and choose Host.
Schedules (cron), in plain terms
A schedule is a standard 5-field cron string, in the Synq server's time zone (UTC in the standard install):
┌───────── minute (0-59)
│ ┌─────── hour (0-23)
│ │ ┌───── day of month (1-31)
│ │ │ ┌─── month (1-12)
│ │ │ │ ┌─ day of week (0-6, Sunday is 0)
* * * * *| Cron | When |
|---|---|
0 3 * * * | every day at 03:00 |
*/15 * * * * | every 15 minutes |
0 * * * * | every hour, on the hour |
0 2 * * 0 | every Sunday at 02:00 |
30 4 1 * * | 04:30 on the 1st of each month |
Run now is recorded too
A run started with Run now is saved in the history like a scheduled one, marked as manual, so you always have a full record.
Who can manage jobs
- Built-in jobs: instance administrators change their schedule, turn them on or off and run them.
- Custom jobs: you need admin access to every target server (owners, admins and members have it; restricted members need a server grant with admin). A job that runs inside a container also needs write access to its project. People who can't reach a job's servers don't see it.
CLI
Use synq job (alias jobs) with your self-hosted connection context:
synq job list
synq job create --name weekly-sync --server <server-id> \
--command 'cd /srv/app && npm run db:sync' --cron '17 4 * * 1'
synq job get <key>
synq job update <key> --no-enabled
synq job update <key> --enabled --cron '0 3 * * *'
synq job run <key> --follow
synq job runs <key> --limit 10
synq job logs <run-id> --follow
synq job delete <key> --yesJobs also work with synq --native-config <file> job ... through the native SDK.
Use the job key from list or create, not its database ID. For a one-time job, pass
--schedule once --at <ISO-timestamp>. For manual execution only, pass --schedule manual. Recurring jobs use
--cron.
Both create and update accept --file <path> containing a JSON Jobs API body. Use it for env, secrets,
serverIds, retry, timeoutMs, dependsOn, triggerEvents, notifyConfig, or a container target, or to supply
the entire job configuration. Explicit flags override file values. Updates send only supplied fields. Keep files
containing secrets private. The API encrypts secrets at rest.
A job that runs inside a container sets both projectId and serviceId (the server is derived from the project):
{
"label": "Laravel scheduler",
"command": "php artisan schedule:run",
"scheduleType": "recurring",
"cronExpression": "* * * * *",
"projectId": "proj_123",
"serviceId": "svc_456"
}synq job create --file scheduler.jsonSending "projectId": null, "serviceId": null in an update moves the job back to the host.
--json returns API data without the envelope. Followed runs emit JSON events. Without --follow, run returns a
custom run ID immediately. With --follow, the CLI waits for the outcome and exits nonzero on failure or an
interrupted stream. Built-in jobs return their summary directly. logs without --follow shows stored output, or
the full run record with --json.
Related guides
Notifications
Get told when a deploy fails, an app goes down, a disk fills up or a certificate can't renew, by email, webhook, Slack, Discord, Microsoft Teams, Telegram, ntfy, Gotify, Pushover, Mattermost or Matrix.
Backups & restore
Back up your databases and service data on a schedule, keep the copies you need, and restore one with the step-by-step wizard, from the panel or the terminal.