--- title: "Upgrading from v2" description: "How to upgrade v2 jobs to v3 tasks, and how to use them together." --- ## v3 feature matrix As v3 is in Developer Preview there are some features that are not yet available. Take a look at the [Feature matrix](/v3/feature-matrix) to check what is currently available. ## Changes from v2 to v3 The main difference is that things in v3 are far simpler. That's because in v3 your code is deployed to our servers (unless you self-host) which are long-running. 1. No timeouts. 2. No `io.runTask()` (and no `cacheKeys`). 3. Just use official SDKs, not integrations. 4. `task`s are the new primitive, not `job`s. ## OpenAI example comparison This is a (very contrived) example that does a long OpenAI API call (>10s), stores the result in a database, waits for 5 mins, and then returns the result. ### v2 First, the old v2 code, which uses the OpenAI integration. Comments inline: ```ts v2 OpenAI task import { client } from "~/trigger"; import { eventTrigger } from "@trigger.dev/sdk"; //1. A Trigger.dev integration for OpenAI import { OpenAI } from "@trigger.dev/openai"; const openai = new OpenAI({ id: "openai", apiKey: process.env["OPENAI_API_KEY"]!, }); //2. Use the client to define a "Job" client.defineJob({ id: "openai-tasks", name: "OpenAI Tasks", version: "0.0.1", trigger: eventTrigger({ name: "openai.tasks", schema: z.object({ prompt: z.string(), }), }), //3. integrations are added and come through to `io` in the run fn integrations: { openai, }, run: async (payload, io, ctx) => { //4. You use `io` to get the integration //5. Also note that "backgroundCreate" was needed for OpenAI // to do work that lasted longer than your serverless timeout const chatCompletion = await io.openai.chat.completions.backgroundCreate( //6. You needed to add "cacheKeys" to any "task" "background-chat-completion", { messages: [{ role: "user", content: payload.prompt }], model: "gpt-3.5-turbo", } ); const result = chatCompletion.choices[0]?.message.content; if (!result) { //7. throwing an error at the top-level in v2 failed the task immediately throw new Error("No result from OpenAI"); } //8. io.runTask needed to be used to prevent work from happening twice const dbRow = await io.runTask("store-in-db", async (task) => { //9. Custom logic can be put here // Anything returned must be JSON-serializable, so no Date objects etc. return saveToDb(result); }); //10. Wait for 5 minutes. // You need a cacheKey and the 2nd param is a number await io.wait("wait some time", 60 * 5); //11. Anything returned must be JSON-serializable, so no Date objects etc. return result; }, }); ``` ### v3 In v3 we eliminate a lot of code mainly because we don't need tricks to try avoid timeouts. Here's the equivalent v3 code: ```ts v3 OpenAI task import { logger, task, wait } from "@trigger.dev/sdk/v3"; //1. Official OpenAI SDK import OpenAI from "openai"; const openai = new OpenAI({ apiKey: process.env.OPENAI_API_KEY, }); //2. Jobs don't exist now, use "task" export const openaiTask = task({ id: "openai-task", //3. Retries happen if a task throws an error that isn't caught // The default settings are in your trigger.config.ts (used if not overriden here) retry: { maxAttempts: 3, }, run: async (payload: { prompt: string }) => { //4. Use the official SDK //5. No timeouts, so this can take a long time const chatCompletion = await openai.chat.completions.create({ messages: [{ role: "user", content: payload.prompt }], model: "gpt-3.5-turbo", }); const result = chatCompletion.choices[0]?.message.content; if (!result) { //6. throwing an error at the top-level will retry the task (if retries are enabled) throw new Error("No result from OpenAI"); } //7. No need to use runTask, just call the function const dbRow = await saveToDb(result); //8. You can provide seconds, minutes, hours etc. // You don't need cacheKeys in v3 await wait.for({ minutes: 5 }); //9. You can return anything that's serializable using SuperJSON // That includes undefined, Date, bigint, RegExp, Set, Map, Error and URL. return result; }, }); ``` ## Triggering tasks comparison ### v2 In v2 there were different trigger types and triggering each type was slightly different. ```ts v2 triggering async function yourBackendFunction() { //1. for `eventTrigger` you use `client.sendEvent` const event = await client.sendEvent({ name: "openai.tasks", payload: { prompt: "Create a good programming joke about background jobs" }, }); //2. for `invokeTrigger` you'd call `invoke` on the job const { id } = await invocableJob.invoke({ prompt: "What is the meaning of life?", }); } ``` ### v3 We've unified triggering in v3. You use `trigger()` or `batchTrigger()` which you can do on any type of task. Including scheduled, webhooks, etc if you want. ```ts v3 triggering async function yourBackendFunction() { //call `trigger()` on any task const handle = await openaiTask.trigger({ prompt: "Tell me a programming joke", }); } ``` ## Upgrading your project Just follow the [v3 quick start](/v3/quick-start) to get started with v3. Our new CLI will take care of the rest. ## Using v2 together with v3 You can use v2 and v3 in the same codebase. This can be useful where you already have v2 jobs or where we don't support features you need (yet).