Skip to content

Why I Built a Native Google Calendar App for Mac

Why I built hora as a native Mac client for Google Calendar, chose the official API over CalDAV, and kept Google as the source of truth.

7 min read
A native Mac calendar architecture connecting SwiftUI directly to Google Calendar through an authenticated sync layer

For years, my calendar setup followed the same loop. I would try a Mac app, enjoy the native window for a while, then return to a Google Calendar tab because that was where my schedule actually lived.

The existing apps were not bad. They were solving a broader problem than mine.

I did not need one calendar for Google, iCloud, Exchange, tasks, email, and an entire productivity system. I wanted Google Calendar to remain the source of truth, with a fast Mac app around it. That narrower frustration became hora Calendar.

This post started as a build note on March 26, 2026. hora eventually reached the Mac App Store on June 30. I am updating the note now because the original idea survived, but the way I explain it has become much more precise.

The problem was not a missing calendar website

Google Calendar on the web is capable and complete. It is also one tab among many.

That distinction matters when the calendar stays open all day. Checking the next meeting, moving an event, or protecting an hour of focus time should feel like using the Mac, not like locating the correct browser context first.

Apple Calendar solves the native-window part and supports Google accounts. Multi-provider apps go further by bringing several calendar ecosystems into one polished interface. Those are sensible choices if your schedule is spread across services.

My own setup was simpler:

  • Every important calendar was in Google.
  • I wanted Google-specific event behavior to survive intact.
  • I cared about keyboard commands, the menu bar, widgets, notifications, and normal Mac window behavior.
  • I did not want another web interface disguised as a desktop app.

The opportunity was not "build a better calendar for everyone." It was "make Google Calendar feel at home on macOS."

The first product decision was what not to support

hora is focused on Google Calendar. It does not combine iCloud, Exchange, and general CalDAV accounts in one app.

That is a real limitation, not a line of marketing copy. It also keeps the product honest. I can design around Google's event model instead of flattening several providers into the smallest set of features they share.

Conference links, attendee responses, event colors, blocking events, recurring-event rules, and account ownership all have details that matter. A calendar can look correct while quietly losing one of those details during synchronization.

Choosing one provider gave me room to care about that layer.

If you need every calendar provider in one window, Apple Calendar, Fantastical, or BusyCal will probably fit better. If Google Calendar already runs your day, a focused client starts to make sense.

Why hora talks to the Google Calendar API directly

I chose the official Google Calendar API instead of using CalDAV as a common translation layer.

The API gives hora access to Google's own event representation and synchronization model. Google's documented incremental synchronization flow starts with a full sync, returns a token, then uses that token to request only subsequent changes. That became the foundation for keeping a local cache current without downloading the entire calendar on every refresh.

The shape of the app is straightforward:

  1. Google Calendar remains the source of truth.
  2. hora fetches events directly from Google's API.
  3. SwiftData keeps a local cache so the interface can open quickly and continue showing previously fetched data.
  4. Local edits appear immediately, then synchronize with Google and reconcile against the server response.
The hora Calendar sync loop from local SwiftData cache to the Google Calendar API

Apple describes SwiftData as suitable for a lightweight cache around data fetched from a remote service. That is exactly its role here. The cache improves the Mac experience; it does not create a second calendar account or replace Google as the owner of the events.

Direct API access is not the easy route. It means handling pagination, expired sync tokens, rate limits, recurrence, partial failures, and optimistic updates correctly. I wanted that responsibility because synchronization is part of the product, not plumbing I could safely ignore.

There is a more technical version of this decision in Google Calendar API vs CalDAV.

Native means more than drawing the interface in SwiftUI

The first prototype used Swift 6 and SwiftUI. As the app grew, AppKit joined in where the platform details required it.

That is still a native Mac architecture. SwiftUI provides most of the interface, while AppKit handles selected behaviors where direct control produces a better result. The main calendar is not a wrapped website.

The reason was never purity for its own sake. Native code made the workflows I cared about possible:

  • A menu bar view for the next event.
  • Desktop widgets with a glanceable agenda.
  • Mac keyboard commands and drag interactions.
  • System notifications and normal window behavior.
  • A local cache that can render immediately.

