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

taskflare

v1.14.0

Published

A light and fast task runner for Node.js projects

Readme

taskflare

A small TypeScript-friendly task runner for Node.js projects.

Taskflare gives you a simple taskflare <task> command for project automation: build steps, release checks, local scripts, CI tasks, or anything else you would normally hide behind long package scripts. It is intentionally lightweight and familiar if you have used tools like Grunt.

Install

npm install --save-dev taskflare
pnpm add -D taskflare
yarn add -D taskflare

Quick Start

Create a taskflare.ts file in your project root:

import { registerTask } from 'taskflare'

registerTask('build', 'Build the project', function () {
    console.log('Building...')
})

registerTask('test', 'Run tests', async function () {
    console.log('Testing...')
})

registerTask('release', 'Run all release checks', ['test', 'build'])
registerTask('default', ['release'])

Run tasks:

taskflare build
taskflare release
taskflare

Running Shell Commands

Taskflare does not force a shell-command library on you. If you want a modern promise-based API, execa works well:

pnpm add -D execa
import { execa } from 'execa'
import { registerTask } from 'taskflare'

registerTask('typecheck', 'Check TypeScript types', async function () {
    const done = this.async()
    const result = await execa('tsc', ['--noEmit'], { stdio: 'inherit', reject: false })

    return done(result.exitCode === 0)
})

Task Files

By default, Taskflare looks for:

taskflare.js
taskflare.ts

Use --file when your task file has another name:

taskflare --file tasks.ts build
taskflare -f tasks.ts build
taskflare --config tasks.ts build

Task Types

Synchronous

registerTask('clean', 'Clean generated files', function () {
    // Throw an error to fail the task.
})

Promise-Based

registerTask('build', 'Build the project', async function () {
    await buildProject()
})

Callback-Based

Use this.async() when you want Grunt-style completion control:

registerTask('publish', 'Publish the package', async function () {
    const done = this.async()

    try {
        await publishPackage()
        return done(true)
    } catch {
        return done(false)
    }
})

Taskflare warns when a task keeps running for more than 30 seconds. This is especially useful when a callback task calls this.async() but never calls done(). The warning does not fail the task.

import { setTaskflareOptions } from 'taskflare'

setTaskflareOptions({
    hangWarningMs: 60_000,
})

Set hangWarningMs to 0 to disable the warning.

Use timeoutMs on a task when it should fail after a fixed time:

registerTask(
    'integration-test',
    {
        timeoutMs: 120_000,
    },
    async function () {
        await runIntegrationTests()
    },
)

Set timeoutMs to 0 or leave it unset when the task should not have a timeout.

Composite

Composite tasks run other tasks in sequence and stop on the first failure:

registerTask('ci', 'Run CI checks', ['typecheck', 'test', 'build'])

Taskflare detects circular composite tasks and fails them cleanly instead of recursing forever.

Use a nested array when independent tasks can run at the same time:

import { registerTask } from 'taskflare'

registerTask('ci', 'Run CI checks', ['typecheck', ['lint', 'test'], 'build'])

In this example, typecheck runs first, lint and test run together, and build runs after both parallel tasks finish.

Set continueOnFailure when you want composite tasks to attempt every task even after one fails. The composite task still returns false when any task failed.

import { setTaskflareOptions } from 'taskflare'

setTaskflareOptions({
    continueOnFailure: true,
})

Taskflare prints a duration summary after each run:

[TASK] Duration summary:
  Total  2.59s
  3 completed, 0 failed, 0 skipped, 0 missing, 0 circular
  OK lint   642ms
  OK test   1.42s  slowest
  OK build  530ms

Disable it with:

setTaskflareOptions({
    showSummary: false,
})

Lifecycle Hooks

Use lifecycle hooks when you want custom logging, metrics, timing, cleanup, or CI annotations around every task attempt.

import { setTaskflareOptions } from 'taskflare'

setTaskflareOptions({
    beforeTask({ task }) {
        console.log(`starting ${task}`)
    },
    afterTask({ durationMs, status, task }) {
        console.log(`${task} finished with ${status} in ${durationMs}ms`)
    },
})

beforeTask runs before normal tasks, composite tasks, skipped tasks, missing tasks, circular checks, and parallel groups. If beforeTask throws, the task is marked as failed and the task body does not run.

afterTask runs with task, kind, status, and durationMs after each task attempt. Errors thrown from afterTask are logged and do not change the task result.

CLI

taskflare [options] [task]

Options:

-f, --file <path>    Load tasks from a specific file
    --config <path>  Alias for --file
    --dry-run        Show the task plan without running it
    --json           Print JSON output with --list or --dry-run
-l, --list           List registered tasks
-v, --version        Print the current version
-h, --help           Show help

Examples:

taskflare --list
taskflare --list --json
taskflare --dry-run release
taskflare --dry-run --json release
taskflare --version
taskflare --file tasks.ts release

API

Most task files only need registerTask:

import { registerTask } from 'taskflare'

Taskflare ships both ESM and CommonJS builds:

import { registerTask } from 'taskflare'
const { registerTask } = require('taskflare')

registerTask(name, task)

registerTask('build', async function () {})

registerTask(name, description, task)

registerTask('build', 'Build the project', async function () {})

registerTask(name, options, task)

Use task options when you need a description, conditional execution, or a task timeout:

registerTask(
    'open-browser',
    {
        description: 'Open the local app in a browser',
        enabled: !process.env.CI,
        timeoutMs: 10_000,
    },
    async function () {
        await openBrowser()
    },
)

enabled can be a boolean or a function. When it resolves to false, the task is skipped and counted as successful.

timeoutMs fails the task if it does not finish in time. This works for promise tasks and callback tasks using this.async().

Programmatic API

These exports are useful when you want to embed Taskflare, write tests around tasks, or build tooling on top of it:

import {
    clearTasks,
    getTaskPlan,
    listTaskDetails,
    listTasks,
    runTask,
    setTaskflareOptions,
    type TaskflareTask,
    type TaskflareTaskDefinition,
    type TaskflareEnabled,
} from 'taskflare'

runTask(name)

Runs a task programmatically and resolves to true or false.

const success = await runTask('build')

listTasks()

Returns registered task names.

listTaskDetails()

Returns task names and optional descriptions. This is what powers taskflare --list.

getTaskPlan(name)

Returns the task execution plan without running the task. This is what powers taskflare --dry-run.

const plan = getTaskPlan('release')

setTaskflareOptions(options)

Configures runner behavior.

setTaskflareOptions({
    beforeTask({ task }) {
        console.log(`starting ${task}`)
    },
    afterTask({ status, task }) {
        console.log(`${task}: ${status}`)
    },
    continueOnFailure: true,
    hangWarningMs: 60_000,
    showSummary: true,
})

Releases

This repository is configured for semantic-release:

  • pushes to dev create GitHub prereleases such as v1.2.3-rc.1
  • pushes or merges to prod create stable GitHub releases and publish to npm

Requirements

Taskflare requires Node.js 18 or newer and has no runtime dependencies.

TypeScript configuration files (taskflare.ts) run natively on Node.js versions with type stripping (>= 22.6 with --experimental-strip-types, >= 23.6 by default). On older Node.js versions, install the optional tsx peer dependency:

npm install --save-dev tsx

JavaScript configuration files (taskflare.js) work everywhere without extra setup.

License

MIT