Speedy Workers
Why we moved off Trigger.dev
We started on Trigger.dev because it let us ship background work without running our own infrastructure — a smart trade when we were small. As Expensicat grew, the operational overhead and the round-trip out to a cloud service on every single job became the slow part. So we built our own runners.
Self-hosted runners, always warm
Background jobs now run on our own queue — BullMQ on Redis — across machines that stay warm and scale up automatically when the backlog grows. There's no cold start and no hop out to a third party, so a job runs the moment it's queued. That's how exporting your inbox went from roughly 19 seconds down to about 1.5.
Faster across the board
This isn't only exports. Bank syncs, receipt and invoice imports from email, Gmail, and Outlook, recurring and scheduled invoices, document processing, and reconciliation all run on the same pipeline — so the work that used to make you wait now happens quietly in the background.
Keys that don't outlive the job
We tightened security on the way through. Instead of one long-lived key shared across every background task, each job now mints its own — tied to that single run, limited to exactly the permissions it needs, and expiring after five minutes. Even if one were ever intercepted, it would be useless almost immediately.
- PerformanceBackground jobs now run on Expensicat's own self-hosted runners, so the work behind exports, imports, and receipt processing starts the instant it's queued.
- PerformanceExporting your inbox is about 13× faster — what used to take around 19 seconds now finishes in roughly 1.5.
- PerformanceBank syncs, email and Gmail/Outlook imports, recurring and scheduled invoices, and document processing all run on the new, faster pipeline.
- ReliabilityJobs pick up immediately with no cold start, and retry on their own when something hiccups.
- SecurityEvery job now runs with its own key, scoped to just that job and the exact permissions it needs, and it expires after five minutes.