npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

workflow-cron-sleep

v1.0.2

Published

Sleep until the next cron expression occurrence in Vercel Workflows

Readme

workflow-cron-sleep

Sleep until the next cron expression occurrence in Vercel Workflows.

What This Does

cronSleep pauses your workflow until the next single occurrence of a cron expression. It is not a recurring cron job scheduler.

// This sleeps ONCE until the next 9 AM, then continues execution
await cronSleep("0 9 * * *", { timezone: "America/New_York" })

If you need recurring behavior, you'll need to structure your workflows to handle that (see Recurring Workflows below).

Installation

npm install workflow-cron-sleep

Quick Start

import { cronSleep } from "workflow-cron-sleep"

async function myWorkflow() {
    "use workflow"
    
    // Sleep until the next 9 AM Eastern Time
    await cronSleep("0 9 * * *", { timezone: "America/New_York" })
    
    // This runs once at 9 AM, then the workflow ends
    console.log("It's 9 AM!")
}

Timezone Behavior

Important: When no timezone is specified, cronSleep uses the local system timezone of the server running your workflow. On Vercel, this depends on the region your function is deployed to.

For predictable behavior, always specify a timezone:

// Recommended: Explicit timezone
await cronSleep("0 9 * * *", { timezone: "America/New_York" })

// UTC for timezone-agnostic scheduling
await cronSleep("0 14 * * *", { timezone: "UTC" })

// Not recommended: Server's local timezone (varies by region)
await cronSleep("0 9 * * *")

API

cronSleep(cronExpression, options?)

Sleeps until the next occurrence of a cron expression.

Parameters

| Parameter | Type | Description | |-----------|------|-------------| | cronExpression | string | A valid cron expression (e.g., "0 9 * * *") | | options.timezone | string (optional) | IANA timezone (e.g., "America/New_York", "UTC") |

Returns

Promise<void> - Resolves when the workflow resumes at the scheduled time.

Throws

Throws an error if the cron expression is invalid or has no future occurrences.

Cron Expression Reference

| Expression | Description | |------------|-------------| | 0 9 * * * | Every day at 9:00 AM | | 30 8 * * 1 | Every Monday at 8:30 AM | | 0 0 1 * * | First day of every month at midnight | | 0 */2 * * * | Every 2 hours | | 0 9 * * 1-5 | Weekdays at 9:00 AM | | 59 23 L * * | Last day of every month at 11:59 PM |

Recurring Workflows

Since cronSleep only sleeps until the next occurrence, you need to design your workflow architecture to handle recurring schedules.

Pattern: While Loop Scheduler

The simplest approach is a single workflow with a while (true) loop that sleeps and triggers your business logic workflow repeatedly:

workflows/report-scheduler.ts - The scheduler workflow

import { cronSleep } from "workflow-cron-sleep"
import { triggerReportProcessor } from "./steps"

export interface ReportSchedulerInput {
    reportId: string
    cronExpression: string
}

export async function reportScheduler(input: ReportSchedulerInput) {
    "use workflow"
    
    const { reportId, cronExpression } = input
    
    while (true) {
        // Wait for the next scheduled time
        await cronSleep(cronExpression, { timezone: "America/New_York" })
        
        // Trigger the processor workflow
        await triggerReportProcessor(reportId)
    }
}

workflows/steps.ts - Step function to start the processor

import { start } from "workflow/api"
import { reportProcessorWorkflow } from "./report-processor"

export async function triggerReportProcessor(reportId: string) {
    "use step"
    await start(reportProcessorWorkflow, [{ reportId }])
}

workflows/report-processor.ts - The processor workflow (business logic)

export interface ReportProcessorInput {
    reportId: string
}

export async function reportProcessorWorkflow(input: ReportProcessorInput) {
    "use workflow"
    
    const { reportId } = input
    
    // Your business logic here - completely agnostic to scheduling
    await generateReport(reportId)
    await sendNotifications(reportId)
}

Starting and Canceling

import { start, getRun } from "workflow/api"
import { reportScheduler } from "./workflows/report-scheduler"

// Start the cron scheduler
const run = await start(reportScheduler, [{
    reportId: "daily-report",
    cronExpression: "0 9 * * *"
}])

// Save the run ID to cancel later
await db.cronJobs.create({ runId: run.id })

// To cancel the cron (stops the while loop)
const currentRun = getRun(run.id)
await currentRun.cancel()

This pattern keeps your scheduling and business logic decoupled. The scheduler runs forever, triggering your processor workflow on schedule. Save the runId so you can cancel if the cron expression changes or the job is no longer needed.

Requirements

  • workflow package (Vercel Workflows SDK)

License

MIT