Back to Blog
A laptop displaying financial graphs and analytics on a desk with printed reports
Tutorial
September 28, 2026
11 min read

How to Build a Subscription Renewal Calendar for SaaS

By SimpleCalendarJS Team

SimpleCalendarJS~18 KB gzipped · Zero dependencies · Any framework

Every SaaS product eventually needs a subscription renewal calendar. Once you're managing more than a handful of customers, a database table of renewal dates isn't enough — your team needs a visual timeline showing which subscriptions renew this week, which trials expire next month, and which accounts are at risk of churning. Spreadsheets break. SaaS management platforms cost thousands per month. A custom subscription renewal calendar built into your own dashboard is the middle path that scales.

The build-vs-buy decision

The obvious first move is to adopt a subscription management platform. Chargebee starts free but jumps to $599/month on the Performance plan — and real-world costs reach $3,000–$8,000/month once you factor in overage fees (0.75% of billing volume) and add-ons like revenue recognition. Recurly charges $249+/month. CloudEagle.ai and Zluri handle renewal tracking but are built for IT procurement teams managing vendor subscriptions, not for SaaS companies tracking their own customers.

These platforms earn their price when you need full billing automation, dunning workflows, and multi-currency invoicing. But if your goal is narrower — show upcoming renewals on a calendar, let customer success reps click into accounts, and trigger reminders at key intervals — you don't need a $7,000/year platform. You need a calendar component wired to your existing subscription data.

ConcernSaaS platform (Chargebee, Recurly)Custom calendar
Cost$599–$8,000+/monthOne-time library cost or free
Data ownershipSubscription data synced to third partyEverything stays in your database
CustomisationLimited to vendor UI and webhooksFull control over views and behaviour
IntegrationAPI sync with your app (often fragile)Direct database queries
Time to shipDays (if it fits your model)Hours to days
Billing automationBuilt-in dunning, invoicing, retriesYou handle billing separately

If billing automation is the priority, use Chargebee or Recurly. If visibility into renewal timelines is the priority, build the calendar.

Choosing a calendar library

SaaS dashboards already carry auth, analytics, charts, and navigation. Adding a heavy calendar library compounds the load. Here's how the options compare for embedding a renewal calendar:

LibraryBundle Size (gzip)LicenseMonth/Week/Day ViewsDashboard Fit
FullCalendar~500 KB (full)Free core / paid premiumYesFeature-rich but heavy
DayPilot Pro~100 KB+Per-developer ($849+)YesCommercial license required
React Big Calendar~50 KB (+ React)MITYesReact-only
SimpleCalendarJS~18 KBFree personal / license req. commercialYesLightweight, framework-agnostic

For a dashboard widget whose job is to render coloured dots on dates and respond to clicks, ~18 KB beats ~500 KB — especially when your dashboard already loads React, a charting library, and your app bundle.

Building the renewal calendar

Step 1: Model the subscription-to-event mapping

Your database stores subscriptions. The calendar displays events. The mapping converts each subscription into something the calendar can render:

function subscriptionsToEvents(subscriptions) { const statusColors = { active: '#10b981', expiring_soon: '#f59e0b', trial: '#3b82f6', churned: '#ef4444', paused: '#6b7280', }; return subscriptions.map((sub) => ({ id: sub.id, title: `${sub.customerName} — ${sub.planName}`, start: new Date(sub.renewalDate), end: new Date(sub.renewalDate), color: statusColors[sub.status] || '#6b7280', })); }

Active subscriptions show in green, expiring-soon in amber, trials in blue, churned in red, and paused in grey. A quick glance at the calendar tells your team exactly where attention is needed — a cluster of amber dots on a single week means a wave of renewals is approaching.

Step 2: Mount the calendar in your dashboard

npm install simple-calendar-js
import SimpleCalendarJs from 'simple-calendar-js'; import 'simple-calendar-js/dist/simple-calendar-js.min.css'; const calendar = new SimpleCalendarJs('#renewal-calendar', { defaultView: 'month', locale: 'en-US', enabledViews: ['month', 'week'], fetchEvents: async (start, end) => { const res = await fetch( `/api/subscriptions?from=${start.toISOString()}&to=${end.toISOString()}` ); const subscriptions = await res.json(); return subscriptionsToEvents(subscriptions); }, onEventClick: (event) => { window.location.href = `/dashboard/customers/${event.id}`; }, onSlotClick: (date) => { console.log('No renewals on', date.toLocaleDateString()); }, });

Clicking a subscription opens the customer detail page. The fetchEvents callback fires on every calendar navigation, so the view always reflects live data. Month view gives the high-level timeline; week view zooms into busy renewal periods.

Step 3: Build the API endpoint

Your backend needs to return subscriptions within a date range. Here's a Node.js example with a SQL database:

app.get('/api/subscriptions', async (req, res) => { const { from, to } = req.query; const result = await db.query( `SELECT s.id, c.name AS customer_name, p.name AS plan_name, s.status, s.renewal_date, s.mrr FROM subscriptions s JOIN customers c ON c.id = s.customer_id JOIN plans p ON p.id = s.plan_id WHERE s.renewal_date BETWEEN $1 AND $2 ORDER BY s.renewal_date`, [from, to] ); res.json( result.rows.map((row) => ({ id: row.id, customerName: row.customer_name, planName: row.plan_name, status: row.status, renewalDate: row.renewal_date, mrr: row.mrr, })) ); });

