A production-minded Apple CalDAV / iCloud to Google Calendar synchronization daemon.
Calendar Sync is a bidirectional background service that keeps Apple Calendar through CalDAV/iCloud and Google Calendar aligned. It preserves core event metadata, supports multiple calendar pairs, resolves conflicts deterministically, and is ready to run as a long-lived PM2 process.
This project was built by Mattia Beltrami, a Computer Engineering student at Politecnico di Milano, as part of a personal portfolio focused on practical, well-engineered automation tools.
- Bidirectional sync between Apple CalDAV/iCloud calendars and Google Calendar.
- Multiple calendar mappings through parallel Apple and Google calendar lists.
- Conflict handling based on the most recently modified event, with Apple as the deterministic tie-breaker.
- Event fidelity for title, description, location, start/end time, all-day events, categories, color metadata, and links.
- Deletion propagation using persisted sync state to detect events removed on either side.
- PM2-friendly runtime for always-on deployment.
- Typed TypeScript codebase with focused unit tests for calendar parsing and conflict behavior.
Calendar Sync periodically reads a configurable time window from both providers, normalizes events into a shared internal shape, and compares matching events by UID. Each Apple calendar URL is paired with the Google calendar ID in the same position of the configuration lists.
When an event exists on both sides, the service compares the normalized payload and updates the older copy. When an event exists only on one side, persisted state is used to decide whether the event is new and should be copied, or whether it was deleted on the opposite side and should be removed.
Apple Calendar / iCloud (CalDAV)
|
v
Calendar Sync daemon
|
v
Google Calendar API
- Runtime: Node.js 18+
- Language: TypeScript
- Apple side: CalDAV via
tsdavandical.js - Google side: Google Calendar API via
googleapis - Logging:
pino - Process manager: PM2
- Testing: Vitest
npm install
cp .env.example .env
npm run build
npm startFor development:
npm run devFor tests:
npm testCreate a .env file from .env.example and fill in the required values.
| Variable | Description |
|---|---|
APPLE_CALDAV_URL |
Apple CalDAV base URL. Defaults to https://caldav.icloud.com. |
APPLE_USERNAME |
Apple ID used for CalDAV authentication. |
APPLE_APP_PASSWORD |
Apple app-specific password. |
APPLE_CALENDAR_URLS |
Comma-separated CalDAV calendar URLs. |
GOOGLE_SERVICE_ACCOUNT_EMAIL |
Google service account email. |
GOOGLE_SERVICE_ACCOUNT_KEY |
Google service account private key, with escaped \n line breaks. |
GOOGLE_CALENDAR_IDS |
Comma-separated Google calendar IDs. |
SYNC_INTERVAL_MINUTES |
Minutes between sync cycles. Defaults to 5. |
SYNC_WINDOW_DAYS |
Past and future event window to scan. Defaults to 180. |
TZ |
Timezone used for timed events. Defaults to UTC. |
LOG_LEVEL |
Pino log level. Defaults to info. |
Calendar mappings are positional:
APPLE_CALENDAR_URLS[0] <-> GOOGLE_CALENDAR_IDS[0]
APPLE_CALENDAR_URLS[1] <-> GOOGLE_CALENDAR_IDS[1]
npm run build
pm2 start dist/index.js --name calendar-sync
pm2 saveUseful PM2 commands:
pm2 logs calendar-sync
pm2 restart calendar-sync
pm2 stop calendar-sync- Create or select a Google Cloud project.
- Enable the Google Calendar API.
- Create a service account.
- Generate a JSON key and copy the service account email/private key into
.env. - Share each target Google Calendar with the service account email and grant write permissions.
- Create an Apple app-specific password for the Apple ID.
- Find the CalDAV calendar URLs for the calendars you want to sync.
- Add those URLs to
APPLE_CALENDAR_URLSin the same order as the matching Google calendar IDs.
npm install
npm run dev
npm test
npm run buildThe code is organized around provider clients, shared event types, normalization utilities, and a sync service that owns conflict resolution and propagation.
src/
clients/ Provider integrations
sync/ Sync orchestration and conflict logic
utils/ iCalendar parsing and persisted sync state
config.ts Environment-based configuration
index.ts Runtime bootstrap
Calendar Sync is designed as a practical systems project rather than a toy demo: it handles real provider APIs, long-running process concerns, deterministic conflict behavior, and stateful synchronization. It represents the kind of engineering Mattia Beltrami is interested in building: reliable automation that turns a daily workflow problem into maintainable software.
MIT. See LICENSE.
