{"id":13525943,"url":"https://github.com/fastify/fastify-autoload","last_synced_at":"2025-05-14T10:09:27.767Z","repository":{"id":30384387,"uuid":"124746440","full_name":"fastify/fastify-autoload","owner":"fastify","description":"Require all plugins in a directory","archived":false,"fork":false,"pushed_at":"2025-05-01T02:29:05.000Z","size":450,"stargazers_count":356,"open_issues_count":15,"forks_count":73,"subscribers_count":16,"default_branch":"main","last_synced_at":"2025-05-11T16:03:16.522Z","etag":null,"topics":["fastify","fastify-plugin"],"latest_commit_sha":null,"homepage":"https://npmjs.com/package/@fastify/autoload","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/fastify.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null},"funding":{"github":"fastify","open_collective":"fastify"}},"created_at":"2018-03-11T10:42:13.000Z","updated_at":"2025-05-05T20:35:23.000Z","dependencies_parsed_at":"2023-02-16T03:01:28.231Z","dependency_job_id":"6096b20e-b8d8-407a-bb6c-5ca64d690236","html_url":"https://github.com/fastify/fastify-autoload","commit_stats":{"total_commits":324,"total_committers":68,"mean_commits":4.764705882352941,"dds":0.7716049382716049,"last_synced_commit":"df32f5055723217a85388ce531a55988af3f4a32"},"previous_names":[],"tags_count":71,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fastify%2Ffastify-autoload","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fastify%2Ffastify-autoload/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fastify%2Ffastify-autoload/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fastify%2Ffastify-autoload/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/fastify","download_url":"https://codeload.github.com/fastify/fastify-autoload/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":253645580,"owners_count":21941330,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["fastify","fastify-plugin"],"created_at":"2024-08-01T06:01:23.722Z","updated_at":"2025-05-14T10:09:27.725Z","avatar_url":"https://github.com/fastify.png","language":"JavaScript","readme":"# @fastify/autoload\n\n[![CI](https://github.com/fastify/fastify-autoload/actions/workflows/ci.yml/badge.svg?branch=main)](https://github.com/fastify/fastify-autoload/actions/workflows/ci.yml)\n[![NPM version](https://img.shields.io/npm/v/@fastify/autoload.svg?style=flat)](https://www.npmjs.com/package/@fastify/autoload)\n[![neostandard javascript style](https://img.shields.io/badge/code_style-neostandard-brightgreen?style=flat)](https://github.com/neostandard/neostandard)\n\nConvenience plugin for Fastify that loads all plugins found in a directory and automatically configures routes matching the folder structure.\n\n## Installation\n\n```\nnpm i @fastify/autoload\n```\n\n### Compatibility\n| Plugin version | Fastify version |\n| ---------------|-----------------|\n| `\u003e=6.x`        | `^5.x`          |\n| `^5.x`         | `^4.x`          |\n| `\u003e=2.x \u003c5.x`   | `^3.x`          |\n| `^1.x`         | `^2.x`          |\n| `^1.x`         | `^1.x`          |\n\n\nPlease note that if a Fastify version is out of support, then so are the corresponding versions of this plugin\nin the table above.\nSee [Fastify's LTS policy](https://github.com/fastify/fastify/blob/main/docs/Reference/LTS.md) for more details.\n\n## Example\n\nFastify server that automatically loads in all plugins from the `plugins` directory:\n\n```js\nconst fastify = require('fastify')\nconst autoload = require('@fastify/autoload')\n\nconst app = fastify()\n\napp.register(autoload, {\n  dir: path.join(__dirname, 'plugins')\n})\n\napp.listen({ port: 3000 })\n```\n\nor with ESM syntax:\n\n```js\nimport autoLoad from '@fastify/autoload'\nimport { fileURLToPath } from 'node:url'\nimport { dirname, join } from 'node:path'\nimport fastify from 'fastify'\n\nconst __filename = fileURLToPath(import.meta.url)\nconst __dirname = dirname(__filename)\n\nconst app = fastify()\n\napp.register(autoLoad, {\n  dir: join(__dirname, 'plugins')\n})\n\napp.listen({ port: 3000 })\n```\n\nFolder structure:\n\n```\n├── plugins\n│   ├── hooked-plugin\n│   │   ├── autohooks.mjs\n│   │   ├── routes.js\n│   │   └── children\n│   │       ├── commonjs.cjs\n│   │       ├── module.mjs\n│   │       └── typescript.ts\n│   ├── single-plugin\n│   │   ├── index.js\n│   │   └── utils.js\n│   ├── more-plugins\n│   │   ├── commonjs.cjs\n│   │   ├── module.mjs\n│   │   └── typescript.ts\n│   └── another-plugin.js\n├── package.json\n└── app.js\n```\n\n## Global Configuration\n\nAutoload can be customized using the following options:\n\n- `dir` (required) - Base directory containing plugins to be loaded\n\n  Each script file within a directory is treated as a plugin unless the directory contains an index file (e.g. `index.js`). In which case, only the index file (and the potential sub-directories) will be loaded.\n\n  The following script types are supported:\n\n  - `.js ` (CommonJS or ES modules depending on `type` field of parent `package.json`)\n  - `.cjs` (CommonJS)\n  - `.mjs` (ES modules)\n  - `.ts` (TypeScript)\n\n- `dirNameRoutePrefix` (optional) - Default: true. Determines whether routes will be automatically prefixed with the subdirectory name in an autoloaded directory. It can be a sync function that must return a string that will be used as prefix, or it must return `false` to skip the prefix for the directory.\n\n  ```js\n  fastify.register(autoLoad, {\n    dir: path.join(__dirname, 'routes'),\n    dirNameRoutePrefix: false // lack of prefix will mean no prefix, instead of directory name\n  })\n\n  fastify.register(autoLoad, {\n    dir: path.join(__dirname, 'routes'),\n    dirNameRoutePrefix: function rewrite (folderParent, folderName) {\n      if (folderName === 'YELLOW') {\n        return 'yellow-submarine'\n      }\n      if (folderName === 'FoOoO-BaAaR') {\n        return false\n      }\n      return folderName\n    }\n  })\n  ```\n\n- `matchFilter` (optional) - Filter matching any path that should be loaded. Can be a RegExp, a string, or a function returning a boolean.\n\n  ```js\n  fastify.register(autoLoad, {\n    dir: path.join(__dirname, 'plugins'),\n    matchFilter: (path) =\u003e path.split(\"/\").at(-2) === \"handlers\"\n  })\n  ```\n\n\n- `ignoreFilter` (optional) - Filter matching any path that should not be loaded. Can be a RegExp, a string ,or a function returning a boolean.\n\n  ```js\n  fastify.register(autoLoad, {\n    dir: path.join(__dirname, 'plugins'),\n    ignoreFilter: (path) =\u003e path.endsWith('.spec.js')\n  })\n  ```\n\n\n- `ignorePattern` (optional) - RegExp matching any file or folder that should not be loaded.\n\n  ```js\n  fastify.register(autoLoad, {\n    dir: path.join(__dirname, 'plugins'),\n    ignorePattern: /^.*(?:test|spec).js$/\n  })\n  ```\n\n\n- `scriptPattern` (optional) - Regex to override the script files accepted by default. You should only use this option\nwith a [customization hooks](https://nodejs.org/docs/latest/api/module.html#customization-hooks)\nprovider, such as `ts-node`. Otherwise, widening the acceptance extension here will result in an error.\n\n\n  ```js\n  fastify.register(autoLoad, {\n    dir: path.join(__dirname, 'plugins'),\n    scriptPattern: /(?\u003c!\\.d)\\.(ts|tsx)$/\n  })\n  ```\n\n- `indexPattern` (optional) - Regex to override the `index.js` naming convention\n\n  ```js\n  fastify.register(autoLoad, {\n    dir: path.join(__dirname, 'plugins'),\n    indexPattern: /^.*routes(?:\\.ts|\\.js|\\.cjs|\\.mjs)$/\n  })\n  ```\n\n- `maxDepth` (optional) - Limits the depth at which nested plugins are loaded\n\n  ```js\n  fastify.register(autoLoad, {\n    dir: path.join(__dirname, 'plugins'),\n    maxDepth: 2 // files in `opts.dir` nested more than 2 directories deep will be ignored.\n  })\n  ```\n\n- `forceESM` (optional) - If set to 'true' it always use `await import` to load plugins or hooks.\n\n  ```js\n  fastify.register(autoLoad, {\n    dir: path.join(__dirname, 'plugins'),\n    forceESM: true\n  })\n  ```\n- `encapsulate` (optional) - Defaults to 'true', if set to 'false' each plugin loaded is wrapped with [fastify-plugin](https://github.com/fastify/fastify-plugin). This allows you to share contexts between plugins and the parent context if needed. For example, if you need to share decorators. Read [this](https://github.com/fastify/fastify/blob/main/docs/Reference/Encapsulation.md#sharing-between-contexts) for more details.\n\n  ```js\n  fastify.register(autoLoad, {\n    dir: path.join(__dirname, 'plugins'),\n    encapsulate: false\n  })\n  ```\n\n- `options` (optional) - Global options object used for all registered plugins\n\n  Any option specified here will override `plugin.autoConfig` options specified in the plugin itself.\n\n  When setting both `options.prefix` and `plugin.autoPrefix` they will be concatenated.\n\n  ```js\n  // index.js\n  fastify.register(autoLoad, {\n    dir: path.join(__dirname, 'plugins'),\n    options: { prefix: '/defaultPrefix' }\n  })\n\n  // /plugins/something.js\n  module.exports = function (fastify, opts, next) {\n    // your plugin\n  }\n\n  module.exports.autoPrefix = '/something'\n\n  // /plugins/something.mjs\n  export default function (f, opts, next) {\n    f.get('/', (request, reply) =\u003e {\n      reply.send({ something: 'else' })\n    })\n\n    next()\n  }\n\n  export const autoPrefix = '/prefixed'\n\n  // routes can now be added to /defaultPrefix/something\n  ```\n\n- `autoHooks` (optional) - Apply hooks from `autohooks.js` file(s) to plugins found in folder\n\n  Automatic hooks from `autohooks` files will be encapsulated with plugins. If `false`, all `autohooks.js` files will be ignored.\n\n  ```js\n  fastify.register(autoLoad, {\n    dir: path.join(__dirname, 'plugins'),\n    autoHooks: true // apply hooks to routes in this level\n  })\n  ```\n\n  If `autoHooks` is set, all plugins in the folder will be [encapsulated](https://github.com/fastify/fastify/blob/main/docs/Reference/Encapsulation.md)\n  and decorated values _will not be exported_ outside the folder.\n\n- `autoHooksPattern` (optional) - Regex to override the `autohooks` naming convention\n\n  ```js\n  fastify.register(autoLoad, {\n    dir: path.join(__dirname, 'plugins'),\n    autoHooks: true,\n    autoHooksPattern: /^[_.]?auto_?hooks(?:\\.js|\\.cjs|\\.mjs)$/i\n  })\n  ```\n\n- `cascadeHooks` (optional) - If using `autoHooks`, cascade hooks to all children. Ignored if `autoHooks` is `false`.\n\n  Default behavior of `autoHooks` is to apply hooks only to the level on which the `autohooks.js` file is found. Setting `cascadeHooks: true` will continue applying the hooks to any children.\n\n  ```js\n  fastify.register(autoLoad, {\n    dir: path.join(__dirname, 'plugins'),\n    autoHooks: true, // apply hooks to routes in this level,\n    cascadeHooks: true // continue applying hooks to children, starting at this level\n  })\n  ```\n\n- `overwriteHooks` (optional) - If using `cascadeHooks`, cascade will be reset when a new `autohooks.js` file is encountered. Ignored if `autoHooks` is `false`.\n\n  Default behavior of `cascadeHooks` is to accumulate hooks as new `autohooks.js` files are discovered and cascade to children. Setting `overwriteHooks: true` will start a new hook cascade when new `autohooks.js` files are encountered.\n\n  ```js\n  fastify.register(autoLoad, {\n    dir: path.join(__dirname, 'plugins'),\n    autoHooks: true, // apply hooks to routes in this level,\n    cascadeHooks: true, // continue applying hooks to children, starting at this level,\n    overwriteHooks: true // re-start hook cascade when a new `autohooks.js` file is found\n  })\n  ```\n\n- `routeParams` (optional) - Folders prefixed with `_` will be turned into route parameters.\n\n  If you want to use mixed route parameters use a double underscore `__`.\n\n  ```js\n  /*\n  ├── routes\n  ├── __country-__language\n  │   │  └── actions.js\n  │   └── users\n  │       ├── _id\n  │       │   └── actions.js\n  │       ├── __country-__language\n  │       │   └── actions.js\n  │       └── index.js\n  └── app.js\n  */\n\n  fastify.register(autoLoad, {\n    dir: path.join(__dirname, 'routes'),\n    routeParams: true\n    // routes/users/_id/actions.js will be loaded with prefix /users/:id\n    // routes/__country-__language/actions.js will be loaded with prefix /:country-:language\n  })\n\n  // curl http://localhost:3000/users/index\n  // { userIndex: [ { id: 7, username: 'example' } ] }\n\n  // curl http://localhost:3000/users/7/details\n  // { user: { id: 7, username: 'example' } }\n\n  // curl http://localhost:3000/be-nl\n  // { country: 'be', language: 'nl' }\n  ```\n\n## Override TypeScript detection using an environment variable\nThis plugin uses [native type stripping](https://nodejs.org/docs/latest-v23.x/api/typescript.html#modules-typescript) with Node 23 and later.\n\nIt is possible to override the automatic detection of a TypeScript-capable runtime using the `FASTIFY_AUTOLOAD_TYPESCRIPT` environment variable. If set to a truthy value Autoload will load `.ts` files, expecting that node has a TypeScript-capable loader.\n\nThis is useful for cases where you want to use Autoload for loading TypeScript files but detecting the TypeScript loader fails because, for example, you are using a custom loader.\n\nIt can be used like this:\n\n```sh\nFASTIFY_AUTOLOAD_TYPESCRIPT=1 node --loader=my-custom-loader index.ts\n```\n\n## Plugin Configuration\n\nEach plugin can be individually configured using the following module properties:\n\n- `plugin.autoConfig` - Specifies the options to be used as the `opts` parameter.\n\n  ```js\n  module.exports = function (fastify, opts, next) {\n    console.log(opts.foo) // 'bar'\n    next()\n  }\n\n  module.exports.autoConfig = { foo: 'bar' }\n  ```\n\n  Or with ESM syntax:\n\n  ```js\n  import plugin from '../lib-plugin.js'\n\n  export default async function myPlugin (app, options) {\n    app.get('/', async (request, reply) =\u003e {\n      return { hello: options.name }\n    })\n  }\n  export const autoConfig = { name: 'y' }\n  ```\n\n  You can also use a callback function if you need to access the parent instance:\n  ```js\n  export const autoConfig = (fastify) =\u003e {\n    return { name: 'y ' + fastify.rootName }\n  }\n  ```\n\n  However, note that the `prefix` option should be set directly on `autoConfig` for autoloading to work as expected:\n  ```js\n  export const autoConfig = (fastify) =\u003e {\n    return { name: 'y ' + fastify.rootName }\n  }\n\n  autoConfig.prefix = '/hello'\n  ```\n\n- `plugin.autoPrefix` - Set routing prefix for plugin\n\n  ```js\n  module.exports = function (fastify, opts, next) {\n    fastify.get('/', (request, reply) =\u003e {\n      reply.send({ hello: 'world' })\n    })\n\n    next()\n  }\n\n  module.exports.autoPrefix = '/something'\n\n  // when loaded with autoload, this will be exposed as /something\n  ```\n\n  Or with ESM syntax:\n\n  ```js\n  export default async function (app, opts) {\n    app.get('/', (request, reply) =\u003e {\n      return { something: 'else' }\n    })\n  }\n\n  export const autoPrefix = '/prefixed'\n  ```\n\n\n- `plugin.prefixOverride` - Override all other prefix options\n\n  ```js\n  // index.js\n  fastify.register(autoLoad, {\n    dir: path.join(__dirname, 'plugins'),\n    options: { prefix: '/defaultPrefix' }\n  })\n\n  // /foo/something.js\n  module.exports = function (fastify, opts, next) {\n    // your plugin\n  }\n\n  module.exports.prefixOverride = '/overriddenPrefix'\n\n  // this will be exposed as /overriddenPrefix\n  ```\n\n  Or with ESM syntax:\n\n  ```js\n  export default async function (app, opts) {\n    // your plugin\n  }\n\n  export const prefixOverride = '/overriddenPrefix'\n  ```\n\n  If you have a plugin in the folder you do not want any prefix applied to, you can set `prefixOverride = ''`:\n\n  ```js\n  // index.js\n  fastify.register(autoLoad, {\n    dir: path.join(__dirname, 'plugins'),\n    options: { prefix: '/defaultPrefix' }\n  })\n\n  // /foo/something.js\n  module.exports = function (fastify, opts, next) {\n    // your plugin\n  }\n\n  // optional\n  module.exports.prefixOverride = ''\n\n  // routes can now be added without a prefix\n  ```\n\n- `plugin.autoload` - Toggle whether the plugin should be loaded\n\n  Example:\n\n  ```js\n  module.exports = function (fastify, opts, next) {\n    // your plugin\n  }\n\n  // optional\n  module.exports.autoload = false\n  ```\n\n- `opts.name` - Set name of plugin so that it can be referenced as a dependency\n\n- `opts.dependencies` - Set plugin dependencies to ensure correct load order\n\n  Example:\n\n  ```js\n  // plugins/plugin-a.js\n  const fp = require('fastify-plugin')\n\n  function plugin (fastify, opts, next) {\n    // plugin a\n  }\n\n  module.exports = fp(plugin, {\n    name: 'plugin-a',\n    dependencies: ['plugin-b']\n  })\n\n  // plugins/plugin-b.js\n  function plugin (fastify, opts, next) {\n    // plugin b\n  }\n\n  module.exports = fp(plugin, {\n    name: 'plugin-b'\n  })\n  ```\n\n  ## Autohooks:\n\n  The autohooks functionality provides several options for automatically adding hooks, decorators, etc. to your routes. CJS and ESM `autohook` formats are supported.\n\n  The default behavior of `autoHooks: true` is to encapsulate the `autohooks.js` plugin with the contents of the folder containing the file. The `cascadeHooks: true` option encapsulates the hooks with the current folder contents and all subsequent children, with any additional `autohooks.js` files being applied cumulatively. The `overwriteHooks: true` option will restart the cascade any time an `autohooks.js` file is encountered.\n\n  Plugins and hooks are encapsulated together by folder and registered on the `fastify` instance that loaded the `@fastify/autoload` plugin. For more information on how encapsulation works in Fastify, see: https://fastify.dev/docs/latest/Reference/Encapsulation/#encapsulation\n\n    ### Example:\n\n    ```\n    ├── plugins\n    │   ├── hooked-plugin\n    │   │   ├── autohooks.js // req.hookOne = 'yes' # CJS syntax\n    │   │   ├── routes.js\n    │   │   └── children\n    │   │       ├── old-routes.js\n    │   │       ├── new-routes.js\n    │   │       └── grandchildren\n    │   │           ├── autohooks.mjs // req.hookTwo = 'yes' # ESM syntax\n    │   │           └── routes.mjs\n    │   └── standard-plugin\n    │       └── routes.js\n    └── app.js\n    ```\n\n    ```js\n    // hooked-plugin/autohooks.js\n\n    module.exports = async function (app, opts) {\n      app.addHook('onRequest', async (req, reply) =\u003e {\n        req.hookOne = yes;\n      });\n    }\n\n    // hooked-plugin/children/grandchildren/autohooks.mjs\n\n    export default async function (app, opts) {\n      app.addHook('onRequest', async (req, reply) =\u003e {\n        req.hookTwo = yes\n      })\n    }\n    ```\n\n    ```bash\n    # app.js { autoHooks: true }\n\n    $ curl http://localhost:3000/standard-plugin/\n    {} # no hooks in this folder, so behavior is unchanged\n\n    $ curl http://localhost:3000/hooked-plugin/\n    { hookOne: 'yes' }\n\n    $ curl http://localhost:3000/hooked-plugin/children/old\n    {}\n\n    $ curl http://localhost:3000/hooked-plugin/children/new\n    {}\n\n    $ curl http://localhost:3000/hooked-plugin/children/grandchildren/\n    { hookTwo: 'yes' }\n    ```\n\n    ```bash\n    # app.js { autoHooks: true, cascadeHooks: true }\n\n    $ curl http://localhost:3000/hooked-plugin/\n    { hookOne: 'yes' }\n\n    $ curl http://localhost:3000/hooked-plugin/children/old\n    { hookOne: 'yes' }\n\n    $ curl http://localhost:3000/hooked-plugin/children/new\n    { hookOne: 'yes' }\n\n    $ curl http://localhost:3000/hooked-plugin/children/grandchildren/\n    { hookOne: 'yes', hookTwo: 'yes' } # hooks are accumulated and applied in ascending order\n    ```\n\n    ```bash\n    # app.js { autoHooks: true, cascadeHooks: true, overwriteHooks: true }\n\n    $ curl http://localhost:3000/hooked-plugin/\n    { hookOne: 'yes' }\n\n    $ curl http://localhost:3000/hooked-plugin/children/old\n    { hookOne: 'yes' }\n\n    $ curl http://localhost:3000/hooked-plugin/children/new\n    { hookOne: 'yes' }\n\n    $ curl http://localhost:3000/hooked-plugin/children/grandchildren/\n    { hookTwo: 'yes' } # new autohooks.js takes over\n    ```\n\n## License\n\nLicensed under [MIT](./LICENSE).\n","funding_links":["https://github.com/sponsors/fastify","https://opencollective.com/fastify"],"categories":["JavaScript"],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffastify%2Ffastify-autoload","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ffastify%2Ffastify-autoload","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffastify%2Ffastify-autoload/lists"}