Those details sound small in isolation. Together, they determine whether a calendar feels like part of the computer or a destination you have to visit.

I later wrote a separate explanation of the tradeoffs in Native App vs Electron and PWA.

The security correction that had to happen early

The rough prototype embedded an OAuth client secret in the app bundle. That was a mistake.

A distributed Mac app is a public client. Anything shipped inside the binary should be treated as recoverable, so a static secret cannot be trusted to remain secret.

On March 26, I replaced that flow with PKCE. For each sign-in attempt, hora creates a one-time verifier and sends a derived challenge with the authorization request. The verifier is required when exchanging the returned code for tokens. RFC 7636 defines this flow specifically to protect OAuth authorization codes used by public clients.

The browser authentication itself runs through ASWebAuthenticationSession, Apple's system API for authenticating with a web service. OAuth tokens are stored in macOS Keychain.

That change did not produce a visible feature. It did make the prototype something I could responsibly put in front of another person.

What the first version had to prove

I started with four tests:

  1. Could a direct Google sync layer stay reliable with real calendars?
  2. Could event creation and editing feel immediate without lying about server state?
  3. Could a Google-only product earn its place on a Mac through native workflows?
  4. Could I explain where calendar data goes in plain language?

The first few days answered enough of those questions to keep going. They also exposed how much work hides behind a calm calendar grid.

That same 48-hour stretch brought scope cuts, a rebuilt Day View, availability sharing, dual time zones, a widget, and more security work. I wrote that part down in What I Shipped in 48 Hours.

Looking back after version 1.0

The core bet did not change.

hora is still for people who live in Google Calendar and want a focused native Mac client. Google is still the source of truth. The app still uses the official API directly, with a local cache and platform-native surfaces around it.

What changed was my understanding of the hard part. Building a calendar view is visible. Building trust is not. Trust comes from recurrence handling, retries, account identity, rate limits, background synchronization, and making sure the menu bar agrees with the main window five seconds before a call.

That became the real product.

You can read what eventually shipped in hora Calendar 1.0.

Try hora Calendar on the Mac App Store

About building hora Calendar

04 questions / quick answers

Why did you build another calendar app for Mac?

I wanted Google Calendar to remain the source of truth while gaining a focused native Mac interface, including menu bar access, widgets, keyboard workflows, local caching, and system notifications. Existing multi-provider apps solve a broader problem.

Is hora a native Mac app or a web wrapper?

hora is a native Mac app built with Swift, SwiftUI, and selected AppKit components. Its calendar interface is not a wrapped Google Calendar website.

Does hora use the Google Calendar API or CalDAV?

hora connects directly to the official Google Calendar API. This keeps the app close to Google's event and synchronization model instead of translating it through CalDAV.

Where does hora store calendar data?

Google Calendar remains the source of truth. hora fetches event content from Google and keeps a local SwiftData cache on the Mac so the interface can load quickly. OAuth tokens are stored in macOS Keychain.

Related stories

Building a Native Mac Calendar App in 48 Hours
Build notes

Building a Native Mac Calendar App in 48 Hours

What I cut, rebuilt, and shipped during a 48-hour sprint on hora, including PKCE auth, Day View, FreeBusy sharing, and WidgetKit.

Maciej Szamowski6 min read
Week One Building hora: 107 Commits Later
Build notes

Week One Building hora: 107 Commits Later

A candid snapshot of hora's first ten days: 107 commits, three Swift packages, 21 resolved issues, useful workflows, and plenty still rough.

Maciej Szamowski7 min read
Five Days Later: The Road to Launching hora Calendar
Build notes

Five Days Later: The Road to Launching hora Calendar

Five days after I first wrote about hora, the visible app worked. The road to launch was now OAuth verification, TestFlight, reliability, and feedback.

Maciej Szamowski6 min read
Mobile Beta Sign-up

Want to stay updated?

Subscribe for information about iOS/iPadOS beta availability.