अधिकांश प्रोडक्शन एप्लिकेशन को ऐसे काम की ज़रूरत होती है जो रिक्वेस्ट/रेस्पॉन्स साइकल मे फ़िट नही होता: ईमेल भेजना, अपलोड प्रोसेस करना, AI पाइपलाइन चलाना, थर्ड-पार्टी डेटा सिंक करना, रिपोर्ट जनरेट करना। पारंपरिक उत्तर एक क्यू (Redis, SQS, RabbitMQ), वर्कर फ़्लीट, एक शेड्यूलर, और ग्लू कोड का एक नाज़ुक ढेर है जो हर डिप्लॉय पर टूट जाता है।
Trigger.dev उस स्टैक को एक एकल TypeScript SDK मे संकुचित करता है। आप फ़ंक्शन लिखते है, उन्हे कही से भी कॉल करते है, और प्लेटफ़ॉर्म क्यूइंग, रिट्राई, ऑब्ज़र्वेबिलिटी, शेड्यूलिंग और टिकाऊ निष्पादन को संभालता है। टास्क उतने समय तक चलते है जितनी ज़रूरत हो - कोई 10-सेकंड सर्वरलेस टाइमआउट नही, रीडिप्लॉय पर कोई खोया हुआ काम नही।
क्यो Trigger.dev
2026 मे शिफ़्ट टिकाऊ निष्पादन है। वर्कफ़्लो को रीस्टार्ट, क्रैश, डिप्लॉय और रेट लिमिट से बचना होगा। उन्हे प्रगति को रियलटाइम मे UI मे स्ट्रीम करना और मानवीय इनपुट के लिए रुकना भी होगा। Trigger.dev को संस्करण 3 के साथ इन आवश्यकताओ के आसपास फिर से बनाया गया था और AI इन्फ्रास्ट्रक्चर सतह का विस्तार जारी रखता है।
मॉडल सरल है: आप टास्क को एक्सपोर्ट के रूप मे परिभाषित करते है, SDK उन्हे उठाता है, प्लेटफ़ॉर्म उन्हे अलग कंटेनरो मे शेड्यूल और चलाता है, और रन स्टेट को बनाए रखा जाता है ताकि आप फिर से शुरू कर सके, रिट्राई कर सके और निरीक्षण कर सके।
शुरू करना
प्रोजेक्ट इनिशियलाइज़ करे
npx trigger.dev@latest login npx trigger.dev@latest init
यह एक trigger.config.ts फ़ाइल और उदाहरण टास्क के साथ एक trigger/ डायरेक्टरी बनाता है। कॉन्फ़िग फ़ाइल आपके प्रोजेक्ट के लिए सत्य का स्रोत है: कौन सी डायरेक्टरीज़ मे टास्क है, बिल्ड सेटिंग्स, lifecycle hooks और रनटाइम विकल्प।
// trigger.config.ts import { defineConfig } from "@trigger.dev/sdk"; export default defineConfig({ project: "proj_abc123", runtime: "node", logLevel: "log", maxDuration: 3600, retries: { enabledInDev: true, default: { maxAttempts: 3, factor: 2, minTimeoutInMs: 1000, maxTimeoutInMs: 30_000, }, }, dirs: ["./trigger"], });
टास्क लोकल मे चलाए
npx trigger.dev@latest dev
dev सर्वर क्लाउड से कनेक्ट होता है, आपके टास्क रजिस्टर करता है, और आपके लोकल कोड के माध्यम से रन स्ट्रीम करता है। आप अपने एडिटर मे ब्रेकपॉइंट सेट करते है और उन्हे असली ट्रिगर्स पर हिट करते है - वही लूप जो आप किसी सामान्य Node.js प्रोजेक्ट मे उपयोग करेगे।
एक Task परिभाषित करना
टास्क एक एक्सपोर्टेड ऑब्जेक्ट है जिसमे एक यूनीक id और एक run फ़ंक्शन है। SDK dirs के माध्यम से एक्सपोर्ट का निरीक्षण करता है और उन्हे स्वचालित रूप से रजिस्टर करता है।
// trigger/send-welcome-email.ts import { task } from "@trigger.dev/sdk"; import { Resend } from "resend"; const resend = new Resend(process.env.RESEND_API_KEY); export const sendWelcomeEmail = task({ id: "send-welcome-email", retry: { maxAttempts: 5, factor: 1.8, minTimeoutInMs: 500, maxTimeoutInMs: 30_000, }, run: async (payload: { email: string; name: string }) => { const { data, error } = await resend.emails.send({ from: "hello@spinny.dev", to: payload.email, subject: `Welcome, ${payload.name}`, html: `<p>Glad you are here, ${payload.name}.</p>`, }); if (error) throw error; return { messageId: data?.id }; }, });
ध्यान देने योग्य तीन बाते:
- रन बॉडी मे कोई टाइमआउट नही। प्लेटफ़ॉर्म रनटाइम मे नही, कॉन्फ़िग मे
maxDurationके माध्यम से निष्पादन समय का प्रबंधन करता है। - Throws रिट्राई है। SDK अपवादो को पकड़ता है और
retryपॉलिसी के अनुसार exponential backoff के साथ पुनः चलाता है। - रिटर्न वैल्यू बनी रहती है। अन्य टास्क और आपका फ्रंटएंड कही से भी
run.outputपढ़ सकते है।
Tasks ट्रिगर करना
आप अपने बैकएंड, अपने API रूट्स, या किसी अन्य टास्क से एक टास्क कॉल करते है।
import { sendWelcomeEmail } from "@/trigger/send-welcome-email"; const handle = await sendWelcomeEmail.trigger( { email: "user@example.com", name: "Alex" }, { idempotencyKey: `welcome-${userId}`, concurrencyKey: `tenant-${tenantId}`, queue: { name: "emails", concurrencyLimit: 50 }, delay: "30s", ttl: "10m", } ); console.log(handle.id); // run_xyz - इसका उपयोग प्रगति को ट्रैक या प्रदर्शित करने के लिए करे
विकल्प एक कॉल मे बहुत सारे व्यवहार खोलते है:
idempotencyKey- यदि उसी key के साथ एक रन पहले से मौजूद है, तो SDK काम को डुप्लिकेट करने के बजाय मौजूदा हैंडल लौटाता है।concurrencyKey- उस key को साझा करने वाले रन को क्रमबद्ध करता है ताकि आप प्रति-tenant रेट लिमिट को न पार करे।queue.concurrencyLimit- सभी keys मे क्यू के लिए वैश्विक कैप।delay- रन को भविष्य के समय के लिए शेड्यूल करता है।ttl- यदि रन तब तक शुरू नही हुआ है, तो इसे स्वचालित रूप से समाप्त कर दे।
Batch trigger
फ़ैन-आउट वर्कलोड के लिए, batchTrigger प्रति कॉल 500 आइटम तक स्वीकार करता है और प्रति आइटम एक रन बनाता है।
await sendWelcomeEmail.batchTrigger( newUsers.map((u) => ({ payload: { email: u.email, name: u.name }, options: { idempotencyKey: `welcome-${u.id}` }, })) );
शेड्यूल किए गए Tasks
Cron जॉब्स प्रथम-श्रेणी की घोषणाएँ बन जाती है। शेड्यूल स्वयं एक अलग ऑब्जेक्ट है जिसे आप कई बार किसी टास्क मे संलग्न कर सकते है।
// trigger/daily-digest.ts import { schedules } from "@trigger.dev/sdk"; export const dailyDigest = schedules.task({ id: "daily-digest", cron: "0 9 * * *", run: async (payload) => { console.log("Scheduled at:", payload.timestamp); console.log("Last run:", payload.lastTimestamp); console.log("Timezone:", payload.timezone); console.log("Next 5 runs:", payload.upcoming); await sendDigestForDate(payload.timestamp); }, });
प्रति-tenant शेड्यूल के लिए - मान लीजिए, प्रति ग्राहक एक cron - आप उन्हे management API के माध्यम से गतिशील रूप से बनाते है।
import { schedules } from "@trigger.dev/sdk"; await schedules.create({ task: "daily-digest", cron: "0 9 * * *", timezone: "America/New_York", externalId: `customer_${customerId}`, deduplicationKey: `digest-${customerId}`, });
deduplicationKey कॉल को आइडेम्पोटेन्ट बनाता है: डिप्लॉय समय पर एक ही कोड को फिर से चलाने से डुप्लिकेट शेड्यूल नही बनते।
क्यू, कन्करन्सी और आइडेम्पोटेन्सी
तीन प्रिमिटिव्स अधिकांश रेट-लिमिटिंग और ऑर्डरिंग आवश्यकताओ को कवर करते है।
एक सामान्य पैटर्न: एक vendor की रेट लिमिट का सम्मान करने के लिए प्रति tenant एक क्यू, छोटी प्रति-key concurrency के साथ, साथ ही रिट्राई को सुरक्षित बनाने के लिए एक आइडेम्पोटेन्सी key।
await syncShopifyOrders.trigger( { shopId }, { queue: { name: `shopify-${shopId}`, concurrencyLimit: 2 }, concurrencyKey: shopId, idempotencyKey: `sync-${shopId}-${Date.now() / 60_000 | 0}`, } );
प्रतीक्षा और लंबे समय तक चलने वाला काम
टास्क एक कनेक्शन को बनाए रखे या कंप्यूट को जलाए बिना रुक सकते है। प्लेटफ़ॉर्म स्टेट को बनाए रखता है और जब प्रतीक्षा पूरी होती है तो फ़ंक्शन को फिर से शुरू करता है।
import { wait } from "@trigger.dev/sdk"; export const onboarding = task({ id: "onboarding", run: async (payload: { userId: string }) => { await sendWelcomeEmail.triggerAndWait({ userId: payload.userId }); await wait.for({ days: 1 }); await sendTipsEmail.trigger({ userId: payload.userId }); await wait.until({ date: oneWeekFromSignup(payload.userId) }); await sendUpgradeOffer.trigger({ userId: payload.userId }); }, });
triggerAndWait मारक फ़ीचर है: यह एक चाइल्ड टास्क को ट्रिगर करता है और चाइल्ड के पूरा होने तक पैरेंट को सस्पेंड करता है। आप टास्क को async फ़ंक्शन की तरह कंपोज़ करते है, लेकिन ऑर्केस्ट्रेशन दिनो या हफ़्तो तक टिकाऊ रूप से चलता है।
wait.forToken के साथ Human-in-the-loop
अनुमोदन प्रवाह और AI गेट्स के लिए, wait.forToken तब तक रुकता है जब तक आपका एप्लिकेशन परिणाम के साथ कॉलबैक न करे।
import { task, wait } from "@trigger.dev/sdk"; export const publishPost = task({ id: "publish-post", run: async (payload: { draftId: string }) => { const draft = await generateAIContent(payload.draftId); const token = await wait.createToken({ timeout: "7d" }); await notifyEditor({ draftId: draft.id, token: token.id }); const decision = await wait.forToken<{ approved: boolean; notes?: string }>( token.id ); if (decision.approved) { return await publish(draft); } return await applyFeedback(draft, decision.notes); }, });
संपादक एक UI खोलता है, ड्राफ्ट की समीक्षा करता है, अनुमोदन पर क्लिक करता है, और आपका बैकएंड टोकन पूरा करता है। टास्क वही से जारी रहता है जहाँ छूटा था - भले ही घंटे या दिन बीत गए हो।
Lifecycle Hooks
आप init, onStart, onSuccess और onFailure को एक टास्क या वैश्विक रूप से trigger.config.ts मे संलग्न कर सकते है। उन्हे ट्रेसिंग, error reporting और साझा सेटअप के लिए उपयोग करे।
// trigger.config.ts export default defineConfig({ // ... init: async () => { Sentry.init({ dsn: process.env.SENTRY_DSN }); }, onFailure: async ({ error, ctx }) => { Sentry.captureException(error, { tags: { taskId: ctx.task.id, runId: ctx.run.id }, }); }, });
init बूट पर प्रति वर्कर कंटेनर एक बार चलता है, प्रति रन नही, इसलिए यह क्लाइंट और पूल सेट अप करने के लिए सही जगह है।
फ्रंटएंड मे रियलटाइम
Trigger.dev रन स्टेट परिवर्तन - status, metadata, output - एक स्ट्रीमिंग API पर प्रकाशित करता है। React हुक उस स्ट्रीम की सदस्यता लेते है और स्वचालित रूप से री-रेंडर करते है।
// trigger/process-video.ts import { task, metadata } from "@trigger.dev/sdk"; export const processVideo = task({ id: "process-video", run: async (payload: { videoId: string }) => { metadata.set("stage", "transcoding"); await transcode(payload.videoId); metadata.set("stage", "thumbnails"); await generateThumbnails(payload.videoId); metadata.set("stage", "uploading"); const url = await uploadToCDN(payload.videoId); return { url }; }, });
// components/VideoStatus.tsx "use client"; import { useRealtimeRun } from "@trigger.dev/react-hooks"; import type { processVideo } from "@/trigger/process-video"; export function VideoStatus({ runId, publicAccessToken, }: { runId: string; publicAccessToken: string; }) { const { run, error } = useRealtimeRun<typeof processVideo>(runId, { accessToken: publicAccessToken, }); if (error) return <p>Error: {error.message}</p>; if (!run) return <p>Loading...</p>; return ( <div> <p>Status: {run.status}</p> <p>Stage: {String(run.metadata?.stage ?? "queued")}</p> {run.output?.url && <video src={run.output.url} controls />} </div> ); }
आप सर्वर-साइड पर सार्वजनिक एक्सेस टोकन उत्पन्न करते है, जो किसी विशिष्ट रन के लिए स्कोप किया जाता है, और इसे क्लाइंट को भेजते है। हुक auth, पुनः कनेक्शन और incremental updates को संभालता है।
एक चरण मे trigger-and-subscribe के लिए:
import { useRealtimeTaskTrigger } from "@trigger.dev/react-hooks"; const { submit, run, isLoading } = useRealtimeTaskTrigger<typeof processVideo>( "process-video", { accessToken: publicAccessToken } ); <button onClick={() => submit({ videoId })} disabled={isLoading}> Process video </button>;
AI एजेंट्स और स्ट्रीमिंग
Trigger.dev AI एजेंटो के लिए एक लोकप्रिय रनटाइम बन गया है क्योकि वही प्रिमिटिव्स - टिकाऊ निष्पादन, रिट्राई, प्रतीक्षा, रियलटाइम मेटाडेटा, human-in-the-loop - बिल्कुल वही है जो एजेंटो को चाहिए। आप रन के होने के दौरान एक मॉडल प्रदाता से टोकन को metadata मे स्ट्रीम करते है, फ्रंटएंड उन्हे लाइव रेंडर करता है, और रन सर्वरलेस टाइमआउट को जलाए बिना लंबे समय तक चलने वाले टूल कॉल को जीवित रहता है।
import { task, metadata } from "@trigger.dev/sdk"; import { streamText } from "ai"; import { anthropic } from "@ai-sdk/anthropic"; export const researchAgent = task({ id: "research-agent", maxDuration: 1800, run: async (payload: { question: string }) => { const result = streamText({ model: anthropic("claude-opus-4-7"), system: "You are a research assistant. Use the web.", prompt: payload.question, tools: { webSearch }, }); let fullText = ""; for await (const chunk of result.textStream) { fullText += chunk; metadata.set("partial", fullText); } return { answer: fullText, usage: await result.usage }; }, });
फ्रंटएंड useRealtimeRun का उपयोग करता है और स्ट्रीमिंग प्रतिक्रिया को रेंडर करने के लिए run.metadata.partial पढ़ता है, उसी तरह जैसे आप एक चैट कम्प्लीशन को रेंडर करेगे - सिवाय इसके कि यह एक पूर्ण पेज रीलोड को जीवित रखता है।
डिप्लॉय करना
डिप्लॉय आपके टास्क को एक संस्करण बंडल मे संकलित करते है, एक कंटेनर बनाते है, और ट्रैफ़िक को परमाणु रूप से स्वैप करते है। पुराने इन-फ्लाइट रन पिछले संस्करण का उपयोग करते रहते है।
npx trigger.dev@latest deploy --env prod
CI मे आप आमतौर पर इसे उसी वर्कफ़्लो मे जोड़ते है जो आपकी ऐप शिप करता है:
# .github/workflows/deploy.yml - name: Deploy Trigger.dev env: TRIGGER_ACCESS_TOKEN: ${{ secrets.TRIGGER_ACCESS_TOKEN }} run: npx trigger.dev@latest deploy --env prod
प्रीव्यू वातावरणो के लिए, --env preview --branch ${{ github.head_ref }} पास करे और Trigger.dev प्रति शाखा एक अलग वातावरण बनाता है, यह दर्शाता है कि Vercel प्रीव्यू डिप्लॉयमेंट को कैसे संभालता है।
Self-Hosting बनाम Cloud
Trigger.dev Apache 2.0 लाइसेंस के तहत ओपन सोर्स है। आप किसी भी कंटेनर प्लेटफ़ॉर्म (Docker Compose, Kubernetes, Fly.io) पर self-host कर सकते है या trigger.dev पर प्रबंधित क्लाउड का उपयोग कर सकते है।
| पहलू | Cloud | Self-hosted |
|---|---|---|
| सेटअप | साइन अप, init चलाएं | docker-compose या Helm chart चलाएं |
| स्केलिंग | स्वचालित | आपकी ज़िम्मेदारी |
| मूल्य निर्धारण | प्रति run + प्रति compute | केवल इन्फ्रा लागत |
| अनुपालन | SOC 2 | जो आपका वातावरण प्रदान करता है |
| के लिए सर्वोत्तम | अधिकांश टीमे | सख्त डेटा निवास, custom इन्फ्रा |
SDK और CLI मोड के बीच समान है - आप एक प्रोफ़ाइल फ़्लैग बदलते है और अपने स्वयं के इंस्टेंस की ओर इशारा करते है।
सर्वोत्तम प्रथाएँ
1. payloads को छोटा और serializable रखे
IDs और संदर्भ पास करे, पूर्ण ऑब्जेक्ट नही। टास्क के अंदर डेटा खीचे। यह क्यू को छोटा रखता है, payloads को log करना सस्ता बनाता है, और आपको पुनः ट्रिगर किए बिना डेटा स्रोत बदलने देता है।
2. हर बाहरी कॉल पर idempotency keys
टास्क ट्रिगर पर idempotencyKey को अपने vendor APIs (Stripe, OpenAI, आदि) पर idempotency keys के साथ संयोजित करे। रिट्राई end-to-end सुरक्षित होगे।
3. ऑर्केस्ट्रेशन के लिए triggerAndWait का उपयोग करे, ट्रिगर्स के Promise.all का नही
एक पैरेंट जो triggerAndWait कॉल करता है, टिकाऊ रूप से चाइल्ड टास्क को कंपोज़ करता है। एक पैरेंट जो ट्रिगर करता है और तुरंत हल हो जाता है, चेन की ऑब्ज़र्वेबिलिटी खो देता है।
4. Runs को टैग करे
ट्रिगर्स मे tags जोड़े (tags: ["user:123", "feature:onboarding"]) ताकि आप व्यावसायिक आयामो द्वारा डैशबोर्ड और management API को फ़िल्टर कर सके।
5. init को idempotent रखे
यह हर cold start पर चलता है। वहाँ migrations या one-shot side effects से बचे।
निष्कर्ष
Trigger.dev उन कार्य श्रेणियो को हटाता है जिनके लिए पहले स्क्रैच से एक जॉब सिस्टम बनाने की आवश्यकता होती थी। आप async TypeScript लिखते है, इसे कही से भी कॉल करते है, और प्लेटफ़ॉर्म आपको out of the box टिकाऊ निष्पादन, शेड्यूलिंग, क्यू, रिट्राई, रियलटाइम अपडेट और human-in-the-loop पैटर्न देता है।
वही सतह जो रात के cron को शक्ति देती है, वही सतह है जो एक मल्टी-स्टेप AI एजेंट को शक्ति देती है जो फ्रंटएंड पर स्ट्रीम करता है और समीक्षा के लिए रुकता है। यह अभिसरण ही है जो फ्रेमवर्क को 2026 मे एक गंभीर नज़र के लायक बनाता है, चाहे आप विश्वसनीय बैकग्राउंड कार्य की आवश्यकता वाले SaaS का संचालन कर रहे हो या सर्वरलेस टाइमआउट से बाहर रहने वाले AI फ़ीचर शिप कर रहे हो।
शुरुआत चेकलिस्ट:
- trigger.dev पर साइन अप करे या self-hosted Docker स्टैक चलाएं
- अपने प्रोजेक्ट मे
npx trigger.dev@latest inittask({ id, run })के साथ अपना पहला टास्क परिभाषित करे- अपने API से इसे ट्रिगर करे और डैशबोर्ड मे रन देखे
- प्रोडक्शन सुरक्षा के लिए
idempotencyKeyऔरconcurrencyKeyजोड़ेuseRealtimeRunको एक status component मे जोड़े- CI से
trigger.dev deploy --env prodके साथ डिप्लॉय करे