Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/cost-skill-webhook-filters.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@trigger.dev/sdk": patch
---

The bundled `trigger-cost-savings` skill now notes that a webhook delivery no subscriber's filter matches starts no run and costs no compute.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Fix the changeset sentence.

The phrase a webhook delivery no subscriber's filter matches starts no run is not grammatical. Use a webhook delivery starts no run when no subscriber's filter matches.

4 changes: 4 additions & 0 deletions docs/how-to-reduce-your-spend.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -190,6 +190,10 @@ export const waitpointTask = task({

Waiting saves you compute, but it doesn't always free up concurrency — see [Wait](/wait).

## Filter webhooks before they start runs

Give each [webhook](/webhooks/overview) subscriber a [filter](/webhooks/filters) so it only runs for the events it handles. A delivery that no filter matches is recorded as `FILTERED` and starts no run, so you aren't charged compute for it. Receiving webhooks has no separate charge.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Filtered subscribers do not prevent waiter compute

When subscriber filters reject an event but a waiter matches, FILTERED is not its status and the waiting run resumes. That run consumes compute despite the cost-saving promise.

Learn more

Webhook waiters subscribe to an endpoint independently of task, agent, and channel subscribers. A matching waiter resumes its existing run even when all subscriber filters reject the event. The delivery then succeeds rather than settling as FILTERED in #finishDelivery. Resuming the run incurs compute, so the same unconditional claim in the pricing overview and bundled cost skill also needs qualification.

Example: A Stripe endpoint has a task filtered to charge.refunded and a waiter matching payment_intent.succeeded. A payment event rejects the task filter but resumes the waiter, so the delivery is not FILTERED and the resumed task can incur compute.

Recommended fix: Qualify the zero-compute claim on there being no matching waiter as well as no matching subscriber; update the cost guide, pricing overview, and bundled skill together.

Devin Review


Was this helpful? React with 👍 or 👎 to provide feedback.


## Use debounce to consolidate multiple triggers

When a task might be triggered multiple times in quick succession, use debounce to consolidate them into a single run. This is useful for document indexing, webhook aggregation, cache invalidation, and real-time sync scenarios.
Expand Down
40 changes: 40 additions & 0 deletions docs/limits.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,46 @@ All of an environment's endpoints also share a per-environment limit, counted in
| Pro | 3,000 every 10 sec |
| Enterprise | Set per organization |

## Webhook waiters

A [waiter](/webhooks/waiters) is a run paused until a matching webhook arrives. The per-endpoint limit is also the most waiting runs one delivery can resume.

| Pricing tier | Live waiters per environment | Live waiters per endpoint |
| :----------- | :--------------------------- | :------------------------ |
| Free | 500 | 100 |
| Hobby | 2,000 | 1,000 |
| Pro | 25,000 | 10,000 |
| Enterprise | Set per organization | Set per organization |

A waiter can wait for up to 90 days.

## Webhook processing concurrency

This limit controls how many webhook deliveries and waiter resumes are processed at once per environment. More wait their turn. It is not a limit on the runs those deliveries start, which use your normal [concurrency limits](#concurrency-limits).

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Clarify the processing-concurrency sentence.

Replace “More wait their turn.” with “Additional deliveries wait their turn.” The current sentence is not grammatical and does not identify what waits.


| Pricing tier | Limit |
| :----------- | :----------------------- |
| Free | 5 concurrent deliveries |
| Hobby | 10 concurrent deliveries |
| Pro | 50 concurrent deliveries |
Comment on lines +198 to +202

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🗄️ Data Integrity & Integration | 🟡 Minor | ⚡ Quick win

Document the Enterprise processing limit.

Add an Enterprise row or state that Enterprise uses a separate organization-level setting. The other webhook limit tables document Enterprise explicitly, and the webhook limits configuration supports an optional concurrency override.


## Webhook delivery retention

How long [deliveries](/webhooks/deliveries) stay visible in the dashboard and the API.

| Pricing tier | Limit |
| :----------- | :--------------------------- |
| Free | 3 days |
| Hobby | 7 days |
| Pro | 30 days |
| Enterprise | 90, 180 or 365 days |

Deliveries are stored for at least 30 days, so upgrading your plan shows older deliveries right away.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Strict retention removes upgrade history

With deliveryRetentionStrict enabled, Free deliveries use a three-day storage class rather than the promised 30 days. Upgrading after those deliveries expire cannot restore them.

Learn more

The visible retention limit and physical storage duration are separate settings. resolveWebhookLimits selects the visible retention class for storage when deliveryRetentionStrict is true, instead of enforcing the default 30-day minimum. The back-office retention option allows this override, and the partition maintenance deletes expired classes. Thus an upgrade can only reveal history still physically stored.

Example: An organization with three-day visible retention and strict retention receives a delivery on Monday. Its delivery enters the three-day class; an upgrade several weeks later cannot reveal it.

Recommended fix: Qualify the 30-day storage and upgrade promise with the condition that strict retention is not enabled, or describe the strict-retention exception explicitly.

Devin Review


Was this helpful? React with 👍 or 👎 to provide feedback.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🗄️ Data Integrity & Integration | 🟡 Minor | ⚡ Quick win

🔎 Supported by static analysis

🏁 Script executed:

set -o pipefail
printf '%s\n' '--- changed docs hunk ---'
git diff --no-ext-diff --unified=25 d9bf563ae3badd0620a88b85c6784c5a8a5c1b6d 451d78c9b54eda489cf9ba278f05ec68544bfcbf -- docs/limits.mdx

printf '%s\n' '--- retention identifier references ---'
rg -n -F --glob '!node_modules' --glob '!dist' --glob '!build' -e 'deliveryRetentionDays' -e 'deliveryStorageDays' -e 'deliveryRetentionStrict' -e 'Deliveries are stored for at least 30 days' .

printf '%s\n' '--- relevant file candidates ---'
rg --files | rg '(^|/)(limits|retention|delivery|webhook|cloud|plan|configuration|config)([^/]*)\.(ts|tsx|js|jsx|json|md|mdx|yaml|yml)$' | head -200

Repository: triggerdotdev/trigger.dev

Length of output: 13606


🏁 Script executed:

set -o pipefail
printf '%s\n' '--- changed docs hunk ---'
git diff --no-ext-diff --unified=25 d9bf563ae3badd0620a88b85c6784c5a8a5c1b6d 451d78c9b54eda489cf9ba278f05ec68544bfcbf -- docs/limits.mdx
printf '%s\n' '--- retention identifier references ---'
rg -n -F --glob '!node_modules' --glob '!dist' --glob '!build' -e 'deliveryRetentionDays' -e 'deliveryStorageDays' -e 'deliveryRetentionStrict' -e 'Deliveries are stored for at least 30 days' .

Repository: triggerdotdev/trigger.dev

Length of output: 9882


🏁 Script executed:

set -o pipefail
git diff --no-ext-diff --unified=25 d9bf563ae3badd0620a88b85c6784c5a8a5c1b6d 451d78c9b54eda489cf9ba278f05ec68544bfcbf -- docs/limits.mdx
rg -n -F --glob '!node_modules' --glob '!dist' --glob '!build' -e 'deliveryRetentionDays' -e 'deliveryStorageDays' -e 'deliveryRetentionStrict' -e 'Deliveries are stored for at least 30 days' .

Repository: triggerdotdev/trigger.dev

Length of output: 9816


🏁 Script executed:

set -o pipefail
printf '%s\n' '--- resolver ---'
nl -ba apps/webapp/app/v3/webhookLimits.ts | sed -n '1,90p'
printf '%s\n' '--- default loading ---'
nl -ba apps/webapp/app/v3/webhookLimits.server.ts | sed -n '1,95p'
printf '%s\n' '--- webhook engine README contract ---'
nl -ba internal-packages/webhook-engine/README.md | sed -n '35,70p'
printf '%s\n' '--- retention environment/config declarations ---'
rg -n -F --glob '!node_modules' --glob '!dist' --glob '!build' -e 'WEBHOOK_DELIVERY_RETENTION_DAYS' -e 'WEBHOOK_DELIVERY_STORAGE_DAYS' -e 'WEBHOOK_DELIVERY_RETENTION_STRICT' -e 'deliveryRetentionStrict' -e 'deliveryStorageDays' -e 'deliveryRetentionDays' -- .env* apps internal-packages packages deploy infra docs 2>/dev/null || test "$?" -eq 1

Repository: triggerdotdev/trigger.dev

Length of output: 16811


🏁 Script executed:

set -o pipefail
printf '%s\n' '--- environment defaults ---'
nl -ba apps/webapp/app/env.server.ts | sed -n '2112,2135p'
printf '%s\n' '--- admin retention controls ---'
nl -ba apps/webapp/app/components/admin/backOffice/WebhookLimitsSection.tsx | sed -n '135,195p'
nl -ba apps/webapp/app/components/admin/backOffice/WebhookLimitsForm.ts | sed -n '1,70p'
printf '%s\n' '--- webhook limits config persistence/references ---'
rg -n -F --glob '!node_modules' --glob '!dist' --glob '!build' -e 'webhookLimitsConfig' -e 'deliveryRetentionStrict' apps/webapp | head -160

Repository: triggerdotdev/trigger.dev

Length of output: 9546


Qualify the delivery storage claim.

Strict retention changes the storage window. When it is disabled, deliveries remain stored for at least 30 days and an upgrade can reveal older deliveries that remain within their storage class. When it is enabled, new deliveries are stored only for the visible retention period rounded to a retention class, so an upgrade cannot recover deliveries already deleted.

Suggested wording
--- "a/docs/limits.mdx"
+++ "b/docs/limits.mdx"
@@ -212,7 +212,7 @@
 | Pro          | 30 days                      |
 | Enterprise   | 90, 180 or 365 days          |
 
-Deliveries are stored for at least 30 days, so upgrading your plan shows older deliveries right away.
+When strict retention is disabled, deliveries are stored for at least 30 days and hidden after the visible retention, so upgrading can show older deliveries that remain within their storage class. When strict retention is enabled, new deliveries are stored only for the visible retention rounded to a retention class, so upgrading cannot recover deliveries deleted before the upgrade.
 
 ## Webhook subscribers
 
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
Deliveries are stored for at least 30 days, so upgrading your plan shows older deliveries right away.
When strict retention is disabled, deliveries are stored for at least 30 days and hidden after the visible retention, so upgrading can show older deliveries that remain within their storage class. When strict retention is enabled, new deliveries are stored only for the visible retention rounded to a retention class, so upgrading cannot recover deliveries deleted before the upgrade.


## Webhook subscribers

An endpoint can have up to 25 subscribers (tasks, agent sessions and channels) on every plan.

## Log retention

| Pricing tier | Limit |
Expand Down
4 changes: 4 additions & 0 deletions docs/webhooks/deliveries.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,10 @@ The [MCP server](/mcp-introduction) has `list_webhook_deliveries` (filter by end
| [`GET /api/v1/webhooks/deliveries/{deliveryId}`](/management/webhooks/retrieve-delivery) | Reads a delivery, with a `targets` entry per subscriber and one for waiting runs. |
| [`POST /api/v1/webhooks/deliveries/{deliveryId}/replay`](/management/webhooks/replay-delivery) | Replays it, as above. The key needs permission to trigger every task the replay starts, and to write sessions if it reaches an agent's subscriber. |

## Retention

Deliveries stay visible for 3 days on Free, 7 days on Hobby and 30 days on Pro. See [Limits](/limits#webhook-delivery-retention).

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Include Enterprise retention.

Add the Enterprise retention values, or explicitly scope this sentence to Free, Hobby, and Pro. The limits page documents 90, 180, or 365 days for Enterprise, so this page currently gives Enterprise users an incomplete answer.


## Deduplication

Trigger.dev uses the endpoint and idempotency key to deduplicate incoming events. Delivery records and task runs have separate deduplication windows:
Expand Down
8 changes: 8 additions & 0 deletions docs/webhooks/overview.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,14 @@ The CLI finds your endpoints and subscribers during `trigger dev` and deployment

A request must pass verification before anything else happens. Provider handshakes are answered directly and create no delivery. A verified request is checked for duplicates, recorded, and then routed: each subscriber's filter is checked, matching subscribers run, and waiting runs whose match fits the event are resumed. The delivery records a result per subscriber.

## Pricing and limits

Webhooks have no separate charge on Trigger.dev Cloud. Receiving, verifying, filtering and recording deliveries is included in every plan. The runs a delivery starts or resumes are billed like any other run, by compute time. See [pricing](https://trigger.dev/pricing).

A delivery that no subscriber's filter matches starts no run, so it uses no compute. A run [waiting](/webhooks/waiters) for a webhook is suspended, so it uses no compute until the webhook arrives.
Comment on lines +88 to +90

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🗄️ Data Integrity & Integration | 🟡 Minor | ⚡ Quick win

🔎 Supported by static analysis

🏁 Script executed:

set -eu
printf '%s\n' '--- diff ---'
git diff --stat d9bf563ae3badd0620a88b85c6784c5a8a5c1b6d 451d78c9b54eda489cf9ba278f05ec68544bfcbf -- docs/webhooks/overview.mdx docs/webhooks/deliveries.mdx docs/limits.mdx docs/guides/spend.mdx skills/trigger-cost-savings || true
git diff --unified=25 d9bf563ae3badd0620a88b85c6784c5a8a5c1b6d 451d78c9b54eda489cf9ba278f05ec68544bfcbf -- docs/webhooks/overview.mdx docs/webhooks/deliveries.mdx docs/limits.mdx docs/guides/spend.mdx skills/trigger-cost-savings || true
printf '%s\n' '--- relevant repository text ---'
rg -n -i --glob '!node_modules' --glob '!dist' --glob '!build' -e 'webhook.*(bill|charg|compute|filter)' -e '(bill|charg|compute).*webhook' -e 'FILTERED' -e 'webhook-limits-backfill' -e 'webhook.*limit' . || test "$?" -eq 1
printf '%s\n' '--- changed overview context ---'
nl -ba docs/webhooks/overview.mdx | sed -n '70,110p'
printf '%s\n' '--- changed spend/skill references ---'
rg -n -C 5 -i --glob '*.md' --glob '*.mdx' --glob '*.ts' --glob '*.json' --glob '*.yaml' --glob '*.yml' -e 'webhooks have no separate charge' -e 'no separate charge' -e 'filtered deliveries' -e 'webhook.*compute' -e 'webhook.*pricing' . || test "$?" -eq 1

Repository: triggerdotdev/trigger.dev

Length of output: 45664


🏁 Script executed:

set -eu
printf '%s\n' '--- webhook billing and ingress references ---'
rg -n -i --glob 'apps/**' --glob 'internal-packages/**' --glob 'packages/**' --glob 'docs/**' --glob '!**/node_modules/**' -e 'chargeWebhook' -e 'webhook.*billing' -e 'billing.*webhook' -e 'webhook.*price' -e 'price.*webhook' -e 'compute.*charge' -e 'charge.*compute' -e 'Webhook.*Billing' .
printf '%s\n' '--- ingress limiter implementation ---'
nl -ba apps/webapp/app/services/webhookIngressRateLimit.server.ts | sed -n '1,240p'
printf '%s\n' '--- webhook engine billing-adjacent declarations ---'
nl -ba internal-packages/webhook-engine/src/engine/index.ts | sed -n '230,330p'
nl -ba internal-packages/webhook-engine/src/engine/index.ts | sed -n '520,620p'
printf '%s\n' '--- local pricing references ---'
rg -n -i --glob 'docs/**' --glob 'apps/**' --glob 'internal-packages/**' --glob 'packages/**' -e 'pricing' -e 'included in every plan' -e 'no separate' -e 'billed like any other run' .
printf '%s\n' '--- exact changed files ---'
git diff --name-status d9bf563ae3badd0620a88b85c6784c5a8a5c1b6d 451d78c9b54eda489cf9ba278f05ec68544bfcbf

Repository: triggerdotdev/trigger.dev

Length of output: 41893


🌐 Web query:

site:trigger.dev pricing webhooks no separate charge compute

💡 Result:

<source_evidence>
<source kind="search">
<title>Cloud Pricing | Trigger.dev</title>
<location>https://trigger.dev/pricing</location>
<excerpt>citeturn0search0 [wordlim: 200] Crawled: 2 weeks ago; ## Compute pricing ... Multiply per second machine price by the seconds your run will take. ... Trigger.dev is framework agnostic so it works with most JavaScript frameworks. ... You can use any API either by using their SDK or through web requests using fetch or your preferred alternative.

# Simple pricing, built for growth

Begin for free, invite your team, and scale without limits.

## Free

### $0/month

* * *

[Input]

Get started

  * $5 / month free credits

  * 20 concurrent runs

  * Unlimited tasks

  * 5 team members

  * Dev and Prod environments

  * Preview branches

  * Custom dashboards

  * 10 schedules

  * 1 day log retention

  * 1 day query period

  * Community support

  * 1 alert destination

  * 10 concurrent Realtime connections

## Hobby

### $10/month

* * *

Get started

  * $10 / month credits included

  * 50 concurrent runs

  * Unlimited tasks

  * 5 team members

  * Dev, Preview and Prod environments

  * 5 preview branches

  * 1 custom dashboard

  * 100 schedules

  * 7 day log retention

  * 7 days query period

  * Community support

  * 3 alert destinations

  * 150 concurrent Realtime connections

  * HIPAA BAA add-on

Request a BAA

## Pro

### $50/month

* * *

Get started

  * $50 / month credits included

  * 200+ concurrent runs

Then $10/month per 50

  * Unlimited tasks

  * 25+ team members

Then $20/month per seat

  * Dev, Preview and Prod environments

  * 20+ preview branches

Then $10/month per branch

  * 5+ custom dashboards

Then $10/month per dashboard

  * 1000+ schedules

Then $10/month per 1,000

  * 30 day log retention

  * 30 days query period

  * Dedicated Slack support

  * 100+ alert destinations

  * 1000+ concurrent Realtime connections

Then $10/month per 1,000

  * AWS PrivateLink

  * HIPAA BAA add-on

Request a BAA

## Enterprise

## Custom

* * *

Contact us

  * Custom discounts

  * All Pro plan features +

  * Custom log retention

  * Priority support

  * Role-based access control (RBAC)

  * SOC 2 report

  * Penetration test report

  * Single sign-on (SSO)

  * HIPAA BAA add-on

Request a BAA

## Compute pricing

[Input]

Per sec

Per hour

Machine  | vCPU  | GB RAM  | Cost/sec
--- | --- | --- | ---
Micro  | 0.25  | 0.25  | $0.0000169
Small 1x Default  | 0.5  | 0.5  | $0.0000338
Small 2x  | 1  | 1  | $0.0000675
Medium 1x  | 1  | 2  | $0.0000850
Medium 2x  | 2  | 4  | $0.0001700
Large 1x  | 4  | 8  | $0.0003400
Large 2x  | 8  | 16  | $0.0006800

Tasks are executed on our managed workers. You are only charged when your tasks are executing.

## Run pricing

#### Cost/run invocation

$0.000025

($0.25 per 10,000 runs)

Every run that starts executing on our managed workers is charged an invocation cost in addition to compute costs. Runs in the DEV environment are not charged for.

## Frequently asked questions

### What is a task?

Tasks are functions that can run for a long time and provide strong resilience to failure. They run on our servers so there are no timeouts and no infrastructure to manage. You can read more about how they work in our docs .

### Can I self-host Trigger.dev?

Absolutely. We have a self hosting guide right here .

### How long can a task run for?

Tasks can run for as long as you need, with no timeouts.

### Where are my tasks run?

On our managed infrastructure. Your task code lives in `trigger` folders (commonly `src/trigger`), and the code inside is bundled and deployed together. You can also self-host if you prefer.

### How do I estimate my usage?

Multiply per second machine price by the seconds your run will take. Add the per run invocation cost and multiply by your run count.

A 10s task that does 100 runs per day on the small-1x machine:

1 run = (10s × $0.0000338) + $0.000025 = $0.000363
1 day = 100 × $0.000363 = $0.0363
1 month = $0.0363 × 30 = $1.09

### How does usage work?

We charge for usage in 2 ways: the number of seconds of compute yo…[truncated]</excerpt>
</source>
<source kind="search">
<title>Wait for HTTP callback | Changelog</title>
<location>https://trigger.dev/changelog/wait-for-http-callback</location>
<excerpt>citeturn0search1 [wordlim: 200] Published: 1.2 years ago; Crawled: today; ## Save on compute costs by pausing runs until third-party services complete their work with webhook callbacks. ... You can save money with Trigger.dev cloud when you are doing long requests to 3rd parties that support webhook callbacks.

# Wait for HTTP callback

## Save on compute costs by pausing runs until third-party services complete their work with webhook callbacks.

Matt Aitken

CEO, Trigger.dev

When you create a Waitpoint token we give you a URL back that can be passed to a 3rd party. When they&#39;re done with the work they can make a POST request to that URL and we&#39;ll continue the run with the result.

It&#39;s easier to understand with an example. Here we&#39;re going to get Replicate to generate an image for us in the background.

`

import { task, wait } from &quot;@trigger.dev/sdk&quot;;

const replicate = new Replicate({

auth: process.env.REPLICATE_API_KEY,

});

export const generateImage = task({

id: &quot;generate-image&quot;,

run: async () =&gt; {

// You can create this token from your backend or inside a task

const token = await wait.createToken({

timeout: &quot;10m&quot;,

});

await replicate.predictions.create({

version:

&quot;27b93a2413e7f36cd83da926f3656280b2931564ff050bf9575f1fdf9bcd7478&quot;,

input: {

prompt: &quot;A painting of a cat by Andy Warhol&quot;,

},

// pass the token url to Replicate&#39;s webhook, so they can &quot;callback&quot;

// 👇

webhook: token.url,

webhook_events_filter: [&quot;completed&quot;],

});

const result = await wait.forToken&lt;Prediction&gt;(token).unwrap();

// unwrap() throws a timeout error or returns the result 👆

return result;

},

});

`

When Replicate has finished processing the image it will make an HTTP POST request to the URL we gave it. That will complete the Waitpoint and the JSON body is set as the output of the Waitpoint. The run is continued with the output of the Waitpoint.

On the Cloud product we pause the run when you call `wait.forToken()` (so you stop being charged) and then continue the run when the HTTP callback comes in.
</excerpt>
</source>
<source kind="search">
<title>Trigger.dev vs Inngest | Trigger.dev</title>
<location>https://trigger.dev/vs/inngest</location>
<excerpt>citeturn0search2 [wordlim: 200] Crawled: today; Trigger.dev provides its own compute, so background tasks are decoupled from your web app entirely. ... ### How does pricing compare between Inngest and Trigger.dev?
The models favor different workload shapes.

Feature  | Trigger.dev  | Inngest
--- | --- | ---
Pricing model  | Compute-seconds + per-run fee  | Per-step execution + concurrency tiers
Free tier  | Free plan with monthly usage included  | 50,000 executions/mo, 5 concurrent steps
Pro tier  | See pricing  | Pro tier with more executions and concurrency (see pricing )
What counts as a billable unit  | Compute time (per second, by machine size) plus a flat fee per task run, however many steps it has  | Executions: 1 when the run starts, plus 1 for each step
Self-hosted cost  | Free (Apache 2.0) + your infra  | Free (SSPL) + your infra

Inngest&#39;s per-execution pricing scales with function complexity. Each run counts as the run itself plus every step, so a 5-step run is 6 executions and 100,000 runs of that function is 600,000 executions against your plan. This model works well for simple functions with few steps. Trigger.dev charges for compute time: a task that runs for 10 seconds costs the same whether it has 1 logical step or 50 internal operations. Which is cheaper depends on the workload. On Inngest, add your own hosting bill to the execution count. On Trigger.dev, cost depends on machine size and run time (including retries), plus a per-run fee for every task and subtask, so a workflow that splits work into subtasks, like the order example below, pays several run fees. Many-step work often favors Trigger.dev, while short functions with few steps can cost less on Inngest.
</excerpt>
</source>
<source kind="search">
<title>Trigger.dev vs n8n: open source n8n alternative | Trigger.dev</title>
<location>https://trigger.dev/vs/n8n</location>
<excerpt>citeturn0search3 [wordlim: 200] Crawled: today; The MCP server works across development and production environments, letting AI editors search docs, write tasks, trigger runs, and deploy. ... n8n&#39;s default architecture runs everything in a single Node.js process: the UI, webhooks, polling triggers, and workflow execution share the same resources. ... See n8n pricing and Trigger.dev pricing for current details. ... Trigger.dev charges per compute-second plus a per-run fee. n8n&#39;s model is simpler to predict for high-volume simple automations.
Environments  | Production, Staging, Preview (per-branch), Development  | Business + Enterprise: environments with source control sync

n8n&#39;s default architecture runs everything in a single Node.js process: the UI, webhooks, polling triggers, and workflow execution share the same resources. For production scale, queue mode distributes execution to separate worker processes via Redis. Both modes are available on self-hosted (including the free community edition). n8n Cloud handles hosting; Code nodes on Cloud run vanilla JS and Python without external package imports. Trigger.dev takes a managed compute approach: each task run gets its own container with configurable machine presets, so a memory spike in one task can&#39;t affect others. Build extensions add system-level dependencies (Prisma, FFmpeg, Playwright, Python) with a config line. Deploy with the CLI, GitHub auto-deploy, or the Vercel integration.

## How does pricing compare?

n8n charges per workflow execution. Trigger.dev charges per compute-second plus a per-run fee. </excerpt>
</source>
<source kind="search">
<title>Billing alerts | Changelog</title>
<location>https://trigger.dev/changelog/billing-alerts</location>
<excerpt>citeturn0search4 [wordlim: 200] Published: 1.2 years ago; Crawled: last month; Co-founder, Trigger.dev ... You can now get notified when your compute usage exceeds a certain threshold.

July 31, 2025 View all changelogs

# Billing alerts

## Get notified when your usage exceeds certain thresholds.

James Ritchie

Co-founder, Trigger.dev

Matt Aitken

CEO, Trigger.dev

Image: Image for Billing alerts

You can now get notified when your compute usage exceeds a certain threshold. Head to the new &quot;Billing alerts&quot; page in &quot;Settings&quot; from the top left main menu.

Image: Billing alerts menu

Set a threshold in dollars for when you want to be notified. You can also get notified when you hit different percentages of usage so you have plenty of warning. You can also add as many team members as you want to be notified.

Image: Billing alerts UI</excerpt>
</source>
<omitted_sources count="7">Additional source records were omitted from this bounded result.</omitted_sources>
</source_evidence>

Citations:

- 1: https://trigger.dev/pricing?utm_source=openai

Describe the standard run fee as well as compute charges.

docs/webhooks/overview.mdx:88 says delivery-started or resumed runs are billed “by compute time.” Normal pricing also charges an invocation fee when a run starts executing. State both charges so this documentation does not understate webhook-triggered run costs.

Suggested fix
--- "a/docs/webhooks/overview.mdx"
+++ "b/docs/webhooks/overview.mdx"
@@ -85,7 +85,7 @@
 
 ## Pricing and limits
 
-Webhooks have no separate charge on Trigger.dev Cloud. Receiving, verifying, filtering and recording deliveries is included in every plan. The runs a delivery starts or resumes are billed like any other run, by compute time. See [pricing](https://trigger.dev/pricing).
+Webhooks have no separate charge on Trigger.dev Cloud. Receiving, verifying, filtering and recording deliveries is included in every plan. The runs a delivery starts or resumes use normal run pricing: a run that starts executing incurs the standard invocation fee, and execution time incurs compute charges. See [pricing](https://trigger.dev/pricing).
 
 A delivery that no subscriber's filter matches starts no run, so it uses no compute. A run [waiting](/webhooks/waiters) for a webhook is suspended, so it uses no compute until the webhook arrives.
 
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
Webhooks have no separate charge on Trigger.dev Cloud. Receiving, verifying, filtering and recording deliveries is included in every plan. The runs a delivery starts or resumes are billed like any other run, by compute time. See [pricing](https://trigger.dev/pricing).
A delivery that no subscriber's filter matches starts no run, so it uses no compute. A run [waiting](/webhooks/waiters) for a webhook is suspended, so it uses no compute until the webhook arrives.
Webhooks have no separate charge on Trigger.dev Cloud. Receiving, verifying, filtering and recording deliveries is included in every plan. The runs a delivery starts or resumes use normal run pricing: a run that starts executing incurs the standard invocation fee, and execution time incurs compute charges. See [pricing](https://trigger.dev/pricing).
A delivery that no subscriber's filter matches starts no run, so it uses no compute. A run [waiting](/webhooks/waiters) for a webhook is suspended, so it uses no compute until the webhook arrives.


Each plan sets limits on the ingest rate, waiting runs, processing concurrency and how long deliveries are kept. See [Limits](/limits#webhook-ingest-rate-limits).

## Connect it

Every endpoint can produce a setup prompt for an AI coding agent. It holds the URL, the events your subscribers filter on, and the steps for registering the endpoint and its signing secret with the provider. Copy it from the endpoints list or the endpoint's page, or read it with the MCP server's `get_webhook_endpoint_details` tool. See [Connect a provider](/webhooks/connect).
Expand Down
2 changes: 1 addition & 1 deletion docs/webhooks/waiters.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,6 @@ if (!result.cancelled) {
| Tags per waiter | 10 |
| Timeout | 24 hours by default, 90 days at most |

On Trigger.dev Cloud the per-endpoint and per-environment limits depend on your plan. Self-hosted installs can change them with `WEBHOOK_WAITER_MAX_PER_ENDPOINT`, `WEBHOOK_WAITER_MAX_PER_ENVIRONMENT` and `WEBHOOK_WAITER_MAX_SHAPES`.
On Trigger.dev Cloud the per-endpoint and per-environment limits depend on your plan: see [Limits](/limits#webhook-waiters). Self-hosted installs can change them with `WEBHOOK_WAITER_MAX_PER_ENDPOINT`, `WEBHOOK_WAITER_MAX_PER_ENVIRONMENT` and `WEBHOOK_WAITER_MAX_SHAPES`.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Clarify the scope of the preceding limits table.

The table lists 10,000 live waiters per endpoint as the default, while the linked Cloud table lists 100 for Free and 1,000 for Hobby. Label the table as self-hosted defaults or separate Cloud and self-hosted values.


A delivery that resumes waiters shows one **Waiting runs** row on its [delivery page](/webhooks/deliveries#where-a-delivery-went) with how many matched, resumed and failed. A delivery that arrives while runs are waiting but matches none of them, and no subscriber takes, is `UNMATCHED`.
1 change: 1 addition & 0 deletions packages/trigger-sdk/skills/trigger-cost-savings/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,7 @@ Larger machines cost proportionally more per second of compute:
## Key principles

- **Waits > 5 seconds are free** — checkpointed, no compute charge.
- **Webhook filters skip runs** — a webhook delivery that no subscriber's filter matches starts no run and costs no compute. Receiving webhooks has no separate charge.
- **Start small, scale up** — the default `small-1x` is right for most tasks.
- **I/O-bound tasks don't need big machines** — API calls and DB queries wait on the network.
- **Debounce saves the most on high-frequency tasks** — it consolidates bursts into single runs.
Expand Down
Loading