Backend Development 13 min read

Mastering Yargs Middleware: From Basics to Advanced Usage

Explore how Yargs middleware enhances command-line tools by allowing pre- and post-validation processing, global and command-specific hooks, and flexible implementation details, with practical code examples, API insights, and strategies for managing, freezing, and resetting middleware chains.

Code Mala Tang
Code Mala Tang
Code Mala Tang
Mastering Yargs Middleware: From Basics to Advanced Usage

Yargs Middleware Overview

Yargs is a popular library for parsing command‑line arguments, enabling developers to define CLI interfaces, handle parameters, organize commands, and automatically generate help text. This article explains Yargs’s middleware support.

Middleware API details are available at https://yargs.js.org/docs/#api-reference-middlewarecallbacks-applybeforevalidation.

In Yargs, middleware is a mechanism that inserts custom logic during argument parsing, allowing operations before or after validation, such as preprocessing, validation, transformation, or adding custom actions.

Its main uses are:

Pre‑processing arguments before validation (e.g., formatting input).

Post‑validation handling of parsed data.

Global middleware that applies to all commands or options.

Global Middleware

The API signature is:

<code>.middleware(callbacks, [applyBeforeValidation])</code>

callbacks : a function or an array of functions that receive a reference to argv , the parsed arguments object.

applyBeforeValidation (optional): a boolean, default false . When true , the middleware runs before validation but after parsing.

From this we see that multiple middleware can be defined and their execution order controlled.

Examples:

<code>const mwFunc1 = argv => console.log('I\'m a middleware function');
const mwFunc2 = argv => console.log('I\'m another middleware function');

yargs
  .command('myCommand', 'some command', {}, function (argv) {
    console.log('Running myCommand!');
  })
  .middleware([mwFunc1, mwFunc2])
  .parse();</code>

When myCommand is invoked, mwFunc1 runs first, then mwFunc2 , followed by the command handler, producing:

<code>I\'m a middleware function
I\'m another middleware function
Running myCommand!</code>
<code>require('yargs/yargs')(process.argv.slice(2))
  .middleware(function (argv) {
    if (process.env.HOME) argv.home = process.env.HOME;
  }, true)
  .command('configure-home', "do something with a user's home directory", {
    home: { demand: true, string: true }
  }, function (argv) {
    console.info(`we know the user's home directory is ${argv.home}`);
  })
  .parse();</code>

This middleware fills the home option from the environment variable.

Command‑Specific Middleware

Command middleware applies only to the current command and forces applyBeforeValidation to false . Its signature is:

<code>.command(cmd, desc, [builder], [handler])</code>

Command middleware runs later than global middleware, after the command is selected.

<code>require('yargs')
  .command('$0', 'accept username', () => {}, (argv) => {
    // The middleware will have been applied before the default command is called:
    console.info(argv);
  })
  .choices('user', ['Goofy', 'Miky'])
  .middleware(argv => {
    console.info('gots here');
    const user = argv.user;
    switch (user) {
      case 'Goofy':
        argv.user = { firstName: 'Mark', lastName: 'Pipe' };
        break;
    }
    return argv;
  })
  .parse('--user Miky');</code>

How Middleware Is Implemented

The implementation relies on middleware.ts , which defines a GlobalMiddleware class and related functions for adding, freezing, unfreezing, and resetting middleware.

Key parts of GlobalMiddleware :

globalMiddleware: Middleware[] = [] stores all registered middleware.

frozens: Array<Middleware[]> = [] holds snapshots for rollback.

The constructor receives a YargsInstance to interact with the parser.

Method addMiddleware(callback, applyBeforeValidation, global = true, mutates = false) registers one or more middleware, indicating whether it runs before validation, whether it is global, and whether it mutates argv .

Method addCoerceMiddleware(callback, option) registers a single coerce middleware for a specific option, replacing any previous one.

Methods freeze() and unfreeze() save and restore snapshots of the middleware list.

Method reset() removes all non‑global middleware.

Utility commandMiddlewareFactory(commandMiddleware?) creates command‑level middleware arrays with applyBeforeValidation set to false .

Utility applyMiddleware(argv, yargs, middlewares, beforeValidation) iterates over matching middleware, handling both synchronous and asynchronous results, and merges returned objects into argv .

Support for asynchronous middleware is provided by patterns using reduce or recursion, ensuring promises are awaited before proceeding.

Transferring Middleware Knowledge

Beyond Yargs, frameworks like Express and Koa use similar middleware concepts. The core idea is a chain of functions that receive input, process it, and pass the result to the next function, optionally terminating the chain.

Separate concerns by isolating functionality (e.g., authentication, error handling).

Improve extensibility by inserting new middleware without altering existing code.

Simplify complex logic by breaking it into discrete steps.

A generic middleware structure:

<code>function middleware(input, next) {
  const result = process(input);
  return next(result);
}</code>

Middleware can be registered in an ordered list, frozen, unfrozen, or reset to manage state.

Conclusion

Yargs middleware provides great flexibility for building sophisticated command‑line applications, allowing developers to customize argument parsing, validation, and processing. The same middleware mindset can be applied to broader business development to modularize complex workflows.

clijavascriptMiddlewareNode.jscommand lineyargs
Code Mala Tang
Written by

Code Mala Tang

Read source code together, write articles together, and enjoy spicy hot pot together.

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.