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

dashq

v0.1.0

Published

Database-first functional job queue for Node.js with a built-in dashboard

Readme

DashQ

Zero-setup job queue for Node.js with a built-in dashboard.

npm version License: MIT Node.js

DashQ is a database-first functional job queue that works out of the box — no Redis, no external services. Define jobs as functions, enqueue them with full type safety, and monitor everything through a built-in web dashboard.

Features

  • Zero setup — Works in-memory with SQLite by default. No infrastructure required.
  • Built-in dashboard — Real-time web UI to inspect jobs, view logs, and retry failures.
  • Type-safedefineJob() infers argument types; enqueue() enforces them at compile time.
  • Database-first — Jobs are stored in your database (SQLite or PostgreSQL), not in memory.
  • Job-scoped loggingconsole.log inside a job is automatically captured and visible in the dashboard.
  • Automatic retries — Configurable retry strategies with exponential, linear, or custom backoff.
  • Scheduled jobs — Enqueue jobs to run at a specific time or after a delay.
  • Graceful shutdown — Waits for in-flight jobs before stopping.
  • Crash recovery — Lease-based locking detects stalled workers and re-queues their jobs.
  • Automatic cleanup — Configurable retention policies keep your database lean.

Quick Start

npm install dashq
import { defineJob, start } from "dashq";

const emailJob = defineJob("email.send", async (to: string, subject: string) => {
  console.log(`Sending "${subject}" to ${to}`);
  // ...your logic here
});

const handle = await start({
  database: "file:jobs.db",
  port: 3000,
});

await emailJob.enqueue("[email protected]", "Welcome!");

// Dashboard → http://localhost:3000/dashq/

That's it. Database tables are created automatically, the worker starts polling, and the dashboard is live.

Defining Jobs

Use defineJob() to register a job handler. Arguments are type-checked at enqueue time.

import { defineJob } from "dashq";

const resizeImage = defineJob(
  "image.resize",
  async (url: string, width: number) => {
    console.log(`Resizing ${url} to ${width}px`);
    // ...
  },
  { maxAttempts: 5, backoff: "exponential" },
);

Scheduling

// Run immediately
await resizeImage.enqueue("https://example.com/img.png", 800);

// Run at a specific time
await resizeImage.enqueueAt(new Date("2025-12-25"), "https://example.com/img.png", 800);

// Run after a delay
await resizeImage.enqueueIn("5m", "https://example.com/img.png", 800);
await resizeImage.enqueueIn("2h", "https://example.com/img.png", 800);

Supported delay formats: "30s", "5m", "2h", "7d", or milliseconds as a number.

Dashboard

DashQ ships with a built-in web dashboard — no separate service to deploy.

  • Overview — Job counts by status at a glance.
  • Job list — Filter and sort by status, type, or date. Retry or delete from the UI.
  • Job detail — View arguments, error stack traces, and a live-scrolling log viewer with output captured from console.log/warn/error.

Configuration

const handle = await start({
  // Required
  database: "file:jobs.db",       // SQLite file, ":memory:", or "postgres://..."

  // Optional (defaults shown)
  port: 3000,
  host: "localhost",
  dashboard: true,                // or { basePath: "/dashq" }
  worker: true,                   // or WorkerOptions (see below)
  retention: true,                // or RetentionOptions (see below)
});

Worker Options

| Option | Default | Description | |--------|---------|-------------| | pollingInterval | 1000 | Base poll interval (ms) | | maxPollingInterval | 30000 | Max interval during backoff (ms) | | backoffMultiplier | 1.5 | Multiplier when queue is empty | | leaseTimeout | 300000 | Job lock duration (ms) | | staleCheckInterval | 30000 | Stale job recovery interval (ms) | | shutdownTimeout | 30000 | Max wait on graceful shutdown (ms) |

Retention Options

| Option | Default | Description | |--------|---------|-------------| | succeededJobRetention | "7d" | How long to keep succeeded jobs | | failedJobRetention | "14d" | How long to keep failed jobs | | logRetention | "14d" | How long to keep job logs | | cleanupInterval | "1h" | How often cleanup runs | | cleanupBatchSize | 1000 | Rows deleted per batch |

Database Support

SQLite (default) — Zero setup. Great for development, single-server deployments, or getting started.

await start({ database: ":memory:" });          // In-memory
await start({ database: "file:jobs.db" });       // File-based

PostgreSQL — For production multi-worker deployments. Install pg as a peer dependency.

npm install pg
await start({ database: "postgres://user:pass@localhost:5432/mydb" });

Both adapters share the same interface — switch between them by changing the connection string.

Retry & Backoff

Jobs retry automatically on failure, up to maxAttempts (default: 3).

const job = defineJob("flaky-task", handler, {
  maxAttempts: 5,
  backoff: "exponential",   // 2s, 4s, 8s, 16s, ...
  // backoff: "linear",     // 1s, 2s, 3s, 4s, ...
  // backoff: "fixed",      // 1s, 1s, 1s, 1s, ...
  // backoff: (attempt) => attempt * 5000,  // custom
});

Job-Scoped Logging

Any console.log, console.warn, or console.error called inside a job handler is automatically captured, stored in the database, and displayed in the dashboard — scoped to that job and attempt. No special logging API needed.

const job = defineJob("example", async () => {
  console.log("Starting...");        // captured as info
  console.warn("Hmm...");           // captured as warn
  console.error("Something broke"); // captured as error
});

API Reference

Core

| Export | Description | |--------|-------------| | defineJob(id, handler, options?) | Register a job handler. Returns a JobDefinition with enqueue, enqueueAt, enqueueIn. | | start(options) | Start the database, worker, and dashboard. Returns a DashQHandle. |

Handle

| Method / Property | Description | |-------------------|-------------| | handle.stop() | Graceful shutdown of worker, dashboard, and database. | | handle.cleanup() | Run retention cleanup on demand. | | handle.port | The port the dashboard is listening on. | | handle.adapter | Direct access to the database adapter. |

Advanced

| Export | Description | |--------|-------------| | createAdapter(config) | Create a database adapter directly. | | createWorker(adapter, options?) | Create a standalone worker. | | createDashboardPlugin(fastify, options) | Mount the dashboard on an existing Fastify instance. | | waitForJob(adapter, jobId, options?) | Poll until a job succeeds or fails. | | parseDuration(delay) | Parse "5m" / "2h" / "7d" to milliseconds. | | generateId() | Generate a UUIDv7. |

License

MIT