A food rescue posted a question in the Quickbase community that applies to almost any recurring schedule. They have partner sites that come to pick up food. Most sites come every week on the same day (say, every Tuesday). A few come once a month on a pattern like "the fourth Thursday." They already have a Sites table with each site's pickup day, and they wanted a calendar that shows every site on every day it's due, like the one they'd been keeping by hand in Excel.
Here's the original thread: Ongoing Schedule Calendar on the Quickbase community.
The short answer: a Quickbase calendar report shows each record once, on its date. It won't repeat a site record every Tuesday. So you need one record per pickup. Below is a full build: a Pickup Day and Week of Month on each site, a small Calendar Dates table that does the date math with two formulas, a monthly pipeline that creates next month's Pickup records, and a calendar report on top. I built and tested it in a sandbox app, and the results are further down.
Why a calendar report alone can't do this
Calendar reports place a record on the date in its date field. One site record has no date at all. It has a rule ("Tuesdays" or "fourth Thursday"), and Quickbase reports don't expand rules into dates.
You could try one big formula that works out "the next pickup date" for each site, but that only gives you one date per site, and the calendar would show a single entry per site instead of four or five Tuesdays.
Real records per pickup are better anyway:
- The calendar shows every pickup, every week.
- Holidays and one-off changes are just edits. Move one pickup to Wednesday and the rest of the schedule stays the same.
- You can add fields to a pickup later (who handled it, pounds picked up, no-show) and report on them.
Step 1: Add the schedule fields to Sites
On your Sites table, add two fields:
| Field | Type | What goes in it |
|---|---|---|
| Pickup Day | Text - Multiple Choice | Monday, Tuesday, Wednesday, Thursday, Friday, Saturday, Sunday |
| Week of Month | Numeric | Leave blank for weekly sites. Enter 4 for "fourth Thursday", 1 for "first Monday", and so on |
So a site that comes every Tuesday is Pickup Day = Tuesday, Week of Month = blank. A site that comes the fourth Thursday is Pickup Day = Thursday, Week of Month = 4.
Spell the choices exactly as shown (full day names, capitalized). The pipeline compares them to a formula in the next step, so "Tues" won't match "Tuesday".
Step 2: Create a Calendar Dates table
This table is a plain list of dates, one record per day. It's what lets the pipeline ask "which dates next month are Tuesdays?" without any tricky date math in the pipeline itself.
- Create a new table called Calendar Dates.
- Add a Date field (type Date).
- Add these formula fields:
Day Name (Formula - Text):
Case(DayOfWeek([Date]),
0, "Sunday",
1, "Monday",
2, "Tuesday",
3, "Wednesday",
4, "Thursday",
5, "Friday",
6, "Saturday")
DayOfWeek() returns 0 for Sunday through 6 for Saturday, and the Case turns that into the same names you used for Pickup Day.
Week of Month (Formula - Numeric):
Int((Day([Date]) - 1) / 7) + 1
Days 1 to 7 are week 1, days 8 to 14 are week 2, and so on. That's exactly how people mean "the fourth Thursday": the fourth Thursday always falls on day 22 to 28, which this formula calls week 4. Week 5 covers days 29 to 31, so "fifth Friday" works too, in the months that have one.
In Next Month (Formula - Checkbox):
[Date] >= FirstDayOfMonth(AdjustMonth(Today(), 1))
and [Date] <= LastDayOfMonth(AdjustMonth(Today(), 1))
This is checked for every date in next month, whatever month you're in now. It saves the pipeline from having to calculate the start and end of next month.
- Load the dates once. In Excel or Google Sheets, type a start date in A1, fill down for the rest of the year (or two years), save as CSV, and use Import/Export > Import from a file to bring it into Calendar Dates, mapping the column to Date. That's 365 records a year, which is tiny. Add a reminder to load the next year before December.
Step 3: Create the Pickups table
Create a Pickups table with:
- Pickup Date (Date)
- Notes (Text), handy for "moved for the holiday" notes
- A relationship to Sites: Sites is the parent, Pickups is the child. Name the reference field Related Site and add a lookup of Site Name.
Each Pickup record is one site coming in on one day.
Step 4: Build the monthly pipeline
This pipeline runs once a month and creates next month's Pickup records. It doesn't need a trigger. Pipelines that start with a search step can run on a schedule.
Step A: Search Records on Sites
- Channel: Quickbase, step Search Records.
- Table: Sites.
- Add a filter if you track inactive sites (for example, Status is not Inactive). Otherwise leave it unfiltered.
- In the fields to return, include Record ID#, Pickup Day, and Week of Month.
Pipelines adds a loop automatically. Everything below goes inside it, so it runs once per site.
Step B: Search Records on Calendar Dates (inside step A's loop)
This step does the matching. Add Search Records on Calendar Dates, switch the query to code mode (the Advanced Query box), and use:
{9.EX.'1'}AND{7.EX.'{{a.pickup_day}}'}AND{8.GTE.'{{a.week_of_month | default(1, true)}}'}AND{8.LTE.'{{a.week_of_month | default(5, true)}}'}
Replace the numbers with your own field IDs on Calendar Dates. In my app they were:
| Field ID | Field |
|---|---|
| 7 | Day Name |
| 8 | Week of Month |
| 9 | In Next Month |
You'll find yours under Settings > Fields on the table. The query reads like this:
{9.EX.'1'}: In Next Month is checked (checkboxes are1in a query).{7.EX.'{{a.pickup_day}}'}: Day Name equals this site's Pickup Day.- The last two parts are the Week of Month filter. For a monthly site with Week of Month = 4, they become "Week of Month ≥ 4 and ≤ 4", so only the fourth week matches. For a weekly site the field is blank, and
default(1, true)/default(5, true)fill in 1 and 5, so the range becomes "week 1 through 5", which is every week.
That range trick means one query handles both weekly and monthly sites, with no IF/ELSE branch in the pipeline. The Jinja sits only inside the quoted values, which is how Quickbase supports Jinja in a query.
Return the Date field from this step. Pipelines adds another loop for these results.
Step C: Create Record in Pickups (inside step B's loop)
Add Create Record on Pickups and map:
| Pickups field | Value |
|---|---|
| Related Site | {{a.id}} |
| Pickup Date | {{b.date}} |
Check the step letters in your own pipeline. If you added steps in a different order, the letters will be different.
Schedule it
Open the pipeline's schedule settings and set it to run monthly, on a day before the month ends (for example, the 20th at 6:00 AM). That gives you about ten days to see next month's schedule and fix holidays before it starts.
Turn it on. For the current month, either enter the pickups by hand or make a one-time copy of the pipeline that uses an "In This Month" checkbox (the same formula with Today() in place of AdjustMonth(Today(), 1)) and run it once.
Step 5: Add the calendar report
On Pickups, create a new report and choose Calendar:
- Start date: Pickup Date
- Label: Site Name (the lookup)
- Optionally, color-code by site using report color settings, so each site stands out.
Put the report on your dashboard and you have the shared calendar from the Excel file, kept up to date automatically.
What I saw when I tested it
I built this in a sandbox app with four sites, a Calendar Dates table loaded from October 2026 through December 2027, and a Pickups table. Then I ran the same searches the pipeline does, rendering the query exactly as the Jinja would for each site:
| Site | Pickup Day | Week of Month | Query values used | November 2026 dates found |
|---|---|---|---|---|
| Northside Pantry | Tuesday | blank | week 1 to 5 | Nov 3, 10, 17, 24 |
| Grace Kitchen | Thursday | 4 | week 4 to 4 | Nov 26 |
| Eastside Youth Center | Saturday | blank | week 1 to 5 | Nov 7, 14, 21, 28 |
| Riverside Senior Center | Monday | 1 | week 1 to 1 | Nov 2 |
That created 10 Pickup records, one per site per date. Nov 26, 2026 is Thanksgiving, which is the fourth Thursday, so it's a good real example of a holiday. I opened that one Pickup record, changed the date to Nov 25 and added a note, and nothing else in the schedule changed.
A couple of things I checked along the way:
- The In Next Month checkbox returned exactly the 30 days of November.
- Pipelines can pass a numeric field like Week of Month as
4.0rather than4. That's fine. The query compares numbers, so4.0matches week 4.
Holidays and one-off changes
Because every pickup is its own record, there's no special holiday logic to build:
- Moved pickup: open the Pickup record and change the date. Add a note so people know why.
- Cancelled pickup: delete the record, or add a Status field (Scheduled, Cancelled, Completed) and filter Cancelled out of the calendar.
- Extra pickup: add a Pickup record by hand.
- Site changes its day: update the site. Next month's run uses the new day. Fix any already-created future pickups by hand, or delete them and let the next run recreate them.
Variations and tips
- "Last Thursday of the month." Week 4 isn't always the last week (some months have a fifth Thursday). Add a Last Week of Month checkbox formula to Calendar Dates:
Day([Date]) + 7 > Day(LastDayOfMonth([Date])). Give Sites a matching Last Week Only checkbox. Then copy the pipeline: in the copy, step A searches only sites with Last Week Only checked, and step B's query uses the new field instead of the week range, for example{9.EX.'1'}AND{7.EX.'{{a.pickup_day}}'}AND{10.EX.'1'}(10 being the new field's ID). In the original pipeline, filter those sites out of step A. - Every other week. Add a Week Parity formula (Numeric) to Calendar Dates that flips between 1 and 2 each week:
Mod(Int(ToDays([Date] - Date(2026, 1, 4)) / 7), 2) + 1. (January 4, 2026 is just a Sunday to count from.) On Sites, add a numeric Alternate Week field and enter 1 or 2, whichever matches the site's first pickup. Then add the same range trick to the query:AND{11.GTE.'{{a.alternate_week | default(1, true)}}'}AND{11.LTE.'{{a.alternate_week | default(2, true)}}'}. Sites with the field blank still match every week. (Use 1 and 2 rather than 0 and 1: Jinja'sdefault(..., true)treats 0 as blank.) - Don't double up if it runs twice. If someone runs the pipeline by hand after the scheduled run, you'll get duplicates. To make reruns safe, add a Unique text field called Pickup Key to Pickups and replace Create Record with the bulk upsert steps (Prepare Bulk Record Upsert, Add a Bulk Upsert Row, Commit Upsert), using Pickup Key as the merge field and setting it to
{{a.id}}-{{b.date}}. A second run then updates the same records instead of adding new ones. - Keep the pipeline small. Return only the fields you need from each search. Four or five fields per step is plenty.
Wrapping up
The key change is to stop asking a calendar report to repeat a record and give it real records instead. Sites hold the rule (Pickup Day plus an optional Week of Month), Calendar Dates does the date math with DayOfWeek() and Int((Day([Date]) - 1) / 7) + 1, and one scheduled pipeline turns the rules into next month's Pickup records with a single search query. After that, the calendar report is just a calendar, and holidays are ordinary edits.