Jacob Paris
← Back to all content

Wait for a BullMQ job to complete with Remix Deferred Loaders

Remix's Defer API is a feature that allows you to return an unresolved Promise from a loader. The page will server-side render without waiting for the promise to resolve, and then when it finally does, the client will re-render with the new data.

This works especially well with queued jobs, where a user may try to look at result data before the job has finished processing. In this case, we can return a Promise that will resolve when the job is finished, and the client will re-render with the new data.

BullMQ is a modern, fast, and robust queue system for Node.js. It is a successor to the popular Bull library, and is built on top of Redis. If you've integrated BullMQ into your app, you can use the Defer API to return a Promise that will resolve when the job is finished.

import { defer, redirect } from "@remix-run/node"
import { processItemQueue } from "~/queue.server.ts"
export async function loader({
}: LoaderFunctionArgs) {
const hash = params.hash
if (!hash) {
return redirect("/")
const job = await processItemQueue.getJob(hash)
if (!job) {
return redirect("/")
const TIMEOUT_MILLISECONDS = 30 * 1000
return defer({
job: job.waitUntilFinished(
export default function Index() {
const data = useLoaderData()
return (
<Suspense fallback={<p> loading… </p>}>
errorElement={<p>Error loading job</p>}
{(results) => <pre>{results}</pre>}

As a next step, you can use event streams to update the page as the job progresses.

Professional headshot

Hey there! I'm a developer, designer, and digital nomad building cool things with Remix, and I'm also writing Moulton, the Remix Community Newsletter

About once per month, I send an email with:

  • New guides and tutorials
  • Upcoming talks, meetups, and events
  • Cool new libraries and packages
  • What's new in the latest versions of Remix

Stay up to date with everything in the Remix community by entering your email below.

Unsubscribe at any time.