I’ve spent years trying to find the perfect ‘command-center’ for my productivity. I tried everything from Morgen calendar for its deep integration to various CLI tools. But nothing beats the speed of Raycast. When I realized I was spending too much time clicking between my IDE and my browser just to see when my next meeting started, I decided to build a solution.
In this raycast calendar extension tutorial, I’m going to walk you through the process of creating your own calendar extension. Whether you’re using Google Calendar, Outlook, or a custom internal API, the logic remains the same: fetch data, format it for the Raycast UI, and map it to a keyboard shortcut.
Prerequisites
Before we dive into the code, make sure you have the following set up in your environment:
- Raycast installed on your Mac.
- Node.js (v16+) installed.
- A Raycast API Key (available in the developer settings).
- Calendar API access (e.g., Google Calendar API credentials or a Personal Access Token from your provider).
If you’re coming from a Linux background and are used to a command line calendar for Linux, you’ll find the Raycast SDK surprisingly similar in terms of data handling, but with a much more polished UI layer.
Step 1: Initializing Your Extension
First, we need to scaffold the project using the Raycast CLI. Open your terminal and run the following command:
npx @raycast/api@latest init
Follow the prompts: give your extension a name (e.g., “My Calendar”) and choose TypeScript as the language. TypeScript is highly recommended here because the Raycast API provides excellent type definitions that prevent 90% of common UI bugs.
Step 2: Setting Up the API Client
I prefer using a separate utility file for API calls to keep the UI logic clean. Create a file named src/api.ts. In my experience, using axios or the native fetch API works best for these lightweight requests.
import { getPreferenceValues } from "@raycast/api";
export async function fetchCalendarEvents() {
const { apiKey } = await getPreferenceValues();
const response = await fetch(`https://www.googleapis.com/calendar/v3/calendars/primary/events?key=${apiKey}`);
const data = await response.json();
return data.items.map((event: any) => ({
title: event.summary,
time: event.start.dateTime || event.start.date,
location: event.location || "Remote"
}));
}
As shown in the image below, you will need to define these preferences in your package.json so users can securely enter their own API keys without hardcoding them.
Step 3: Building the User Interface
Now, let’s create the main command. Raycast uses a declarative UI approach. You don’t write HTML; you use components like List and ListItem.
import { List, ListItem, ActionPanel, Action } from "@raycast/api";
import { fetchCalendarEvents } from "./api";
export default async function Command() {
const events = await fetchCalendarEvents();
return (
<List searchability={{ enabled: true }}>
{events.map((event) => (
<ListItem
title={event.title}
subtitle={`${event.time} | ${event.location}`}
actions={
<ActionPanel>
<Action.CopyToClipboard title="Copy Event Link" content={event.link} />
</ActionPanel>
}
/>
))}
</List>
);
}
Pro Tips for Calendar Extensions
- Caching: Don’t fetch the API on every single keystroke. Use a local cache or the Raycast state management to store events for 5-10 minutes.
- Relative Timing: Instead of showing “2026-04-22T14:00:00”, use a library like
date-fnsto display “In 2 hours” or “Today at 2 PM”. - Deep Linking: Add an
Action.Opento launch the specific event in the Google Calendar web app for quick edits.
If you find yourself needing more advanced scheduling logic, I highly recommend checking out my guide on advanced Google Calendar tips for power users to see how to structure your calendar for maximum efficiency.
Troubleshooting Common Issues
Issue: “API Key not found”
Ensure you have run the extension in development mode and gone to the Raycast Settings > Extensions > [Your Extension] to fill in the preference values.
Issue: Slow Loading Times
Calendar APIs can be sluggish. Implement a loading state using the Loading component from @raycast/api to provide visual feedback to the user.
What’s Next?
Now that you have a basic list of events, try adding a “Create Event” action. You can use a Form component to take a title and time, then send a POST request back to your calendar provider. This transforms your extension from a viewer into a full productivity tool.
Want more automation tips? Check out the rest of the productivity guides on ajmani.dev to streamline your entire dev workflow.