How to Create Powerful Advanced Recurring Tasks in Notion
If you're a student, professional, or productivity lover who's wanted your Notion task manager to truly handle recurring tasks—think "every third Thursday," "last weekday of the month," or "Mon/Wed/Fri"—this guide is for you! I'll walk you through step-by-step, from database properties to automation, so you can set up a flexible, smart recurring system in Notion.
Step 1: Set Up Your Database Properties
Before we dive into the magic formulas, make sure your database has the following properties (with these exact names for the formulas to work):
| Property Name | Type | | --- | --- | | Status | Status | | Due | Date | | Recur Interval | Number | | Recur Unit | Select | | Days | Multi-Select | | Localization Key | Formula | | Next Due | Formula |
Tip: For a full walkthrough, check out video guides or FAQ sections (there are great visuals, but this article gives you a concise breakdown).
Step 2: Set Up Your Recurring Options
In your "Recur Unit" property, add these options:
- Day(s)
- Week(s)
- Month(s)
- Year(s)
- Month(s) on the Last Day
- Month(s) on the First Weekday
- Month(s) on the Last Weekday
- Nth Weekday of Month
For "Days" property:
Add each day of the week as options (Monday, Tuesday, etc.).
How These Work in Practice
- Multiple Days: Want a task to recur on Mon/Wed/Fri? Choose "Day(s)" and select your days.
- Nth Weekday: Want "every 3rd Thursday"? Set Recur Interval = 3, Recur Unit = "Nth Weekday of Month", Days = Thursday.
Step 3: Localization for Global Use
Add this formula to your Localization Key property, which allows you to customize language for weekdays, statuses, and units:
[
/* Rewrite these weekday and recur unit options in your own language, so your second brain can work even better with your first. Make sure to set up the same options in the "Recur Unit" and "Days" properties afterward, so you can select them. Feel free to remove the original names afterward! */
/* ["lunes", "3ª", "mercredi", "木曜日", "piątek", "lørdag", "Double Sunday"] */
["Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"],
/* ["Day(s)", "Week(s)", "Month(s)", "Year(s)", "Month(s) on the Last Day", "Month(s) on the First Weekday", "Month(s) on the Last Weekday", "Nth Weekday of Month"] */
["Day(s)", "Week(s)", "Month(s)", "Year(s)", "Month(s) on the Last Day", "Month(s) on the First Weekday", "Month(s) on the Last Weekday", "Nth Weekday of Month"],
/* This final list is for Status option names. */
["To Do", "Doing", "Done"]
]
Customize the values if you prefer another language or terminology—just be sure to sync the names with your select/multi-select property options.
Step 4: The Advanced "Next Due" Formula
Paste this advanced formula into your Next Due property. This formula calculates your next recurring date, including overdue date logic, custom intervals, and "fancy" patterns (like last weekday of each month).
lets(
version, "2.2.0",
dueProp, prop("Due"),
recurIntervalProp, prop("Recur Interval"),
recurUnitProp, prop("Recur Unit"),
localizationKeyProp, prop("Localization Key"),
daysProp, prop("Days"),
emptyDate, parseDate(""),
if(!empty(recurIntervalProp) and !empty(dueProp),
if(recurIntervalProp > 0 and recurIntervalProp == ceil(recurIntervalProp),
lets(
recurUnit,
ifs(
or(recurUnitProp == at(at(localizationKeyProp, 1), 0), recurUnitProp == "Day(s)"), "days",
or(recurUnitProp == at(at(localizationKeyProp, 1), 1), recurUnitProp == "Week(s)"), "weeks",
or(recurUnitProp == at(at(localizationKeyProp, 1), 2), recurUnitProp == "Month(s)"), "months",
or(recurUnitProp == at(at(localizationKeyProp, 1), 3), recurUnitProp == "Year(s)"), "years",
or(recurUnitProp == at(at(localizationKeyProp, 1), 4), recurUnitProp == "Month(s) on the Last Day"), "monthsonthelastday",
or(recurUnitProp == at(at(localizationKeyProp, 1), 5), recurUnitProp == "Month(s) on the First Weekday"), "monthsonthefirstweekday",
or(recurUnitProp == at(at(localizationKeyProp, 1), 6), recurUnitProp == "Month(s) on the Last Weekday"), "monthsonthelastweekday",
or(and(!empty(at(at(localizationKeyProp, 1), 7)), recurUnitProp == at(at(localizationKeyProp, 1), 7)), recurUnitProp == "Nth Weekday of Month"), "nthweekday",
"days"
),
weekdays,
match(
[
if(or(includes(daysProp, at(at(localizationKeyProp, 0), 1 - 1)), includes(daysProp, "Monday")), 1, false),
if(or(includes(daysProp, at(at(localizationKeyProp, 0), 2 - 1)), includes(daysProp, "Tuesday")), 2, false),
if(or(includes(daysProp, at(at(localizationKeyProp, 0), 3 - 1)), includes(daysProp, "Wednesday")), 3, false),
if(or(includes(daysProp, at(at(localizationKeyProp, 0), 4 - 1)), includes(daysProp, "Thursday")), 4, false),
if(or(includes(daysProp, at(at(localizationKeyProp, 0), 5 - 1)), includes(daysProp, "Friday")), 5, false),
if(or(includes(daysProp, at(at(localizationKeyProp, 0), 6 - 1)), includes(daysProp, "Saturday")), 6, false),
if(or(includes(daysProp, at(at(localizationKeyProp, 0), 7 - 1)), includes(daysProp, "Sunday")), 7, false)
],
"[1-7]"
),
dateDue, parseDate(formatDate(dueProp, "YYYY-MM-DD")),
timeNow, now(),
dateNow, parseDate(formatDate(timeNow, "YYYY-MM-DD")),
hasRange, dateEnd(dueProp) > dateStart(dueProp),
recurUnitLapseLength,
if(
includes(["days", "weeks", "months", "years"], recurUnit),
dateBetween(dateNow, dateDue, recurUnit) / recurIntervalProp,
false
),
lastDayBaseDate,
if(
includes(["monthsonthelastday", "monthsonthefirstweekday", "monthsonthelastweekday"], recurUnit),
if(
year(dateNow) * 12 + month(dateNow) - (year(dateDue) * 12 + month(dateDue)) > 0,
dateSubtract(dateAdd(dateSubtract(dateAdd(dateDue, ceil((year(dateNow) * 12 + month(dateNow) - (year(dateDue) * 12 + month(dateDue))) / recurIntervalProp) * recurIntervalProp, "months"), date(dateAdd(dateDue, ceil((year(dateNow) * 12 + month(dateNow) - (year(dateDue) * 12 + month(dateDue))) / recurIntervalProp) * recurIntervalProp, "months")) - 1, "days"), 1, "months"), 1, "days"),
dateSubtract(dateAdd(dateSubtract(dateAdd(dateDue, recurIntervalProp, "months"), date(dateAdd(dateDue, recurIntervalProp, "months")) - 1, "days"), 1, "months"), 1, "days")
),
emptyDate
),
firstDayBaseDate,
if(
lastDayBaseDate != emptyDate,
dateSubtract(lastDayBaseDate, date(lastDayBaseDate) - 1, "days"),
emptyDate
),
firstWeekdayBaseDate,
if(
lastDayBaseDate != emptyDate,
if(
test(day(firstDayBaseDate), "6|7"),
dateAdd(firstDayBaseDate, 8 - day(firstDayBaseDate), "days"),
firstDayBaseDate
),
emptyDate
),
lastWeekdayBaseDate,
if(
lastDayBaseDate != emptyDate,
if(
test(day(lastDayBaseDate), "6|7"),
dateSubtract(lastDayBaseDate, day(lastDayBaseDate) - 5, "days"),
lastDayBaseDate
),
emptyDate
),
nextLastBaseDate,
if(
lastDayBaseDate != emptyDate,
dateSubtract(dateAdd(dateSubtract(dateAdd(lastDayBaseDate, recurIntervalProp, "months"), date(dateAdd(lastDayBaseDate, recurIntervalProp, "months")) - 1, "days"), 1, "months"), 1, "days"),
emptyDate
),
nextFirstBaseDate,
if(
lastDayBaseDate != emptyDate,
dateSubtract(nextLastBaseDate, date(nextLastBaseDate) - 1, "days"),
emptyDate
),
nextFirstWeekday,
if(
lastDayBaseDate != emptyDate,
if(
test(day(nextFirstBaseDate), "6|7"),
dateAdd(nextFirstBaseDate, 8 - day(nextFirstBaseDate), "days"),
nextFirstBaseDate
),
emptyDate
),
nextLastWeekday,
if(
lastDayBaseDate != emptyDate,
if(
test(day(nextLastBaseDate), "6|7"),
dateSubtract(nextLastBaseDate, day(nextLastBaseDate) - 5, "days"),
nextLastBaseDate
),
emptyDate
),
firstWeekSpecificDayBaseDate,
lets(
baseMonthDate,
if(
timeNow > dueProp,
timeNow,
dueProp
),
weekday, toNumber(at(weekdays, 0)),
firstDayOfNextMonth, dateSubtract(dateAdd(baseMonthDate, 1, "months"), date(baseMonthDate) - 1, "days"),
ifs(
day(firstDayOfNextMonth) < weekday, dateAdd(firstDayOfNextMonth, weekday - day(firstDayOfNextMonth), "days"),
day(firstDayOfNextMonth) > weekday, dateAdd(firstDayOfNextMonth, weekday - day(firstDayOfNextMonth) + 7, "days"),
firstDayOfNextMonth
)
),
nthWeekdayBaseDate, dateAdd(firstWeekSpecificDayBaseDate, recurIntervalProp - 1, "weeks"),
nextDueStart,
ifs(
recurUnit == "days" and length(weekdays) > 0 and recurIntervalProp == 1,
if(
dateNow >= dateDue,
ifs(
includes(weekdays, format(day(dateAdd(dateNow, 1, "days")))), dateAdd(dateNow, 1, "days"),
includes(weekdays, format(day(dateAdd(dateNow, 2, "days")))), dateAdd(dateNow, 2, "days"),
includes(weekdays, format(day(dateAdd(dateNow, 3, "days")))), dateAdd(dateNow, 3, "days"),
includes(weekdays, format(day(dateAdd(dateNow, 4, "days")))), dateAdd(dateNow, 4, "days"),
includes(weekdays, format(day(dateAdd(dateNow, 5, "days")))), dateAdd(dateNow, 5, "days"),
includes(weekdays, format(day(dateAdd(dateNow, 6, "days")))), dateAdd(dateNow, 6, "days"),
includes(weekdays, format(day(dateAdd(dateNow, 7, "days")))), dateAdd(dateNow, 7, "days"),
emptyDate
),
ifs(
includes(weekdays, format(day(dateAdd(dateDue, 1, "days")))), dateAdd(dateDue, 1, "days"),
includes(weekdays, format(day(dateAdd(dateDue, 2, "days")))), dateAdd(dateDue, 2, "days"),
includes(weekdays, format(day(dateAdd(dateDue, 3, "days")))), dateAdd(dateDue, 3, "days"),
includes(weekdays, format(day(dateAdd(dateDue, 4, "days")))), dateAdd(dateDue, 4, "days"),
includes(weekdays, format(day(dateAdd(dateDue, 5, "days")))), dateAdd(dateDue, 5, "days"),
includes(weekdays, format(day(dateAdd(dateDue, 6, "days")))), dateAdd(dateDue, 6, "days"),
includes(weekdays, format(day(dateAdd(dateDue, 7, "days")))), dateAdd(dateDue, 7, "days"),
emptyDate
)
),
recurUnit == "nthweekday" and length(weekdays) == 1 and recurIntervalProp >= 1 and recurIntervalProp <= 5,
if(
month(nthWeekdayBaseDate) == month(firstWeekSpecificDayBaseDate),
nthWeekdayBaseDate,
dateSubtract(nthWeekdayBaseDate, 1, "week")
),
recurUnit == "monthsonthelastday",
if(
dateNow >= lastDayBaseDate,
nextLastBaseDate,
lastDayBaseDate
),
recurUnit == "monthsonthefirstweekday",
if(
dateNow >= firstWeekdayBaseDate,
nextFirstWeekday,
firstWeekdayBaseDate
),
recurUnit == "monthsonthelastweekday",
if(
dateNow >= lastWeekdayBaseDate,
nextLastWeekday,
lastWeekdayBaseDate
),
includes(["days", "weeks", "months", "years"], recurUnit),
if(
dateBetween(dateNow, dateDue, "days") >= 1,
if(
recurUnitLapseLength == ceil(recurUnitLapseLength),
dateAdd(dateDue, (recurUnitLapseLength + 1) * recurIntervalProp, recurUnit),
dateAdd(dateDue, ceil(recurUnitLapseLength) * recurIntervalProp, recurUnit)
),
dateAdd(dateDue, recurIntervalProp, recurUnit)
),
emptyDate
),
recurRange, dateBetween(nextDueStart, dateDue, "days"),
timeNextDueStart, dateAdd(dateStart(dueProp), recurRange, "days"),
timeNextDueEnd, dateAdd(dateEnd(dueProp), recurRange, "days"),
nextDue,
if(
hasRange,
dateRange(timeNextDueStart, timeNextDueEnd),
timeNextDueStart
),
nextDue
),
dueProp
),
emptyDate
)
)
This formula is lengthy but essential; ensure your property names are a perfect match!
Step 5: Automate Your Recurring Tasks
Now, let's process these tasks automatically when you finish them.
- Create a filtered view called "Recurring Tasks":
- Filter: Due is not empty AND Recur Interval >= 1
- Create a database automation:
-
Trigger: Status is set to Complete
-
Action 1: Set Status back to "Not Started"
-
Action 2: Set Due property to a Formula:
context("Trigger page").prop("Next Due")
-
This references the "Next Due" property, updating your task's due date automatically using your mega-formula.
-
Pro Tip: Always use formula properties for heavy logic so you can easily audit outputs and troubleshoot!
Why This Matters
With this system, your Notion workspace handles virtually any recurring task scenario—helpful whether you're a student, a professional with complex deadlines, or building a spiritual habit tracker. You can set tasks to repeat in nearly every pattern you might need—automatically!
As a Notion creator and civil engineer, I know how much time smart design can save. With this setup, you can spend less time fiddling with dates, and more time focusing on the tasks that matter.
Final Thoughts & Next Steps
This is just the foundation! Consider adding a task history log, more automation (for notifications, for example), or connecting your recurring setup with dashboards for a holistic productivity workflow.
Curious about specific use cases, or need troubleshooting help on formulas or automations? Drop your questions in the comments, or check out my Notion productivity resources for templates designed for students, professionals, and Muslims who want to organize, learn, and grow—all in one place.
Happy organizing,
Mostafa Yasser
Get Started Today
The path to clarity and success begins with a single template. Click below to unlock the full Second Brain experience: