Defer is reaching the end of its service life on May 1, 2024. Please reach out to for further information.
February 2nd, 2024

Advanced Scheduling with the Defer public API v2

Charly PolyCharly PolyCEO
Bryan FriminBryan FriminCTO
Emile RéEmile Founding Engineer

Today we're reaching GA for our public API v2, granting you direct access to Defer's Epoque Scheduler to build more advanced scheduling use cases.

Defer enabled hundreds of Node.js developers to quickly set up CRON and background tasks, without any infrastructure work. Still, many of our users reached out for more flexibility with Defer's scheduling capabilities, such as rescheduling or listing executions programmatically.

A direct access to the Scheduler

The v2 Defer public API comes with 7 new endpoints, including 5 available from the @defer/client for faster iterations:


Rescheduling an execution no longer requires to cancel and re-enqueue an execution.

Also, by omitting the second argument, rescheduleExecution() can be used to trigger the immediate run of the scheduled execution.


Many of you leverage Defer to orchestrate workflows. Before being able to list executions, keeping track of pending or running executions required to store maps of IDs and workflow ID within your application.

listExecutions() is now a powerful way to gather executions given a set of criteria:

  • listing all executions linked to a workflowID by using the metadata filter
  • list all child executions with the executedBy filter

Example: listing documents processing progress within your application

The following code snippet is a Next.js Server Action used on by a Client Component to list the status of a given user's documents processing:

// src/actions/listUserDocumentsProcessing.ts"use server"
import { listExecutions } from "@defer/client"
export async function listUserDocumentsProcessing(  userId: string,  cursor?: string) {  const { data, pageInfo } = await listExecutions(    {      first: 50,      ...(cursor ? { after: cursor } : {}),    },    {      metadata: [        {          key: "type",          values: ["video-transcript", "document-summarization"],        },        { key: "user_id", values: [userId] },      ],    }  )
  const processings ={ createdAt, functionName, state }) => ({    status: state,    type:      functionName === "videoTranscript" ? "transcript" : "summarization",    createdAt,  }))
  return {    processings,    hasNextPage: pageInfo.hasNextPage,    cursor: pageInfo.endCursor,  }}


For faster performance, starting @defer/client@2.0.0, getExecution() no longer returns the execution's result. You can now use getExecutionResult() to get the full result, along with the GET /executions/{execution-id}/arguments and /executions/{execution-id}/logs for more details on an execution's run.


A faster way to access an execution's retries to perform follow-up actions (ex: custom retry automation) or integrate with your application (ex: document processing user interface).


This new method, combined with listExecutionAttempts() or getExecution() enable you to implement more complex retry system by automating manual reruns.

Example: Enabling end-users to retry document processing

The above 2 methods can be leveraged to empower our documents processing end-user to re-run some transcripts and summarization work.

The UI created using listUserDocumentsProcessing() Next.js Server Action could allow user to inspect individual processing and provide the list of retries and error return by leveraging listExecutionAttempts() and getExecutionResult(). Then, again, with a Next.js Server Action, a end-user could choose to re-run a processing with the help of reRunExecution():

// src/actions/rerunUserDocumentProcessing.ts"use server"
import { reRunExecution } from "@defer/client"
export async function rerunUserDocumentProcessing(executionID: string) {  await reRunExecution(executionID)  return}

// src/app/documentProcessing/[id].tsximport { rerunUserDocumentProcessing } from "@/actions/rerunUserDocumentProcessing"
export default function DocumentProcessing() {  const router = useRouter()  const rerun = rerunUserDocumentProcessing.bind(null,  // ...  return (    <main>      <div>        {/* ... */}        <form action={rerun}>          <button type="submit">Re-run processing</button>        </form>      </div>    </main>  )}

Going further

Get the full description of the 7 newly available methods and endpoints in our References documentation.

Join the community and learn how to get started, and provide feedback.
Stay tuned about our latest product and company updates.
Start creating background jobs in minutes.
Copyright ©2024 Defer Inc.