All episodes

Eric from Trigger.dev - iterating to 50% MoM growth

Trigger.dev rewrote its product twice before finding a version that grew revenue about 50% a month. The breakthrough was taking responsibility for running developers' code instead of orchestrating fragile serverless functions it could not control.

Jack Bridger
Episode 13642:40

Eric Allam is the co-founder of Trigger.dev, the open-source platform for background jobs. He takes us through three substantially different versions of the product and the fourth version that could finally evolve without starting over.

It is a story about listening to the shape and frequency of support problems, simplifying a product to what a small team can make excellent, and recognizing product-market fit not in a survey answer but in users quietly turning up and running enormous workloads.

The Q&A below is experimental — extracted from the episode transcript with AI. If you spot a mistake, let us know at jack@scalingdevtools.com.

What was the first version of Trigger.dev?

It launched as an open-source Zapier alternative for developers: integrations and step-by-step workflows running from schedules or webhooks. Hacker News responded well, but the product needed a long-running Node process, while the developers with this problem were largely on serverless platforms. We worked on it for about four months and it was live for roughly two before we accepted that we were starting from the wrong execution model.

How did version two adapt Trigger.dev to serverless applications?

We broke long workflows into deterministic, cached steps across repeated serverless-function invocations. Every result had to be serialized, and developers had to wrap work in our SDK with stable cache keys. It enabled multi-step jobs and integrations such as responding to a Supabase database event with an email flow, but code could not simply move out of a slow request handler unchanged.

Why did that model keep failing for users?

Normal code is often non-deterministic. A timestamp or a dynamic cache key could make the job repeat forever, and by the tenth execution any difference could break the workflow in a way that was difficult to diagnose. We also inherited constraints outside our control: one platform cached POST requests by design and imposed a 4.5MB request limit. The product could work beautifully for somebody who understood the model, but Discord and customer Slack channels were dominated by variations of 'it isn't working.'

What made you decide Trigger.dev should run the code itself?

I asked users where they thought a Trigger.dev job executed, and about 55% assumed it ran on our cloud even though version two called their serverless function. That mismatch, and the fact that we could not repair constraints on somebody else's platform, pointed toward owning the entire execution stack. Hiring an open-source contributor who deeply understood Linux made the much larger infrastructure project feel possible.

What did you deliberately remove in version three?

We stopped trying to own every integration and webhook lifecycle. Keeping an OpenAI integration current could interrupt the whole roadmap every time its API changed, and doing integrations well would require a team we could not hire. In version three the application triggers a task itself, or uses a specialist webhook service, while we keep core facilities such as scheduling. The rewrite was a chance to focus on what we could make genuinely good.

How can a normal JavaScript task pause without paying for idle compute?

Internally we snapshot the entire Linux process with CRIU, write its memory and state to storage, then rehydrate it later as though it never stopped. That lets user code wait for another task, a Slack approval or some other event and resume from the next line without forcing developers into the deterministic replay model. The complicated mechanism stays hidden, so the task itself reads like ordinary code.

How different was the response to version three?

It felt perhaps two orders of magnitude better. After usage-based cloud billing launched, revenue averaged roughly 50% growth per month. Some users arrive without ever speaking to us and simply run large workloads. Because a task is a customizable container image, it can use Python or Go, shell out to FFmpeg, install LibreOffice or do other work that is awkward on conventional serverless platforms. Owning that flexible compute layer drove much of the growth.

How did customer feedback tell you what to build when nobody explicitly described version three?

The answer emerged from six months of recurring problems across Discord, Slack and GitHub. Customer interviews were useful, but no user handed us the new architecture. We had to notice the frequency and pattern of the failures, then infer that owning execution would remove most of them. Existing version-two users were not universally happy, but a model that worked for a subset was not going to take the company to the next stage.

What did you learn about managing such a large breaking change?

We announced at least six months of cloud support, ran it a little longer for stragglers, helped customers migrate on calls and built an LLM tool that could translate version-two code. Today a breaking rewrite is even riskier because coding models keep reproducing old APIs and sometimes combine them with packages that never existed. Open source meant self-hosters could continue, but we still treated the community's transition as our responsibility.

What changes in version four?

The run engine makes pause-and-resume behavior programmable through wait points, so another system can hold a token and resume a workflow after a human approval or agent action. We also improved streaming between a background LLM and the front end, interruption controls, AI observability and Python support. It is an evolution of the model that works rather than another wholesale rewrite.

Links & references

This episode is brought to you by WorkOS.

Keep listening