op3 Logo

op3

File-based task runner for Node.js with unmatched flexibility and DX.

What is op3?

op3 is a zero-config task scheduler for JavaScript and TypeScript. Write scheduled tasks as simple files, run one command, and get a built-in dashboard with execution history, logs, and performance metrics—no Redis, no MongoDB, no infrastructure.

npx @op3/cli init && npx @op3/cli run

Quick Start

1 Install

bash
# Global installation
npm install -g @op3/cli
# then use it as a command
op3 init
op3 run

# Or use without installing
npx @op3/cli init
npx @op3/cli run

2 Initialize Project

bash
op3 init

Creates:

  • op3.config.json — Configuration file
  • tasks/ — Directory for your task files

3 Add Your First Task

bash
op3 add my-task.ts

This creates tasks/my-task.ts with a template:

typescript
import { EntryContext } from "@op3/cli";

export const timing = "*/5 * * * * *"; // Every 5 seconds

export const task = async (ctx: EntryContext) => {
  console.log("Task executed at:", new Date().toISOString());
};

4 Run

bash
op3 run

Opens the dashboard at http://localhost:8787 and starts scheduling all tasks.


Commands

Command Description
op3 init Initialize op3 in current directory
op3 add <file> Create a new task file in tasks/
op3 run Start scheduler and dashboard
op3 run --match <pattern> Run only tasks matching glob pattern
op3 run:single <file> Run single task with optional custom timing
op3 run:once <file> Execute task once (no scheduling)

Examples

bash
# Run all tasks
op3 run

# Run tasks in a specific folder
op3 run --match "tasks/reports/**"

# Run single task every 10 seconds
op3 run:single tasks/cleanup.ts --timing "*/10 * * * * *"

# Test a task without scheduling
op3 run:once tasks/send-email.ts

Writing Tasks

A task file exports two things:

typescript
import { EntryContext } from "@op3/cli";

// Cron pattern (6 fields: second minute hour day month weekday)
export const timing = "0 */5 * * * *"; // Every 5 minutes

// Task function
export const task = async (ctx: EntryContext) => {
  // Your code here
};

Task Context

Every task receives a context object with built-in utilities:

typescript
export const task = async (ctx: EntryContext) => {
  // Environment variables from .env
  const apiKey = ctx.env?.API_KEY;

  // Persistent key-value storage
  await ctx.$.setItem("lastRun", new Date().toISOString());
  const lastRun = await ctx.$.getItem("lastRun");

  // Structured logging (visible in dashboard)
  ctx.$.logInfo("Processing started");
  ctx.$.logWarning("Rate limit approaching");
  ctx.$.logError("Failed to connect");

  // Performance timing
  const stopTimer = ctx.$.startTimer("api-call");
  await fetch("https://api.example.com");
  await stopTimer(); // Records duration in dashboard
};

Lifecycle Hooks

Control task execution with optional exports:

typescript
// Skip execution conditionally
export const shouldSkip = async (ctx: EntryContext) => {
  const lastRun = await ctx.$.getItem("lastRun");
  return lastRun === new Date().toDateString(); // Skip if already ran today
};

// React to success
export const onSuccess = async (ctx: EntryContext) => {
  ctx.$.logInfo("Task completed successfully");
};

// Handle errors
export const onError = async (error: Error, ctx: EntryContext) => {
  ctx.$.logError(`Failed: ${error.message}`);
};

// Always runs (success or failure)
export const onComplete = async (ctx: EntryContext) => {
  await ctx.$.setItem("lastRun", Date.now().toString());
};

Configuration

op3.config.json options:

json
{
  "$schema": "https://apisurf.dev/static/op3/cli-config-schema.json",
  "dbPath": "file:op3.db",
  "port": 8787,
  "match": ["tasks/**/*.ts"],
  "envFile": ".env"
}
Option Default Description
dbPath file:op3.db SQLite database path
port 8787 Dashboard/API port
match ["tasks/**/*.ts"] Glob patterns for task files
envFile .env Environment variables file

Cron Patterns

op3 uses 6-field cron expressions (includes seconds):

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

Common patterns:

Pattern Description
*/5 * * * * * Every 5 seconds
0 * * * * * Every minute
0 */5 * * * * Every 5 minutes
0 0 * * * * Every hour
0 0 9 * * * Daily at 9:00 AM
0 0 9 * * 1-5 Weekdays at 9:00 AM