@trigger.dev/sdk 4.5.0-rc.6 → 4.5.0-rc.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (191) hide show
  1. package/dist/commonjs/v3/ai.d.ts +171 -5
  2. package/dist/commonjs/v3/ai.js +309 -22
  3. package/dist/commonjs/v3/ai.js.map +1 -1
  4. package/dist/commonjs/v3/chat-server.d.ts +8 -0
  5. package/dist/commonjs/v3/chat-server.js +32 -10
  6. package/dist/commonjs/v3/chat-server.js.map +1 -1
  7. package/dist/commonjs/v3/chat-server.test.js +51 -0
  8. package/dist/commonjs/v3/chat-server.test.js.map +1 -1
  9. package/dist/commonjs/v3/createStartSessionAction.test.js +30 -0
  10. package/dist/commonjs/v3/createStartSessionAction.test.js.map +1 -1
  11. package/dist/commonjs/v3/sessions.d.ts +3 -2
  12. package/dist/commonjs/v3/sessions.js +3 -2
  13. package/dist/commonjs/v3/sessions.js.map +1 -1
  14. package/dist/commonjs/version.js +1 -1
  15. package/dist/esm/v3/ai.d.ts +171 -5
  16. package/dist/esm/v3/ai.js +309 -22
  17. package/dist/esm/v3/ai.js.map +1 -1
  18. package/dist/esm/v3/chat-server.d.ts +8 -0
  19. package/dist/esm/v3/chat-server.js +32 -10
  20. package/dist/esm/v3/chat-server.js.map +1 -1
  21. package/dist/esm/v3/chat-server.test.js +51 -0
  22. package/dist/esm/v3/chat-server.test.js.map +1 -1
  23. package/dist/esm/v3/createStartSessionAction.test.js +30 -0
  24. package/dist/esm/v3/createStartSessionAction.test.js.map +1 -1
  25. package/dist/esm/v3/sessions.d.ts +3 -2
  26. package/dist/esm/v3/sessions.js +3 -2
  27. package/dist/esm/v3/sessions.js.map +1 -1
  28. package/dist/esm/version.js +1 -1
  29. package/docs/ai/prompts.mdx +430 -0
  30. package/docs/ai-chat/actions.mdx +115 -0
  31. package/docs/ai-chat/anatomy.mdx +71 -0
  32. package/docs/ai-chat/backend.mdx +817 -0
  33. package/docs/ai-chat/background-injection.mdx +221 -0
  34. package/docs/ai-chat/changelog.mdx +850 -0
  35. package/docs/ai-chat/chat-local.mdx +174 -0
  36. package/docs/ai-chat/client-protocol.mdx +1081 -0
  37. package/docs/ai-chat/compaction.mdx +411 -0
  38. package/docs/ai-chat/custom-agents.mdx +364 -0
  39. package/docs/ai-chat/error-handling.mdx +415 -0
  40. package/docs/ai-chat/fast-starts.mdx +672 -0
  41. package/docs/ai-chat/frontend.mdx +580 -0
  42. package/docs/ai-chat/how-it-works.mdx +230 -0
  43. package/docs/ai-chat/lifecycle-hooks.mdx +530 -0
  44. package/docs/ai-chat/mcp.mdx +101 -0
  45. package/docs/ai-chat/overview.mdx +90 -0
  46. package/docs/ai-chat/patterns/branching-conversations.mdx +284 -0
  47. package/docs/ai-chat/patterns/code-sandbox.mdx +126 -0
  48. package/docs/ai-chat/patterns/database-persistence.mdx +414 -0
  49. package/docs/ai-chat/patterns/human-in-the-loop.mdx +275 -0
  50. package/docs/ai-chat/patterns/large-payloads.mdx +169 -0
  51. package/docs/ai-chat/patterns/oom-resilience.mdx +120 -0
  52. package/docs/ai-chat/patterns/persistence-and-replay.mdx +211 -0
  53. package/docs/ai-chat/patterns/recovery-boot.mdx +230 -0
  54. package/docs/ai-chat/patterns/skills.mdx +221 -0
  55. package/docs/ai-chat/patterns/sub-agents.mdx +383 -0
  56. package/docs/ai-chat/patterns/tool-result-auditing.mdx +148 -0
  57. package/docs/ai-chat/patterns/trusted-edge-signals.mdx +337 -0
  58. package/docs/ai-chat/patterns/version-upgrades.mdx +172 -0
  59. package/docs/ai-chat/pending-messages.mdx +343 -0
  60. package/docs/ai-chat/prompt-caching.mdx +206 -0
  61. package/docs/ai-chat/quick-start.mdx +161 -0
  62. package/docs/ai-chat/reference.mdx +909 -0
  63. package/docs/ai-chat/server-chat.mdx +263 -0
  64. package/docs/ai-chat/sessions.mdx +333 -0
  65. package/docs/ai-chat/testing.mdx +682 -0
  66. package/docs/ai-chat/tools.mdx +191 -0
  67. package/docs/ai-chat/types.mdx +242 -0
  68. package/docs/ai-chat/upgrade-guide.mdx +515 -0
  69. package/docs/apikeys.mdx +54 -0
  70. package/docs/building-with-ai.mdx +261 -0
  71. package/docs/bulk-actions.mdx +49 -0
  72. package/docs/changelog.mdx +6 -0
  73. package/docs/cli-deploy-commands.mdx +9 -0
  74. package/docs/cli-dev-commands.mdx +9 -0
  75. package/docs/cli-dev.mdx +8 -0
  76. package/docs/cli-init-commands.mdx +58 -0
  77. package/docs/cli-introduction.mdx +25 -0
  78. package/docs/cli-list-profiles-commands.mdx +42 -0
  79. package/docs/cli-login-commands.mdx +33 -0
  80. package/docs/cli-logout-commands.mdx +33 -0
  81. package/docs/cli-preview-archive.mdx +59 -0
  82. package/docs/cli-promote-commands.mdx +9 -0
  83. package/docs/cli-switch.mdx +43 -0
  84. package/docs/cli-update-commands.mdx +42 -0
  85. package/docs/cli-whoami-commands.mdx +33 -0
  86. package/docs/community.mdx +6 -0
  87. package/docs/config/config-file.mdx +602 -0
  88. package/docs/config/extensions/additionalFiles.mdx +38 -0
  89. package/docs/config/extensions/additionalPackages.mdx +40 -0
  90. package/docs/config/extensions/aptGet.mdx +34 -0
  91. package/docs/config/extensions/audioWaveform.mdx +20 -0
  92. package/docs/config/extensions/custom.mdx +380 -0
  93. package/docs/config/extensions/emitDecoratorMetadata.mdx +29 -0
  94. package/docs/config/extensions/esbuildPlugin.mdx +31 -0
  95. package/docs/config/extensions/ffmpeg.mdx +45 -0
  96. package/docs/config/extensions/lightpanda.mdx +56 -0
  97. package/docs/config/extensions/overview.mdx +67 -0
  98. package/docs/config/extensions/playwright.mdx +195 -0
  99. package/docs/config/extensions/prismaExtension.mdx +1014 -0
  100. package/docs/config/extensions/puppeteer.mdx +30 -0
  101. package/docs/config/extensions/pythonExtension.mdx +182 -0
  102. package/docs/config/extensions/syncEnvVars.mdx +291 -0
  103. package/docs/context.mdx +235 -0
  104. package/docs/database-connections.mdx +213 -0
  105. package/docs/deploy-environment-variables.mdx +435 -0
  106. package/docs/deployment/atomic-deployment.mdx +172 -0
  107. package/docs/deployment/overview.mdx +257 -0
  108. package/docs/deployment/preview-branches.mdx +224 -0
  109. package/docs/errors-retrying.mdx +379 -0
  110. package/docs/github-actions.mdx +222 -0
  111. package/docs/github-integration.mdx +136 -0
  112. package/docs/github-repo.mdx +8 -0
  113. package/docs/help-email.mdx +6 -0
  114. package/docs/help-slack.mdx +11 -0
  115. package/docs/hidden-tasks.mdx +56 -0
  116. package/docs/how-it-works.mdx +454 -0
  117. package/docs/how-to-reduce-your-spend.mdx +217 -0
  118. package/docs/idempotency.mdx +504 -0
  119. package/docs/introduction.mdx +223 -0
  120. package/docs/limits.mdx +241 -0
  121. package/docs/logging.mdx +195 -0
  122. package/docs/machines.mdx +952 -0
  123. package/docs/manual-setup.mdx +632 -0
  124. package/docs/mcp-agent-rules.mdx +41 -0
  125. package/docs/mcp-introduction.mdx +385 -0
  126. package/docs/mcp-tools.mdx +273 -0
  127. package/docs/migrating-from-v3.mdx +334 -0
  128. package/docs/observability/dashboards.mdx +102 -0
  129. package/docs/observability/query.mdx +585 -0
  130. package/docs/open-source-contributing.mdx +16 -0
  131. package/docs/open-source-self-hosting.mdx +541 -0
  132. package/docs/private-networking/aws-console-setup.mdx +304 -0
  133. package/docs/private-networking/overview.mdx +144 -0
  134. package/docs/private-networking/troubleshooting.mdx +78 -0
  135. package/docs/queue-concurrency.mdx +354 -0
  136. package/docs/quick-start.mdx +97 -0
  137. package/docs/realtime/auth.mdx +208 -0
  138. package/docs/realtime/backend/overview.mdx +45 -0
  139. package/docs/realtime/backend/streams.mdx +418 -0
  140. package/docs/realtime/backend/subscribe.mdx +225 -0
  141. package/docs/realtime/how-it-works.mdx +94 -0
  142. package/docs/realtime/overview.mdx +63 -0
  143. package/docs/realtime/react-hooks/overview.mdx +73 -0
  144. package/docs/realtime/react-hooks/streams.mdx +449 -0
  145. package/docs/realtime/react-hooks/subscribe.mdx +674 -0
  146. package/docs/realtime/react-hooks/swr.mdx +87 -0
  147. package/docs/realtime/react-hooks/triggering.mdx +194 -0
  148. package/docs/realtime/react-hooks/use-wait-token.mdx +34 -0
  149. package/docs/realtime/run-object.mdx +174 -0
  150. package/docs/replaying.mdx +72 -0
  151. package/docs/request-feature.mdx +6 -0
  152. package/docs/roadmap.mdx +6 -0
  153. package/docs/run-tests.mdx +20 -0
  154. package/docs/run-usage.mdx +113 -0
  155. package/docs/runs/heartbeats.mdx +38 -0
  156. package/docs/runs/max-duration.mdx +139 -0
  157. package/docs/runs/metadata.mdx +734 -0
  158. package/docs/runs/priority.mdx +31 -0
  159. package/docs/runs.mdx +396 -0
  160. package/docs/self-hosting/docker.mdx +458 -0
  161. package/docs/self-hosting/env/supervisor.mdx +74 -0
  162. package/docs/self-hosting/env/webapp.mdx +276 -0
  163. package/docs/self-hosting/kubernetes.mdx +601 -0
  164. package/docs/self-hosting/overview.mdx +108 -0
  165. package/docs/skills.mdx +85 -0
  166. package/docs/tags.mdx +120 -0
  167. package/docs/tasks/overview.mdx +697 -0
  168. package/docs/tasks/scheduled.mdx +382 -0
  169. package/docs/tasks/schemaTask.mdx +413 -0
  170. package/docs/tasks/streams.mdx +884 -0
  171. package/docs/triggering.mdx +1320 -0
  172. package/docs/troubleshooting-alerts.mdx +385 -0
  173. package/docs/troubleshooting-debugging-in-vscode.mdx +8 -0
  174. package/docs/troubleshooting-github-issues.mdx +6 -0
  175. package/docs/troubleshooting-uptime-status.mdx +6 -0
  176. package/docs/troubleshooting.mdx +398 -0
  177. package/docs/upgrading-packages.mdx +80 -0
  178. package/docs/vercel-integration.mdx +207 -0
  179. package/docs/versioning.mdx +56 -0
  180. package/docs/video-walkthrough.mdx +23 -0
  181. package/docs/wait-for-token.mdx +540 -0
  182. package/docs/wait-for.mdx +42 -0
  183. package/docs/wait-until.mdx +53 -0
  184. package/docs/wait.mdx +18 -0
  185. package/docs/writing-tasks-introduction.mdx +33 -0
  186. package/package.json +8 -5
  187. package/skills/trigger-authoring-chat-agent/SKILL.md +296 -0
  188. package/skills/trigger-authoring-tasks/SKILL.md +254 -0
  189. package/skills/trigger-chat-agent-advanced/SKILL.md +368 -0
  190. package/skills/trigger-cost-savings/SKILL.md +116 -0
  191. package/skills/trigger-realtime-and-frontend/SKILL.md +276 -0
