Recurring events
Author with the fluent builder (recommended) — it compiles to the plain config the engine stores and exports.
import { calendary } from "calendaryjs";import { every, weekly, monthly, date, nth } from "calendaryjs/builder";
const cal = calendary();
cal.add( every("year").on(date(12, 25)).title("Christmas"), // every Dec 25 weekly("monday").title("Standup"), // every Monday every(2, "weeks").on("tuesday").title("Biweekly sync"), // every other Tuesday monthly(-1).title("Rent"), // last day of every month every("month").on(nth(1, "monday")).title("Retro"), // 1st Monday of the month every("month").on(nth(-1, "friday")).title("Payday"), // last Friday of the month every(3, "days").title("Water the plants"), // every 3 days);
cal.getEventsInRange("2026-01-01", "2026-01-31").map(e => `${e.date} · ${e.title}`);Ending a series
Section titled “Ending a series”Recurrences are infinite by default — bound them three ways:
// After N occurrences (like RRULE COUNT) — needs a start to count from:cal.add(weekly("tuesday").starting("2026-09-01").times(10).title("Course")); // 10 classes
// Between two dates (inclusive):cal.add(every("week").on("wednesday").between("2026-06-01", "2026-08-31").title("Summer class"));
// Every Nth year, phased from a start year:cal.add(every(4, "years").on(date(6, 1)).starting(2024).title("Reunion")); // 2024, 2028, …Prefer plain objects? Every builder is just sugar for a config — the same shape a
.cdy stores. See Event types for every field and
Building events for the full grammar.