It’s hard to build a Next.js app that reliably handles tasks that run longer than HTTP request timeouts. Use cases like these include:
- Processing large files in the background
- Handling webhook events in order
- Sending batches of emails on a schedule
The standard solution is to set up a separate service running a queueing system like BullMQ. This works, but it means deploying and maintaining additional infrastructure alongside your Next.js app.
DBOS offers a different approach. It’s an open-source TypeScript library that helps you durably execute long-running tasks directly in your Next.js app. It works by storing execution state in your database and if necessary, retrieving that data to resume execution after a failure. This ensures your tasks complete reliably, even if users disconnect, servers restart, or other interruptions occur.
How to Build a Durable Next.js App
Let’s build a simple Next.js app that runs a reliable background task. The app has two buttons: one that launches a background task and one that crashes the app. We’ll show that no matter how many times you crash the app, upon restart the background task will continue from where it left off.
![Building durable Next.js workflows with DBOS](https://cdn.prod.website-files.com/672411cbf038560468c9e68f/67a65f97340d250cce0bde77_AD_4nXcw8UXioGxEVHD15_0_aMRod54Vy7RBKt7QIpkFzJA1EEO975zbNGVX-Hr6oIXs98SA4V327rG_KKEWWdErPg7JwoaANEB_zvthZOVHSTf8hRmrv7sRM662RpZMdYzlJU1eeVV0Aw.png)
Here’s the code for the background task. Each task runs ten steps, and each step sleeps for two seconds. The magic here is in the decorators: @DBOS.workflow() and @DBOS.step().
![Durable Next.js execution code](https://cdn.prod.website-files.com/672411cbf038560468c9e68f/67a65f9781f70ab208c8d815_AD_4nXcArU-VLd4fFA2DpPI_0U_g5B-SCWqEal6fYh8gVt1Bdxu-qelWLJoQSq4_XFsRQs4VeYR1AvTsmDwDFxwjS93kTcUHZntDYxTzai98Ypfo7OhjHJlBS0zbj1nksuzPSUAsYrna.png)
The decorators store the state of your program–what background tasks are running and how many steps they’ve completed–in a database:
![Durable Next.js workflow execution diagram](https://cdn.prod.website-files.com/672411cbf038560468c9e68f/67a65f96b71f27d8aed66c33_AD_4nXea2atHsXnlNkaarQ8eQEd1Sl4ErFwOnCD2Np1o4LuI0S6I15VTSuby7eurPIJDJbIssdVkW6gQ0v_AtNRnenvjVuET8DpOCIGrVZN-B-F16OFU2V9s6_MBsc0J0JSR031QQ5A0Ew.png)
This acts as a “save point” in your app. If it fails at any point, the background task can be restarted and picks up from the last stored checkpoint.
![](https://cdn.prod.website-files.com/672411cbf038560468c9e68f/67a65f9652b6bcb7ce454ca3_AD_4nXfaeHpD-4kaTP-cVuHCs0i2wEvr_yjxF6SumSMZfciF4POZPVj0q4keyyGJjbOgP5-CKmz8plgr-HGMaOo3K-gPlUrF9FTHmMYPmRY4Hz2Yn3neFnpVOQDnLg8YGb6qeebMp-OQ.jpeg)
Because the background task is just a normal TypeScript function, you can start it from a Next.js server action. Here’s the code for the app’s server actions. The first action starts a background task, the second looks up the progress of a background task to display on the screen, and the third crashes the app–for demonstration purposes only 🙂.
![Durable Next.js execution code example](https://cdn.prod.website-files.com/672411cbf038560468c9e68f/67a65f96a076faf602cc33d3_AD_4nXcVcnaFcXttR3svTiZcZqfvxS_Ga7rt0MgnEWPtwTFBCr_SfSFkZY2qt4tUe2KyeI_4R7NsaXyHKeN7TMmj3y9-SsXPOx0INC_VUzqNqtFjphzNliAtErs7XT4UJnamQj7OYZ3I9g.png)
You can call these server actions from buttons in your frontend code:
![Front-end code for durable Next.js example](https://cdn.prod.website-files.com/672411cbf038560468c9e68f/67a65f9662daf64d1b3c5545_AD_4nXet4adD7CvD5Nwh-8iHuREj-b3lSQrj86VDmv57H_OEA16kO1u8uYydaYNXed7yJLp_BP6grvL2w5L9A7LYQD6GYNA3xJgfTx_8769rZbp-XIRqh2ydrekCx2m9YRsM699_B4i_5g.png)
Run the Durable Next.js Example App Yourself
To try out this app yourself, initialize it from a template:
npx @dbos-inc/create -t dbos-nextjs-starter
Launch the development server:
npm run dev
Open localhost:3000 to see the app in action. Try launching a background task and crashing the app – you'll see the task resume exactly where it left off when you restart.
This example shows how to handle long-running tasks, but DBOS can help with other reliability challenges too:
- Running tasks in order with queues (like processing webhooks)
- Scheduling periodic jobs (like sending weekly emails)
- Automatically retrying failed operations