@@ -0,0 +1,734 @@
1
+ ---
2
+ title: "Run metadata"
3
+ sidebarTitle: "Metadata"
4
+ description: "Attach structured data to a run and update it as the task progresses. Use metadata for progress tracking, user context, intermediate results, and more."
5
+ ---
6
+
7
+ **Metadata lets you attach up to 256KB of structured data to a run and update it while the task runs.** Subscribers (via [React hooks](/realtime/react-hooks/subscribe) or [backend](/realtime/backend/subscribe)) get those updates in real time, making metadata the simplest way to build progress bars, status indicators, and live dashboards.
8
+
9
+ You can access metadata from inside the run function, via the API, Realtime, and in the dashboard. Common uses: progress percentage, current step, user context, intermediate results.
10
+
11
+ ## Usage
12
+
13
+ Add metadata to a run when triggering by passing it as an object to the `trigger` function:
14
+
15
+ ```ts
16
+ const handle = await myTask.trigger(
17
+ { message: "hello world" },
18
+ { metadata: { user: { name: "Eric", id: "user_1234" } } }
19
+ );
20
+ ```
21
+
22
+ You can get the current metadata at any time by calling `metadata.get()` or `metadata.current()` (only inside a run):
23
+
24
+ ```ts
25
+ import { task, metadata } from "@trigger.dev/sdk";
26
+
27
+ export const myTask = task({
28
+ id: "my-task",
29
+ run: async (payload: { message: string }) => {
30
+ // Get the whole metadata object
31
+ const currentMetadata = metadata.current();
32
+ console.log(currentMetadata);
33
+
34
+ // Get a specific key
35
+ const user = metadata.get("user");
36
+ console.log(user.name); // "Eric"
37
+ },
38
+ });
39
+ ```
40
+
41
+ Any of these methods can be called anywhere "inside" the run function, or a function called from the run function:
42
+
43
+ ```ts
44
+ import { task, metadata } from "@trigger.dev/sdk";
45
+
46
+ export const myTask = task({
47
+ id: "my-task",
48
+ run: async (payload: { message: string }) => {
49
+ doSomeWork();
50
+ },
51
+ });
52
+
53
+ async function doSomeWork() {
54
+ // Set the value of a specific key
55
+ metadata.set("progress", 0.5);
56
+ }
57
+ ```
58
+
59
+ If you call any of the metadata methods outside of the run function, they will have no effect:
60
+
61
+ ```ts
62
+ import { metadata } from "@trigger.dev/sdk";
63
+
64
+ // Somewhere outside of the run function
65
+ function doSomeWork() {
66
+ metadata.set("progress", 0.5); // This will do nothing
67
+ }
68
+ ```
69
+
70
+ This means it's safe to call these methods anywhere in your code, and they will only have an effect when called inside the run function.
71
+
72
+ <Note>
73
+ Calling `metadata.current()` or `metadata.get()` outside of the run function will always return
74
+ undefined.
75
+ </Note>
76
+
77
+ These methods also work inside any task lifecycle hook, either attached to the specific task or the global hooks defined in your `trigger.config.ts` file.
78
+
79
+ <CodeGroup>
80
+
81
+ ```ts myTasks.ts
82
+ import { task, metadata } from "@trigger.dev/sdk";
83
+
84
+ export const myTask = task({
85
+ id: "my-task",
86
+ run: async (payload: { message: string }) => {
87
+ // Your run function work here
88
+ },
89
+ onStart: async () => {
90
+ metadata.set("progress", 0.5);
91
+ },
92
+ onSuccess: async () => {
93
+ metadata.set("progress", 1.0);
94
+ },
95
+ });
96
+ ```
97
+
98
+ ```ts trigger.config.ts
99
+ import { defineConfig, metadata } from "@trigger.dev/sdk";
100
+
101
+ export default defineConfig({
102
+ project: "proj_1234",
103
+ onStart: async () => {
104
+ metadata.set("progress", 0.5);
105
+ },
106
+ });
107
+ ```
108
+
109
+ </CodeGroup>
110
+
111
+ ## Updates API
112
+
113
+ One of the more powerful features of metadata is the ability to update it as the run progresses. This is useful for tracking the progress of a run, storing intermediate results, or storing any other information that changes over time. (Combining metadata with [Realtime](/realtime) can give you a live view of the progress of your runs.)
114
+
115
+ All metadata update methods (accept for `flush` and `stream`) are synchronous and will not block the run function. We periodically flush metadata to the database in the background, so you can safely update the metadata inside a run as often as you need to, without worrying about impacting the run's performance.
116
+
117
+ ### set
118
+
119
+ Set the value of a key in the metadata object:
120
+
121
+ ```ts
122
+ import { task, metadata } from "@trigger.dev/sdk";
123
+
124
+ export const myTask = task({
125
+ id: "my-task",
126
+ run: async (payload: { message: string }) => {
127
+ // Do some work
128
+ metadata.set("progress", 0.1);
129
+
130
+ // Do some more work
131
+ metadata.set("progress", 0.5);
132
+
133
+ // Do even more work
134
+ metadata.set("progress", 1.0);
135
+ },
136
+ });
137
+ ```
138
+
139
+ ### del
140
+
141
+ Delete a key from the metadata object:
142
+
143
+ ```ts
144
+ import { task, metadata } from "@trigger.dev/sdk";
145
+
146
+ export const myTask = task({
147
+ id: "my-task",
148
+ run: async (payload: { message: string }) => {
149
+ // Do some work
150
+ metadata.set("progress", 0.1);
151
+
152
+ // Do some more work
153
+ metadata.set("progress", 0.5);
154
+
155
+ // Remove the progress key
156
+ metadata.del("progress");
157
+ },
158
+ });
159
+ ```
160
+
161
+ ### replace
162
+
163
+ Replace the entire metadata object with a new object:
164
+
165
+ ```ts
166
+ import { task, metadata } from "@trigger.dev/sdk";
167
+
168
+ export const myTask = task({
169
+ id: "my-task",
170
+ run: async (payload: { message: string }) => {
171
+ // Do some work
172
+ metadata.set("progress", 0.1);
173
+
174
+ // Replace the metadata object
175
+ metadata.replace({ user: { name: "Eric", id: "user_1234" } });
176
+ },
177
+ });
178
+ ```
179
+
180
+ ### append
181
+
182
+ Append a value to an array in the metadata object:
183
+
184
+ ```ts
185
+ import { task, metadata } from "@trigger.dev/sdk";
186
+
187
+ export const myTask = task({
188
+ id: "my-task",
189
+ run: async (payload: { message: string }) => {
190
+ // Do some work
191
+ metadata.set("progress", 0.1);
192
+
193
+ // Append a value to an array
194
+ metadata.append("logs", "Step 1 complete");
195
+
196
+ console.log(metadata.get("logs")); // ["Step 1 complete"]
197
+ },
198
+ });
199
+ ```
200
+
201
+ ### remove
202
+
203
+ Remove a value from an array in the metadata object:
204
+
205
+ ```ts
206
+ import { task, metadata } from "@trigger.dev/sdk";
207
+
208
+ export const myTask = task({
209
+ id: "my-task",
210
+ run: async (payload: { message: string }) => {
211
+ // Do some work
212
+ metadata.set("progress", 0.1);
213
+
214
+ // Append a value to an array
215
+ metadata.append("logs", "Step 1 complete");
216
+
217
+ // Remove a value from the array
218
+ metadata.remove("logs", "Step 1 complete");
219
+
220
+ console.log(metadata.get("logs")); // []
221
+ },
222
+ });
223
+ ```
224
+
225
+ ### increment
226
+
227
+ Increment a numeric value in the metadata object:
228
+
229
+ ```ts
230
+ import { task, metadata } from "@trigger.dev/sdk";
231
+
232
+ export const myTask = task({
233
+ id: "my-task",
234
+ run: async (payload: { message: string }) => {
235
+ // Do some work
236
+ metadata.set("progress", 0.1);
237
+
238
+ // Increment a value
239
+ metadata.increment("progress", 0.4);
240
+
241
+ console.log(metadata.get("progress")); // 0.5
242
+ },
243
+ });
244
+ ```
245
+
246
+ ### decrement
247
+
248
+ Decrement a numeric value in the metadata object:
249
+
250
+ ```ts
251
+ import { task, metadata } from "@trigger.dev/sdk";
252
+
253
+ export const myTask = task({
254
+ id: "my-task",
255
+ run: async (payload: { message: string }) => {
256
+ // Do some work
257
+ metadata.set("progress", 0.5);
258
+
259
+ // Decrement a value
260
+ metadata.decrement("progress", 0.4);
261
+
262
+ console.log(metadata.get("progress")); // 0.1
263
+ },
264
+ });
265
+ ```
266
+
267
+ ### stream
268
+
269
+ <Note>
270
+ As of SDK version **4.1.0**, `metadata.stream()` has been replaced by [Realtime Streams
271
+ v2](/tasks/streams). We recommend using the new `streams.pipe()` API for better reliability,
272
+ unlimited stream length, and improved developer experience. The examples below are provided for
273
+ backward compatibility.
274
+ </Note>
275
+
276
+ Capture a stream of values and make the stream available when using Realtime. See our [Realtime Streams v2](/tasks/streams) documentation for the recommended approach.
277
+
278
+ ```ts
279
+ import { task, metadata } from "@trigger.dev/sdk";
280
+
281
+ export const myTask = task({
282
+ id: "my-task",
283
+ run: async (payload: { message: string }) => {
284
+ const readableStream = new ReadableStream({
285
+ start(controller) {
286
+ controller.enqueue("Step 1 complete");
287
+ controller.enqueue("Step 2 complete");
288
+ controller.enqueue("Step 3 complete");
289
+ controller.close();
290
+ },
291
+ });
292
+
293
+ // IMPORTANT: you must await the stream method
294
+ const stream = await metadata.stream("logs", readableStream);
295
+
296
+ // You can read from the returned stream locally
297
+ for await (const value of stream) {
298
+ console.log(value);
299
+ }
300
+ },
301
+ });
302
+ ```
303
+
304
+ `metadata.stream` accepts any `AsyncIterable` or `ReadableStream` object. The stream will be captured and made available in the Realtime API. So for example, you could pass the body of a fetch response to `metadata.stream` to capture the response body and make it available in Realtime:
305
+
306
+ ```ts
307
+ import { task, metadata } from "@trigger.dev/sdk";
308
+
309
+ export const myTask = task({
310
+ id: "my-task",
311
+ run: async (payload: { url: string }) => {
312
+ logger.info("Streaming response", { url });
313
+
314
+ const response = await fetch(url);
315
+
316
+ if (!response.body) {
317
+ throw new Error("Response body is not readable");
318
+ }
319
+
320
+ const stream = await metadata.stream(
321
+ "fetch",
322
+ response.body.pipeThrough(new TextDecoderStream())
323
+ );
324
+
325
+ let text = "";
326
+
327
+ for await (const chunk of stream) {
328
+ logger.log("Received chunk", { chunk });
329
+
330
+ text += chunk;
331
+ }
332
+
333
+ return { text };
334
+ },
335
+ });
336
+ ```
337
+
338
+ Or the results of a streaming call to the OpenAI SDK:
339
+
340
+ ```ts
341
+ import { task, metadata } from "@trigger.dev/sdk";
342
+ import OpenAI from "openai";
343
+
344
+ const openai = new OpenAI({
345
+ apiKey: process.env.OPENAI_API_KEY,
346
+ });
347
+
348
+ export const myTask = task({
349
+ id: "my-task",
350
+ run: async (payload: { prompt: string }) => {
351
+ const completion = await openai.chat.completions.create({
352
+ messages: [{ role: "user", content: payload.prompt }],
353
+ model: "gpt-3.5-turbo",
354
+ stream: true,
355
+ });
356
+
357
+ const stream = await metadata.stream("openai", completion);
358
+
359
+ let text = "";
360
+
361
+ for await (const chunk of stream) {
362
+ logger.log("Received chunk", { chunk });
363
+
364
+ text += chunk.choices.map((choice) => choice.delta?.content).join("");
365
+ }
366
+
367
+ return { text };
368
+ },
369
+ });
370
+ ```
371
+
372
+ ### flush
373
+
374
+ Flush the metadata to the database. The SDK will automatically flush the metadata periodically, so you don't need to call this method unless you need to ensure that the metadata is persisted immediately.
375
+
376
+ ```ts
377
+ import { task, metadata } from "@trigger.dev/sdk";
378
+
379
+ export const myTask = task({
380
+ id: "my-task",
381
+ run: async (payload: { message: string }) => {
382
+ // Do some work
383
+ metadata.set("progress", 0.1);
384
+
385
+ // Flush the metadata to the database
386
+ await metadata.flush();
387
+ },
388
+ });
389
+ ```
390
+
391
+ ## Fluent API
392
+
393
+ All of the update methods can be chained together in a fluent API:
394
+
395
+ ```ts
396
+ import { task, metadata } from "@trigger.dev/sdk";
397
+
398
+ export const myTask = task({
399
+ id: "my-task",
400
+ run: async (payload: { message: string }) => {
401
+ metadata
402
+ .set("progress", 0.1)
403
+ .append("logs", "Step 1 complete")
404
+ .increment("progress", 0.4)
405
+ .decrement("otherProgress", 0.1);
406
+ },
407
+ });
408
+ ```
409
+
410
+ ## Parent & root updates
411
+
412
+ Tasks that have been triggered by a parent task (a.k.a. a "child task") can update the metadata of the parent task. This is useful for propagating progress information up the task hierarchy. You can also update the metadata of the root task (root = the initial task that was triggered externally, like from your backend).
413
+
414
+ To update the parent task's metadata, use the `metadata.parent` accessor:
415
+
416
+ ```ts
417
+ import { task, metadata } from "@trigger.dev/sdk";
418
+
419
+ export const myParentTask = task({
420
+ id: "my-parent-task",
421
+ run: async (payload: { message: string }) => {
422
+ // Do some work
423
+ metadata.set("progress", 0.1);
424
+
425
+ // Trigger a child task
426
+ await childTask.triggerAndWait({ message: "hello world" });
427
+ },
428
+ });
429
+
430
+ export const childTask = task({
431
+ id: "child-task",
432
+ run: async (payload: { message: string }) => {
433
+ // This will update the parent task's metadata
434
+ metadata.parent.set("progress", 0.5);
435
+ },
436
+ });
437
+ ```
438
+
439
+ All of the update methods are available on `metadata.parent` and `metadata.root`:
440
+
441
+ ```ts
442
+ metadata.parent.set("progress", 0.5);
443
+ metadata.parent.append("logs", "Step 1 complete");
444
+ metadata.parent.remove("logs", "Step 1 complete");
445
+ metadata.parent.increment("progress", 0.4);
446
+ metadata.parent.decrement("otherProgress", 0.1);
447
+ metadata.parent.stream("llm", readableStream); // Use streams.pipe() instead (v4.1+)
448
+
449
+ metadata.root.set("progress", 0.5);
450
+ metadata.root.append("logs", "Step 1 complete");
451
+ metadata.root.remove("logs", "Step 1 complete");
452
+ metadata.root.increment("progress", 0.4);
453
+ metadata.root.decrement("otherProgress", 0.1);
454
+ metadata.root.stream("llm", readableStream); // Use streams.pipe() instead (v4.1+)
455
+ ```
456
+
457
+ You can also chain the update methods together:
458
+
459
+ ```ts
460
+ metadata.parent
461
+ .set("progress", 0.1)
462
+ .append("logs", "Step 1 complete")
463
+ .increment("progress", 0.4)
464
+ .decrement("otherProgress", 0.1);
465
+ ```
466
+
467
+ ### Example
468
+
469
+ An example of where you might use parent and root updates is in a task that triggers multiple child tasks in parallel. You could use the parent metadata to track the progress of the child tasks and update the parent task's progress as each child task completes:
470
+
471
+ ```ts
472
+ import { CSVRow, UploadedFileData, parseCSVFromUrl } from "@/utils";
473
+ import { batch, logger, metadata, schemaTask } from "@trigger.dev/sdk";
474
+
475
+ export const handleCSVRow = schemaTask({
476
+ id: "handle-csv-row",
477
+ schema: CSVRow,
478
+ run: async (row, { ctx }) => {
479
+ // Do some work with the row
480
+
481
+ // Update the parent task's metadata with the progress of this row
482
+ metadata.parent.increment("processedRows", 1).append("rowRuns", ctx.run.id);
483
+
484
+ return row;
485
+ },
486
+ });
487
+
488
+ export const handleCSVUpload = schemaTask({
489
+ id: "handle-csv-upload",
490
+ schema: UploadedFileData,
491
+ run: async (file, { ctx }) => {
492
+ metadata.set("status", "fetching");
493
+
494
+ const rows = await parseCSVFromUrl(file.url);
495
+
496
+ metadata.set("status", "processing").set("totalRows", rows.length);
497
+
498
+ const results = await batch.triggerAndWait<typeof handleCSVRow>(
499
+ rows.map((row) => ({ id: "handle-csv-row", payload: row }))
500
+ );
501
+
502
+ metadata.set("status", "complete");
503
+
504
+ return {
505
+ file,
506
+ rows,
507
+ results,
508
+ };
509
+ },
510
+ });
511
+ ```
512
+
513
+ Combined with [Realtime](/realtime), you could use this to show a live progress bar of the CSV processing in your frontend, like this:
514
+
515
+ <video
516
+ src="https://content.trigger.dev/csv-upload-realtime.mp4"
517
+ preload="auto"
518
+ controls={true}
519
+ loop
520
+ muted
521
+ autoPlay={true}
522
+ width="100%"
523
+ height="100%"
524
+ />
525
+
526
+ ## More metadata task examples
527
+
528
+ Using metadata updates in conjunction with our [Realtime React hooks](/realtime/react-hooks/overview) can be a powerful way to build real-time UIs. Here are some example tasks demonstrating how to use metadata in your tasks to track progress, status, and more:
529
+
530
+ ### Progress tracking
531
+
532
+ Track progress with percentage and current step:
533
+
534
+ ```ts
535
+ import { task, metadata } from "@trigger.dev/sdk";
536
+
537
+ export const batchProcessingTask = task({
538
+ id: "batch-processing",
539
+ run: async (payload: { records: any[] }) => {
540
+ for (let i = 0; i < payload.records.length; i++) {
541
+ const record = payload.records[i];
542
+
543
+ // Update progress
544
+ metadata.set("progress", {
545
+ step: i + 1,
546
+ total: payload.records.length,
547
+ percentage: Math.round(((i + 1) / payload.records.length) * 100),
548
+ currentRecord: record.id,
549
+ });
550
+
551
+ await processRecord(record);
552
+ }
553
+ },
554
+ });
555
+ ```
556
+
557
+ ### Status updates with logs
558
+
559
+ Append log entries while maintaining status:
560
+
561
+ ```ts
562
+ import { task, metadata } from "@trigger.dev/sdk";
563
+
564
+ export const deploymentTask = task({
565
+ id: "deployment",
566
+ run: async (payload: { version: string }) => {
567
+ metadata.set("status", "initializing");
568
+ metadata.append("logs", "Starting deployment...");
569
+
570
+ // Step 1
571
+ metadata.set("status", "building");
572
+ metadata.append("logs", "Building application...");
573
+ await buildApplication();
574
+
575
+ // Step 2
576
+ metadata.set("status", "deploying");
577
+ metadata.append("logs", "Deploying to production...");
578
+ await deployToProduction();
579
+
580
+ // Step 3
581
+ metadata.set("status", "verifying");
582
+ metadata.append("logs", "Running health checks...");
583
+ await runHealthChecks();
584
+
585
+ metadata.set("status", "completed");
586
+ metadata.append("logs", "Deployment successful!");
587
+ },
588
+ });
589
+ ```
590
+
591
+ ### User context and notifications
592
+
593
+ Store user information and notification preferences:
594
+
595
+ ```ts
596
+ import { task, metadata } from "@trigger.dev/sdk";
597
+
598
+ export const userTask = task({
599
+ id: "user-task",
600
+ run: async (payload: { userId: string; action: string }) => {
601
+ // Set user context in metadata
602
+ metadata.set("user", {
603
+ id: payload.userId,
604
+ action: payload.action,
605
+ startedAt: new Date().toISOString(),
606
+ });
607
+
608
+ // Update status for user notifications
609
+ metadata.set("notification", {
610
+ type: "info",
611
+ message: `Starting ${payload.action} for user ${payload.userId}`,
612
+ });
613
+
614
+ await performUserAction(payload);
615
+
616
+ metadata.set("notification", {
617
+ type: "success",
618
+ message: `${payload.action} completed successfully`,
619
+ });
620
+ },
621
+ });
622
+ ```
623
+
624
+ ## Metadata propagation
625
+
626
+ Metadata is NOT propagated to child tasks. If you want to pass metadata to a child task, you must do so explicitly:
627
+
628
+ ```ts
629
+ import { task, metadata } from "@trigger.dev/sdk";
630
+
631
+ export const myTask = task({
632
+ id: "my-task",
633
+ run: async (payload: { message: string }) => {
634
+ await metadata.set("progress", 0.5);
635
+ await childTask.trigger(payload, { metadata: metadata.current() });
636
+ },
637
+ });
638
+ ```
639
+
640
+ ## Type-safe metadata
641
+
642
+ The metadata APIs are currently loosely typed, accepting any object that is JSON-serializable:
643
+
644
+ ```ts
645
+ // ❌ You can't pass a top-level array
646
+ const handle = await myTask.trigger(
647
+ { message: "hello world" },
648
+ { metadata: [{ user: { name: "Eric", id: "user_1234" } }] }
649
+ );
650
+
651
+ // ❌ You can't pass a string as the entire metadata:
652
+ const handle = await myTask.trigger(
653
+ { message: "hello world" },
654
+ { metadata: "this is the metadata" }
655
+ );
656
+
657
+ // ❌ You can't pass in a function or a class instance
658
+ const handle = await myTask.trigger(
659
+ { message: "hello world" },
660
+ { metadata: { user: () => "Eric", classInstance: new HelloWorld() } }
661
+ );
662
+
663
+ // ✅ You can pass in dates and other JSON-serializable objects
664
+ const handle = await myTask.trigger(
665
+ { message: "hello world" },
666
+ { metadata: { user: { name: "Eric", id: "user_1234" }, date: new Date() } }
667
+ );
668
+ ```
669
+
670
+ <Note>
671
+ If you pass in an object like a Date, it will be serialized to a string when stored in the
672
+ metadata. That also means that when you retrieve it using `metadata.get()` or
673
+ `metadata.current()`, you will get a string back. You will need to deserialize it back to a Date
674
+ object if you need to use it as a Date.
675
+ </Note>
676
+
677
+ We recommend wrapping the metadata API in a [Zod](https://zod.dev) schema (or your validator library of choice) to provide type safety:
678
+
679
+ ```ts
680
+ import { task, metadata } from "@trigger.dev/sdk";
681
+ import { z } from "zod";
682
+
683
+ const Metadata = z.object({
684
+ user: z.object({
685
+ name: z.string(),
686
+ id: z.string(),
687
+ }),
688
+ date: z.coerce.date(), // Coerce the date string back to a Date object
689
+ });
690
+
691
+ type Metadata = z.infer<typeof Metadata>;
692
+
693
+ // Helper function to get the metadata object in a type-safe way
694
+ // Note: you would probably want to use .safeParse instead of .parse in a real-world scenario
695
+ function getMetadata() {
696
+ return Metadata.parse(metadata.current());
697
+ }
698
+
699
+ export const myTask = task({
700
+ id: "my-task",
701
+ run: async (payload: { message: string }) => {
702
+ const metadata = getMetadata();
703
+ console.log(metadata.user.name); // "Eric"
704
+ console.log(metadata.user.id); // "user_1234"
705
+ console.log(metadata.date); // Date object
706
+ },
707
+ });
708
+ ```
709
+
710
+ ## Inspecting metadata
711
+
712
+ ### Dashboard
713
+
714
+ You can view the metadata for a run in the Trigger.dev dashboard. The metadata will be displayed in the run details view:
715
+
716
+ ![View run metadata dashboard](/images/run-metadata.png)
717
+
718
+ ### API
719
+
720
+ You can use the `runs.retrieve()` SDK function to get the metadata for a run:
721
+
722
+ ```ts
723
+ import { runs } from "@trigger.dev/sdk";
724
+
725
+ const run = await runs.retrieve("run_1234");
726
+
727
+ console.log(run.metadata);
728
+ ```
729
+
730
+ See the [API reference](/management/runs/retrieve) for more information.
731
+
732
+ ## Size limit
733
+
734
+ The maximum size of the metadata object is 256KB. If you exceed this limit, the SDK will throw an error. If you are self-hosting Trigger.dev, you can increase this limit by setting the `TASK_RUN_METADATA_MAXIMUM_SIZE` environment variable. For example, to increase the limit to 16KB, you would set `TASK_RUN_METADATA_MAXIMUM_SIZE=16384`.