Skip to main content

Features

Nadle comes packed with powerful features to make your build automation and task management more efficient.

Type Safety

TypeScript First

  • Built from the ground up with TypeScript
  • Complete type inference for tasks and configurations
  • Compile-time error detection
  • IDE support with IntelliSense (VS Code, IntelliJ)

Type-Safe Task Options

import { tasks, defineTask } from "nadle";

interface BuildOptions {
target: "web" | "mobile";
optimize: boolean;
}

const BuildTask = defineTask<BuildOptions>({
run: async ({ options }) => {
const { target, optimize } = options;
// Type-safe access to options
}
});

tasks.register("build", BuildTask, {
target: "web",
optimize: false
});

Parallel Execution

  • Automatic parallel task execution via worker threads
  • DAG-based dependency resolution
  • Configurable concurrency limits
  • Progress tracking for parallel tasks
tasks
.register("build:all", async () => {
// These tasks will run in parallel if possible
})
.config({
dependsOn: ["build:web", "build:mobile", "build:desktop"]
});

Dependency Management

  • Clear dependency declaration
  • Circular dependency detection
  • Topological sort scheduling
tasks
.register("deploy", async () => {
// Deploy implementation
})
.config({
dependsOn: ["build", "test"]
});

Progress Tracking

Real-Time Progress

  • Task execution status with interactive footer
  • Scheduled, running, and completed task indicators
  • Time tracking
  • Detailed error reporting

Logging System

  • Multiple log levels
  • Structured logging
  • Color-coded output
tasks.register("build", async ({ context }) => {
context.logger.info("Starting build...");
context.logger.debug("Debug details...");
// ... build steps
context.logger.warn("Something to watch out for");
});

Available logger methods: log, info, warn, error, debug, throw.

Task Organization

Grouping and Naming

  • Logical task groups
  • Consistent naming conventions
  • Task discovery via nadle --list
tasks
.register("build:web", async () => {
// Implementation
})
.config({
group: "Build",
description: "Build web application"
});

Error Handling

Robust Error Management

  • Detailed error messages
  • Stack trace preservation
tasks.register("deploy", async ({ context }) => {
try {
// Deployment steps
} catch (error) {
context.logger.error("Deployment failed", { error });
// Cleanup or rollback steps
}
});

Caching

Input Fingerprinting

Nadle caches task results based on declared inputs and outputs. When inputs haven't changed since the last run, the task is skipped and outputs are restored from cache.

  • Declare file and directory inputs/outputs
  • Cache stored in node_modules/.cache/nadle/ directory
  • Dependency-aware: downstream tasks re-execute when upstream outputs change
  • Task options included in cache key for correct invalidation
  • Automatic eviction of old cache entries (configurable maxCacheEntries)
  • Corruption-resilient: corrupted cache gracefully falls back to re-execution
  • Skip with --no-cache flag
import { tasks, ExecTask, Inputs, Outputs } from "nadle";

tasks
.register("compile", ExecTask, {
command: "tsc",
args: ["--build"]
})
.config({
inputs: [Inputs.files("src/**/*.ts", "tsconfig.json")],
outputs: [Outputs.dirs("lib")],
description: "Compile TypeScript sources"
});

Cache Declarations

  • Inputs.files(...patterns) — declare file input patterns
  • Inputs.dirs(...patterns) — declare directory input patterns
  • Outputs.files(...patterns) — declare file output patterns
  • Outputs.dirs(...patterns) — declare directory output patterns

Environment Variables

Tasks can set environment variables via the env config field:

tasks
.register("build:prod", async () => {
// Build with production env
})
.config({
env: {
NODE_ENV: "production",
MINIFY: true
}
});

Built-in Tasks

Nadle ships with reusable task types for common operations.

ExecTask

Run arbitrary shell commands:

import { tasks, ExecTask } from "nadle";

tasks.register("lint", ExecTask, {
command: "eslint",
args: [".", "--cache"]
});

NodeTask

Run Node.js scripts:

import { tasks, NodeTask } from "nadle";

tasks.register("seed", NodeTask, {
script: "scripts/seed-db.mjs"
});

NpmTask

Run npm commands:

import { tasks, NpmTask } from "nadle";

tasks.register("install", NpmTask, {
args: ["install", "--frozen-lockfile"]
});

NpxTask

Run locally-installed binaries via npx:

import { tasks, NpxTask } from "nadle";

tasks.register("lint", NpxTask, {
command: "eslint",
args: [".", "--cache"]
});

PnpmTask

Run pnpm commands:

import { tasks, PnpmTask } from "nadle";

tasks.register("install", PnpmTask, {
args: ["install", "--frozen-lockfile"]
});

PnpxTask

Run locally-installed binaries via pnpm exec:

import { tasks, PnpxTask } from "nadle";

tasks.register("build", PnpxTask, {
command: "tsup",
args: []
});

CopyTask

Copy files with glob patterns:

import { tasks, CopyTask } from "nadle";

tasks.register("copy:assets", CopyTask, {
from: "src/assets",
to: "dist/assets",
include: ["**/*.png", "**/*.svg"]
});

DeleteTask

Delete files and directories:

import { tasks, DeleteTask } from "nadle";

tasks.register("clean", DeleteTask, {
paths: ["**/lib/**", "**/build/**"]
});

Next Steps

  1. Dive into Configuration Reference
  2. Explore the API Documentation