cronstrue
cronstrue turns a cron expression into a sentence for display to a person, such as converting */5 * * * * to “Every 5 minutes.” It understands ordinary five-field cron, expressions with seconds or years, Quartz characters such as ?, L, W, and #, and nicknames such as @monthly. The package has no dependencies, includes TypeScript declarations and a command-line entry point, and can describe schedules in more than thirty languages. It explains an expression; it does not schedule jobs, compute run dates, or fully validate whether a target cron engine will accept the expression.
Excellent at the narrow presentation job it claims, with unusually broad cron syntax and localization. Pair it with the parser or scheduler that actually owns validation and timing, and never treat a plausible English sentence as proof that a job will run as intended.
Use it if
- You show stored cron expressions in an admin screen, review page, or confirmation dialog
- You accept Quartz or five-, six-, and seven-field cron syntax and need one display formatter for them
- Your product needs localized schedule descriptions and can import only the locales it actually ships
- You want a zero-dependency formatter that works in Node, TypeScript, bundlers, a browser global, and a CLI
- You need validation before saving: the FAQ explicitly says cronstrue does not perform full validation and recommends a parser such as cron-parser
- You need the next run time or missed-run calculation: the FAQ says it cannot output occurrences because it only describes the supplied fields
- You need timezone-aware truth: descriptions contain clock values but the API has no timezone option and does not resolve daylight-saving transitions
- You need wording guaranteed to match every scheduler's semantics: day-of-week indexing, month indexing, and day-of-month plus day-of-week logic are configurable because cron dialects disagree
- You plan to import cronstrue/i18n in a small browser bundle: the README measures the all-locales build at about 130 KB minified versus about 42 KB for the English core and about 4 KB per locale
Setup reality
npm install cronstrue is the whole install: version 3.24.0 has no dependencies and includes declarations at dist/cronstrue.d.ts. CommonJS uses require('cronstrue'), while TypeScript and bundlers use the documented default import. English is the only locale registered by the base module. For another language, import cronstrue/locales/fr or its equivalent for a side effect before calling toString with locale: 'fr'; importing cronstrue/i18n loads every translation and the README warns that this is much larger in the browser. Pin a version if serving the UMD build from a CDN because the README notes that @latest redirects and can change underneath you. The important setup is semantic, not mechanical. Decide whether a six-field string means seconds and whether the scheduler accepts Quartz characters. Match dayOfWeekStartIndexZero and monthStartIndexZero to the system that will execute the job. Decide whether day-of-month and day-of-week fields use the wording implied by logicalAndDayFields. The default throws on parsing errors, but successful description is not validation; the project's FAQ recommends validating separately with cron-parser. cronstrue also does not know a timezone, compute a Date, or model daylight-saving transitions, so label the scheduler's timezone beside the description. Locale modules translate phrases, but you should still review wording with native speakers and test the exact expressions your product emits. If users enter cron themselves, preserve the original expression, validate with the executor's dialect, and treat the generated sentence as explanatory UI rather than an execution guarantee.
Patterns
Describe a standard five-field expressiondescribe-five-field-cron
import cronstrue from 'cronstrue';
const description = cronstrue.toString('*/5 * * * *');
console.log(description); // Every 5 minutesThe sentence is a description, not full validation. Validate against the cron engine that will execute the expression.
Describe a weekday scheduledescribe-weekdays
const description = cronstrue.toString('0 23 ? * MON-FRI');
console.log(description); // At 11:00 PM, Monday through FridayThe question mark is Quartz syntax for no specific value. Traditional Unix cron implementations may reject it even though cronstrue describes it.
Describe an expression with secondsdescribe-seconds-field
const description = cronstrue.toString('30 */10 * * * *');
console.log(description);Six fields can include seconds in cronstrue. Confirm that your scheduler uses the same field count because many crontabs accept only five fields.
Describe a cron nicknamedescribe-cron-nickname
cronstrue.toString('@monthly'); // At 12:00 AM, on day 1 of the monthNicknames are convenient but not universal. The executor, not cronstrue, decides whether @monthly is accepted.
Request a more explicit sentenceuse-verbose-wording
const concise = cronstrue.toString('0 23 * * *');
const verbose = cronstrue.toString('0 23 * * *', { verbose: true });Verbose mode may add phrases such as every day. Snapshot important product copy because translation wording can evolve.
Format descriptions with a 24-hour clockuse-twenty-four-hour-time
const description = cronstrue.toString('23 14 * * SUN#2', {
use24HourTimeFormat: true,
});
console.log(description); // At 14:23, on the second Sunday of the monthSome translations already default to 24-hour time. Pass the option explicitly when the product requires a consistent clock style.
Load only the French localeload-one-locale
import cronstrue from 'cronstrue';
import 'cronstrue/locales/fr';
const description = cronstrue.toString('*/5 * * * *', { locale: 'fr' });Locale imports register translations through side effects. Make sure the import survives tree shaking before calling toString.
Load every bundled translationload-all-locales
import cronstrue from 'cronstrue/i18n';
const french = cronstrue.toString('0 9 * * 1-5', { locale: 'fr' });
const german = cronstrue.toString('0 9 * * 1-5', { locale: 'de' });The README puts the all-locales file at about 130 KB minified. Prefer individual locale modules in browser bundles.
Turn a parse failure into display textreturn-parse-error
const message = cronstrue.toString(userExpression, {
throwExceptionOnParseError: false,
});
showPreview(message);This catches conversion errors and returns the exception message, but it still is not complete cron validation and may expose technical copy to users.
Handle conversion errors explicitlycatch-parse-error
try {
const description = cronstrue.toString(userExpression);
showPreview(description);
} catch (error) {
showFieldError('This schedule cannot be described');
}throwExceptionOnParseError defaults to true. Keep a separate validator if acceptance by the target scheduler matters.
Interpret weekday one as Mondaymatch-weekday-indexing
const description = cronstrue.toString('* * * ? * 2-6/2', {
dayOfWeekStartIndexZero: false,
});The default is true, where weekday numbering starts at zero. Match this setting to the cron dialect that stores and executes the value.
Describe a cron expression from the shelldescribe-from-cli
npx cronstrue "*/15 9-17 * * MON-FRI"npx may download code when the package is not installed locally. Pin it in the project for repeatable scripts and restricted environments.
Alternatives
| Package | Registry | Pick it when |
|---|---|---|
| cron-parser | npm | Use it when validation and actual next or previous occurrence dates matter more than a friendly sentence |
| croner | npm | Use it when the application must calculate runs or execute scheduled callbacks across Node and browser-like runtimes |
| cron-fast | npm | Use it for a small TypeScript parser with timezone-aware date calculations across Node, Deno, Bun, workers, and browsers |