🎩 You're Invited:Meet the Socket team at Black Hat in Las Vegas, August 3-6.RSVP
Sign In

croncall

Package Overview
Dependencies
Maintainers
1
Versions
2
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

croncall

Cron jobs for Next.js. Serverless-native.

latest
Source
npmnpm
Version
0.1.1
Version published
Weekly downloads
20
Maintainers
1
Weekly downloads
 
Created
Source

croncall

Cron jobs for Next.js. Serverless-native.

Zero runtime dependencies. TypeScript-first. Works with Vercel Cron out of the box.

Install

npm install croncall

Quick Start

1. Define your jobs

// lib/jobs.ts
import { createClockTower } from "croncall";

export const tower = createClockTower({
  jobs: {
    syncUsers: {
      schedule: "0 * * * *", // every hour
      handler: async () => {
        await db.syncUsersFromExternalAPI();
      },
      description: "Sync users from external API",
      retry: { maxAttempts: 3, backoff: "exponential" },
      timeout: 30_000,
    },
    sendDigest: {
      schedule: "0 9 * * 1", // Mondays at 9 AM UTC
      handler: async () => {
        await email.sendWeeklyDigest();
      },
      description: "Send weekly digest email",
    },
    cleanupSessions: {
      schedule: "@daily",
      handler: async () => {
        await db.deleteExpiredSessions();
      },
    },
  },
  secret: process.env.CRON_SECRET,
});

2. Create a route handler

// app/api/cron/route.ts
import { createCronHandler } from "croncall/next";
import { tower } from "@/lib/jobs";

export const GET = createCronHandler(tower);

3. Deploy

Add cron schedules to vercel.json:

{
  "crons": [
    { "path": "/api/cron?job=syncUsers", "schedule": "0 * * * *" },
    { "path": "/api/cron?job=sendDigest", "schedule": "0 9 * * 1" },
    { "path": "/api/cron?job=cleanupSessions", "schedule": "0 0 * * *" }
  ]
}

Or generate it programmatically:

import { generateVercelCron } from "croncall/next";
import { tower } from "./lib/jobs";

console.log(JSON.stringify(generateVercelCron(tower, "/api/cron"), null, 2));

Job Definition

Each job has:

FieldTypeRequiredDescription
schedulestringYesCron expression or shortcut
handler() => Promise<void>YesAsync function to execute
descriptionstringNoHuman-readable description
retry{ maxAttempts, backoff, baseDelay? }NoRetry on failure
timeoutnumberNoMax execution time in ms

Cron Syntax

Standard 5-field cron expressions:

 ┌───────────── minute (0-59)
 │ ┌───────────── hour (0-23)
 │ │ ┌───────────── day of month (1-31)
 │ │ │ ┌───────────── month (1-12)
 │ │ │ │ ┌───────────── day of week (0-6, Sun=0)
 │ │ │ │ │
 * * * * *

Supported features:

  • Wildcards: *
  • Ranges: 1-5
  • Lists: 1,3,5
  • Steps: */15, 1-30/2
  • Month names: jan, feb, ..., dec
  • Day names: sun, mon, ..., sat

Shortcuts:

ShortcutEquivalent
@hourly0 * * * *
@daily0 0 * * *
@midnight0 0 * * *
@weekly0 0 * * 0
@monthly0 0 1 * *
@yearly0 0 1 1 *
@annually0 0 1 1 *

Vercel Cron Integration

Clocktower is designed to work with Vercel Cron Jobs.

Authentication

Vercel sends a CRON_SECRET environment variable and includes it in the Authorization: Bearer <secret> header. Clocktower validates this automatically:

  • Checks options.secret passed to createCronHandler
  • Falls back to config.secret from createClockTower
  • Falls back to process.env.CRON_SECRET

If no secret is configured, requests are allowed without authentication.

Generating vercel.json

import { generateVercelCron } from "croncall/next";
import { tower } from "./lib/jobs";

const crons = generateVercelCron(tower, "/api/cron");
// [{ path: "/api/cron?job=syncUsers", schedule: "0 * * * *" }, ...]

Manual Triggers

Run a specific job on demand:

const result = await tower.run("syncUsers");
console.log(result);
// { success: true, duration: 1234 }

Run all due jobs:

const results = await tower.runDue();
for (const [name, result] of results) {
  console.log(`${name}: ${result.success ? "ok" : result.error}`);
}

Via HTTP (useful for testing):

# Run a specific job
curl http://localhost:3000/api/cron?job=syncUsers \
  -H "Authorization: Bearer your-secret"

# Run all due jobs
curl http://localhost:3000/api/cron \
  -H "Authorization: Bearer your-secret"

Inspect the Schedule

const schedule = tower.schedule();
// [
//   { jobName: "syncUsers", nextRun: 2026-03-26T15:00:00.000Z, schedule: "0 * * * *" },
//   { jobName: "sendDigest", nextRun: 2026-03-30T09:00:00.000Z, schedule: "0 9 * * 1" },
// ]

Retry & Error Handling

Configure retries per job:

{
  retry: {
    maxAttempts: 3,          // retry up to 3 times after initial failure
    backoff: "exponential",  // or "linear"
    baseDelay: 1000,         // 1s base delay (default)
  }
}
  • Exponential: delays of 1s, 2s, 4s, 8s, ...
  • Linear: delays of 1s, 2s, 3s, 4s, ...

The JobResult includes retryCount when retries were attempted:

const result = await tower.run("syncUsers");
if (!result.success) {
  console.error(`Failed after ${result.retryCount} retries: ${result.error}`);
}

TypeScript

All types are exported:

import type {
  CronExpression,
  JobDefinition,
  JobRegistry,
  ClockTowerConfig,
  ClockTower,
  JobResult,
  JobExecution,
  ScheduleEntry,
  RetryConfig,
} from "croncall";

Job names are fully typed:

const tower = createClockTower({
  jobs: {
    syncUsers: { schedule: "@hourly", handler: async () => {} },
  },
});

tower.run("syncUsers");    // OK
tower.run("nonexistent");  // Type error

License

MIT

Keywords

cron

FAQs

Package last updated on 29 Mar 2026

Did you know?

Socket

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Install

Related posts