Step 4: Flag expiring-soon subscriptions

The calendar is more useful when it proactively highlights subscriptions approaching renewal. A daily cron job (or a query in your fetchEvents callback) can flag subscriptions as expiring_soon when they enter the 30-day window:

async function flagExpiringSoon() { await db.query( `UPDATE subscriptions SET status = 'expiring_soon' WHERE status = 'active' AND renewal_date <= NOW() + INTERVAL '30 days' AND renewal_date > NOW()` ); }

This turns those calendar dots from green to amber 30 days before renewal, giving your customer success team a visual early warning. Combine this with email or Slack notifications at T-90, T-60, and T-30 days for a full renewal reminder pipeline — research shows that multi-touch reminder sequences at these intervals significantly reduce involuntary churn.

Step 5: Add MRR context to the calendar

A renewal date alone doesn't tell you the stakes. A $49/month subscription and a $4,900/month enterprise contract both show as a dot on the calendar. Add MRR to the event title so your team can prioritise:

function subscriptionsToEvents(subscriptions) { const statusColors = { active: '#10b981', expiring_soon: '#f59e0b', trial: '#3b82f6', churned: '#ef4444', paused: '#6b7280', }; return subscriptions.map((sub) => ({ id: sub.id, title: `$${sub.mrr}/mo — ${sub.customerName}`, start: new Date(sub.renewalDate), end: new Date(sub.renewalDate), color: statusColors[sub.status] || '#6b7280', })); }

Now the calendar reads like a revenue forecast. A week showing $12,400 in amber dots demands more attention than one showing $180.

Step 6: Theme the calendar for your dashboard

SaaS dashboards typically run a dark or neutral theme. Match the calendar to your existing design system with CSS custom properties:

#renewal-calendar .uc-calendar { --uc-primary: #6366f1; --uc-bg: #0f172a; --uc-border: #1e293b; --uc-text: #e2e8f0; --uc-radius: 8px; font-family: 'Inter', -apple-system, sans-serif; }

When SaaS platforms make more sense

A custom renewal calendar covers visibility — seeing what's coming and clicking into it. SaaS billing platforms cover automation — the things that happen without human intervention:

  • Dunning and payment retries: About 50% of customers will need to update their payment info at some point. Chargebee and Recurly automatically retry failed charges, send card-expiration emails, and recover revenue that would otherwise churn silently
  • Revenue recognition: If you need ASC 606-compliant revenue reporting, platforms like Maxio (formerly SaaSOptics + Chargify) handle deferred revenue calculations
  • Multi-currency invoicing: Global SaaS products need localised invoicing, tax calculation, and currency conversion — billing platforms handle this out of the box

If your renewal calendar is the first step toward a full billing overhaul, start with the calendar to prove the concept, then evaluate whether a platform's automation features justify the $7,000+/year cost.

Summary

  • SaaS billing platforms like Chargebee ($599+/month) and Recurly ($249+/month) solve billing automation but are overkill if you only need renewal visibility
  • Your subscription database already has the data a calendar needs — customer name, plan, status, and renewal date — the missing piece is the visual layer
  • FullCalendar (~500 KB) adds unnecessary weight to an already-heavy SaaS dashboard; SimpleCalendarJS renders the same month/week views at ~18 KB gzipped
  • Colour-code subscriptions by status (active, expiring, trial, churned) and include MRR in event titles so the calendar doubles as a revenue forecast
  • Add a daily job to flag subscriptions entering the 30-day renewal window and trigger multi-touch reminders at T-90, T-60, and T-30 to reduce involuntary churn

Sources & Further Reading

Research & References

Image Credits

All images free to use under the Pexels License.

Frequently Asked Questions

What is a subscription renewal calendar?

A subscription renewal calendar is a visual dashboard component that plots every customer subscription on a timeline by its renewal date. It gives SaaS teams a scannable view of upcoming renewals, expiring trials, and at-risk accounts — replacing spreadsheets and manual tracking with an interactive calendar UI.

Should I build a custom renewal calendar or use a SaaS management platform?

If your app already stores subscription data (plan, status, renewal date) and you want the calendar embedded in your own admin dashboard, building a custom calendar with a lightweight JavaScript library is cheaper and gives you full control. Platforms like Chargebee ($599+/month) or CloudEagle make sense when you need billing automation, dunning, and revenue recognition across dozens of vendors.

How do I colour-code subscriptions by status on a calendar?

Map each subscription status to a colour when converting subscription records to calendar events. For example, active subscriptions in green, expiring-soon in amber, churned in red, and trial accounts in blue. Pass the colour as part of each event object so the calendar renders them visually distinct.

Can I add renewal reminders at 90, 60, and 30 days before expiry?

Yes. Query your subscriptions database for records whose renewal date falls within each reminder window, then create calendar events (or trigger emails and Slack notifications) at those intervals. A scheduled job running daily can check for subscriptions entering each window and fire the appropriate reminder.

What JavaScript calendar library is best for a SaaS subscription dashboard?

It depends on your stack and performance budget. FullCalendar (~500 KB full bundle) has the most features but adds significant weight to an already-heavy SaaS dashboard. SimpleCalendarJS (~18 KB gzipped) provides month, week, and day views with event rendering and click handlers — enough for a renewal calendar without the overhead.

Add a calendar to your app today

Free for personal projects. $49/year or $199 lifetime per commercial project.