Generate systemd timer migration drafts from crontab text with diagnostics.
crontab-timer-migration-kit is a clean-room TypeScript package for dry-running small cron-to-systemd migrations. It is browser-friendly, ESM-only, dependency-free, and returns generated .service / .timer text plus stable diagnostics.
npm install crontab-timer-migration-kitimport { migrateCrontabToSystemdTimers } from "crontab-timer-migration-kit";
const result = migrateCrontabToSystemdTimers(`
PATH=/usr/local/bin:/usr/bin
30 2 * * * /usr/local/bin/backup
`);
console.log(result.jobs[0]?.serviceUnit);
console.log(result.jobs[0]?.timerUnit);
console.log(result.diagnostics);Parses crontab text and returns:
- captured environment variables;
- one migration job per supported cron command;
- generated service and timer unit names;
- generated unit file contents;
- stable diagnostics for ignored, risky or unsupported lines.
const result = migrateCrontabToSystemdTimers("15 1 * * * npm run cleanup", {
unitPrefix: "nightly",
workingDirectory: "/srv/app",
user: "deploy",
persistent: false
});
if (result.ok) {
for (const job of result.jobs) {
console.log(job.serviceUnitName, job.serviceUnit);
console.log(job.timerUnitName, job.timerUnit);
}
}Creates a reusable wrapper with default options.
const migrator = createCrontabTimerMigrator({ unitPrefix: "cron-migration" });
const result = migrator.migrate("0 7 * * 1 /usr/bin/report");| Option | Default | Description |
|---|---|---|
unitPrefix |
"cron-job" |
Prefix for generated unit file basenames. |
descriptionPrefix |
"Migrated cron job" |
Prefix used in systemd Description= fields. |
workingDirectory |
undefined |
Optional WorkingDirectory= for each service. |
user |
undefined |
Optional User= for each service. |
persistent |
true |
Timer Persistent= value. |
maxJobs |
50 |
Maximum number of jobs to migrate from one input. |
The MVP converts plain five-field cron schedules where each field is either * or a number:
30 2 * * * /usr/local/bin/backup
0 7 * * 1 /usr/bin/reportIt intentionally does not convert cron macros, ranges, lists, step values or named weekdays/months yet. Those lines receive error diagnostics and keep OnCalendar=UNSUPPORTED when a job record can still be produced for review.
Commands are emitted through /bin/sh -lc because many real crontabs rely on shell behavior. This package still warns when it sees obvious shell syntax so a reviewer can decide whether to split the command into a script.
Diagnostics are stable strings for tests, UI hints and migration reports:
invalid-inputinvalid-optionsempty-crontabline-ignoredenvironment-variableunsupported-macrounsupported-stepunsupported-listunsupported-rangeunsupported-nameinvalid-field-valueinvalid-field-countunsafe-unit-namecommand-needs-shellcron-environment-differsmailto-not-migrated
This package does not read or write files, install units, call systemctl, validate with systemd, or claim full cron compatibility. It produces reviewable migration drafts for small crontabs and makes unsupported syntax explicit.
- TypeScript types are generated from the source.
- ESM-only package with no runtime dependencies.
- Defensive API: invalid input and invalid runtime options return diagnostics instead of throwing.
- CI runs
npm ci,typecheck,build, andtest. - Tested on Node.js 20 and 22 with GitHub Actions.
MPL-2.0