{"id":21393703,"url":"https://github.com/itsmichaelbtw/express-fs-routes","last_synced_at":"2026-05-12T19:05:26.348Z","repository":{"id":63161211,"uuid":"532701063","full_name":"itsmichaelbtw/express-fs-routes","owner":"itsmichaelbtw","description":"Automatically create Express routes with one line of code using the file system. No more hard coding routes into your project's main file.","archived":false,"fork":false,"pushed_at":"2023-06-18T11:37:30.000Z","size":1784,"stargazers_count":2,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2025-02-24T03:50:30.014Z","etag":null,"topics":["expressjs","nodejs","rest-api","routing","typescript"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","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/itsmichaelbtw.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","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}},"created_at":"2022-09-05T01:14:39.000Z","updated_at":"2022-11-30T06:39:38.000Z","dependencies_parsed_at":"2025-01-23T01:41:09.412Z","dependency_job_id":"dfee4550-ab88-401a-8df9-314080dcf9bd","html_url":"https://github.com/itsmichaelbtw/express-fs-routes","commit_stats":null,"previous_names":[],"tags_count":9,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/itsmichaelbtw%2Fexpress-fs-routes","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/itsmichaelbtw%2Fexpress-fs-routes/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/itsmichaelbtw%2Fexpress-fs-routes/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/itsmichaelbtw%2Fexpress-fs-routes/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/itsmichaelbtw","download_url":"https://codeload.github.com/itsmichaelbtw/express-fs-routes/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":243878491,"owners_count":20362433,"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":["expressjs","nodejs","rest-api","routing","typescript"],"created_at":"2024-11-22T14:13:01.988Z","updated_at":"2026-05-12T19:05:26.231Z","avatar_url":"https://github.com/itsmichaelbtw.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# express-fs-routes\n\nAn intuitive way of defining and registering your routes for your Express app. Avoid the clutter and cumbersome process of importing your routes and manually registering them. Easily create and manage Express routes with a simple directory structure. No more hard coding routes into your projects main file. Specify a directory to scan, and all routes will be automatically registered.\n\n**New to Express?** Check out the [Express documentation](https://expressjs.com/en/guide/routing.html) to get started.\n\n## Table of Contents\n\n-   [Features](#features)\n-   [Installation](#installation)\n-   [Quick Start](#quick-start)\n-   [Examples](#examples)\n    -   [Basic](#basic)\n    -   [Custom Directory](#custom-directory)\n    -   [Environment Specific Routes](#environment-specific-routes)\n    -   [Global Route Prefix](#global-route-prefix)\n    -   [Parameters](#parameters)\n    -   [Extended URL Paths](#extended-url-paths)\n    -   [Multiple HTTP Methods](#multiple-http-methods)\n-   [Engine](#route-engine)\n    -   [Engine Options](#engine-options)\n    -   [Routing](#routing)\n-   [Route Options](#route-options)\n-   [Caveats](#caveats)\n-   [FAQ](#faq)\n-   [TypeScript](#typescript)\n-   [Resources](#resources)\n\n## Features\n\n-   Supports CommonJS, ESM, and TypeScript projects\n-   Existing projects can be easily migrated\n-   Prefix routes with a global app mount\n-   Build routes from a directory structure\n-   Environment specific routes\n-   Granular control over route registration behavior\n\n## Installation\n\n```bash\n$ npm install express-fs-routes\n```\n\n```bash\n$ yarn add express-fs-routes\n```\n\n\u003e Ensure you have express installed in your project.\n\nIt is recommended to view the [examples](#examples) before continuing.\n\n## Quick Start\n\nExisting projects should have little to no effort when migrating to this package. This aims to eliminate as much overheard as possible when creating and managing routes. Middleware can be used as well, and will be registered in the order they are defined in the route file.\n\nIt is important to note that the relative path is the url path of a route. This is similiar to how [Next.js](https://nextjs.org/docs/routing/introduction) handles routing.\n\nThere is no limitation on the amount of times you decide to register routes. You can register routes from multiple directories, and even multiple times from the same directory. Using the same instance of the `RouteEngine` class, you can register routes from multiple directories. This is useful if you have a directory for your public routes, and another for your private routes. You can register both directories and have them both be accessible from the same Express app.\n\nExample directory structure:\n\n```bash\n├── routes\n│   ├── users\n│   │   ├── login.ts\n│   │   ├── register.ts\n│   │   ├── fetch.ts\n│   │   ├── create.ts\n│   │   └── delete.ts\n│   └── index.ts\n└── server.ts\n```\n\nThen turns into:\n\n```bash\nGET /users/login\nPOST /users/register\nGET /users/fetch\nPOST /users/create\nDELETE /users/delete\nGET /\n```\n\nExample: `server.ts`\n\nThe initial directory you choose to scan will NOT be included in the route path. For example, if you choose to scan the `routes` directory, the route path will be `/users` and not `/routes/users`. If you wish to provide a one-time prefix for all routes, see the [Engine Options](#engine-options) section.\n\n```typescript\nimport express from \"express\";\n\nimport { RouteEngine } from \"express-fs-routes\";\n\nconst app = express();\nconst routeEngine = new RouteEngine(app, \"module\"); // or \"commonjs\"\n\nrouteEngine.setOptions({\n  directory: \"routes\" // or path.join(__dirname, \"routes\")\n});\n\n// middleware still works as normal\n\napp.use(express.json());\napp.use(express.urlencoded({ extended: true }));\napp.disable(\"x-powered-by\");\n\n// here you would normally do\n// app.use(\"/users\", usersRouter);\n// app.use(\"/posts\", postsRouter);\n// app.use(\"/comments\", commentsRouter);\n// ...\n\n// but now you can do\nconst registry = await routeEngine.run();\n\n// provide a catch all route\napp.use((req, res) =\u003e {\n  res.status(404).send(\"Not Found\");\n});\n\napp.listen(3000, () =\u003e {\n  console.log(\"Server listening on port 3000\");\n});\n```\n\nExample: `routes/users/fetch.ts`\n\nWhether you are using CommonJS, ES6, or TypeScript, all are supported and will be registered as expected. It is important when you define the route, that it is exported as default. This is the expected behaviour designed by Express. See more information about Express routers [here](https://expressjs.com/en/guide/routing.html#express-router).\n\nAn extra feature that is built into this package is the option to export a custom named object that will be used to control the registration behaviour of the route. See the [Route Options](#route-options) section for more information.\n\nIt is important to remember that the folder/file structure that you defined will be the base url of the route that is defined within the file at hand. You may be confused to why each file has a path of `/` and that is because the file\"s relative path is used as the url. You are still free to define additional url paths within the route file. These are referred to as **extended url paths** and are explained in more detail [here](#extended-url-paths).\n\n```typescript\nimport express from \"express\";\n\nimport type { RouterOptions } from \"express-fs-routes\";\n\nconst router = express.Router();\n\nrouter.get(\"/\", async (req, res) =\u003e {\n  const users = await User.find();\n\n  res.json(users);\n});\n\nexport default router;\nexport const routeOptions: RouterOptions = {\n  // options here\n};\n```\n\n## Examples\n\n### Basic\n\n```typescript\nimport express from \"express\";\n\nimport { RouteEngine } from \"express-fs-routes\";\n\nconst app = express();\nconst routeEngine = new RouteEngine(app, \"module\");\n\napp.use(express.json());\napp.use(express.urlencoded({ extended: true }));\n\nawait routeEngine.run(app);\n\napp.listen(3000, () =\u003e {\n  console.log(\"Server listening on port 3000\");\n});\n```\n\nBy default, the directory that is scanned is `routes`. This is the same directory structure that is used in the [quick start](#quick-start) example.\n\nIf you are confused on the `module` reference as the 2nd argument to the constructor, have a look at the [Route Engine](#route-engine) section.\n\n### Custom Directory\n\n```typescript\nimport express from \"express\";\n\nimport { RouteEngine } from \"express-fs-routes\";\n\nconst app = express();\nconst routeEngine = new RouteEngine(app, \"module\");\n\nrouteEngine.setOptions({\n  directory: \"my_custom_path\" // or path.join(__dirname, \"my_custom_path\")\n});\n\napp.use(express.json());\napp.use(express.urlencoded({ extended: true }));\n\nawait routeEngine.run(app);\n\napp.listen(3000, () =\u003e {\n  console.log(\"Server listening on port 3000\");\n});\n```\n\nIf you are having trouble supplying a custom directory, ensure you are using the absolute path. You can use the `path` module to help with this. See the [Engine Options](#engine-options) section for more information or the [examples](examples).\n\nWhen calling `setOptions`, this can be called at any time before `run` is called. This means you can change the directory at any time.\n\n### Environment Specific Routes\n\n```typescript\n// routes/users/fetch.ts\n\nimport express from \"express\";\n\nimport type { RouterOptions } from \"express-fs-routes\";\n\nconst router = express.Router();\n\nrouter.get(\"/\", async (req, res) =\u003e {\n  const users = await User.find();\n\n  res.json(users);\n});\n\nexport default router;\n\nexport const routeOptions: RouterOptions = {\n  environments: [\"development\", \"staging\"]\n};\n```\n\nEnvironments are not standardised, so you can use whatever you want. The default environment is `development`. You can change this by setting the `NODE_ENV` environment variable. As long as the environment matches, the route will be registered. If you want to register a route for all environments, either omit this value or supply a wildcard `*`.\n\nIn this case, the above route will only be registered in the `development` and `staging` environments. Any other environment will not register the route.\n\nSee the [examples](examples) for more information.\n\n### Global Route Prefix\n\nAlso known as an application mount, you can specify a prefix that will be appended to all registered routes. If your server sits behind `/api`, you can specify this as the global route prefix.\n\nThis saves the hassle of having to create a directory just for the prefix.\n\n```typescript\nimport express from \"express\";\n\nimport { RouteEngine } from \"express-fs-routes\";\n\nconst app = express();\nconst routeEngine = new RouteEngine(app, \"module\");\n\nrouteEngine.setOptions({\n  appMount: \"/api\"\n});\n\napp.listen(3000, () =\u003e {\n  console.log(\"Server listening on port 3000\");\n});\n\n// GET /api/users\n// GET /api/posts\n// GET /api/comments\n```\n\n### Parameters\n\nDynamic parameters are supported and will be parsed to treat them as such. The **slug** pattern is used to denote a parameter.\n\n```typescript\n// routes/users/[user_id]\n\nimport express from \"express\";\n\nimport type { RouterOptions } from \"express-fs-routes\";\n\nconst router = express.Router({ mergeParams: true });\n\nrouter.delete(\"/\", (req, res) =\u003e {\n  const { user_id } = req.params;\n\n  await User.delete(user_id);\n\n  res.json({ message: `User ${user_id} deleted` });\n});\n\nexport default router;\n\n// DELETE /users/:user_id\n```\n\nEnsure you set `{ mergeParams: true }` when using parameters. This is required by express to ensure the parameters are parsed correctly. By default, a parameter will be parsed into `:param` format.\n\nAdditionally, you can provide a regex pattern that will be used to replace the slug. This is useful if you want to use a different pattern for your parameters.\n\n```typescript\nexport const routeOptions: RouterOptions = {\n  paramsRegex: {\n    user_id: /user_id_[a-zA-Z0-9]+/ // will match user_id_1234\n  }\n};\n\n// DELETE /users/:user_id(user_id_[a-zA-Z0-9]+)\n```\n\nParameters can be nested as deep as you need. Just ensure that if you wish to use custom patterns, you provide a\npattern for each level. This is not required by default as any missing patterns will be parsed into the default `:param` format.\n\nSee the [examples](examples) for more information.\n\n### Extended URL Paths\n\nYou may think that you are limited to utilizing the directory structure to define your routes, but you are not. You can define additional url paths within the route file. This will be appended at runtime to the base url path and will work as expected.\n\n```typescript\n// routes/users/create.ts\n\nimport express from \"express\";\n\nimport type { RouterOptions } from \"express-fs-routes\";\n\nconst router = express.Router();\n\nrouter.post(\"/admin\", async (req, res) =\u003e {\n  const user = await User.create(req.body);\n\n  res.json(user);\n});\n\nexport default router;\n\n// POST /users/create/admin\n```\n\n### Multiple HTTP Methods\n\nWhen defining a route, you can specify multiple HTTP methods on the same router. All routes are handled as expected and will be registered as expected.\n\nThere is one condition to this, read the [Caveats](#caveats) section for more information.\n\n```typescript\n// routes/users\n\nimport express from \"express\";\n\nconst router = express.Router();\n\nrouter.get(\"/\", async (req, res) =\u003e {\n  const users = await User.find();\n\n  res.json(users);\n});\n\nrouter.post(\"/\", async (req, res) =\u003e {\n  const user = await User.create(req.body);\n\n  res.json(user);\n});\n\nrouter.delete(\"/:user_id\", async (req, res) =\u003e {\n  const { user_id } = req.params;\n\n  await User.delete(user_id);\n\n  res.json({ message: `User ${user_id} deleted` });\n});\n\n// extended url paths also work\nrouter.put(\"/:user_id/avatar\", async (req, res) =\u003e {\n  const { user_id } = req.params;\n\n  await User.updateAvatar(user_id, req.body);\n\n  res.json({ message: `User ${user_id} avatar updated` });\n});\n\nexport default router;\n```\n\n## Route Engine\n\nThe `RouteEngine` class is the main class that is used to register routes. Start by instantiating the class with the express application and context type. The **context** is used to indicate how the internal engine should require the route files. This can be either `commonjs` or `module`. Each context type also performs its own validation on the route files.\n\nNormally, you will most likely only need one instance of the `RouteEngine` class. However, if you wish to have multiple instances, you can do so. This is useful if you wish to have different contexts for different directories. Such as when using TypeScript, one directory may be compiled to `commonjs` and another to `module`.\n\nWhen a class is instantiated, it is best to then call `setOptions` to set the options for the engine. This is required before calling `run`. All options are optional except for the `directory` option. When setting the options, it will override any previously set options.\n\n```typescript\nimport express from \"express\";\n\nimport { RouteEngine } from \"express-fs-routes\";\n\nconst app = express();\nconst routeEngine = new RouteEngine(app, \"module\"); // or \"commonjs\"\n\nrouteEngine.setOptions({\n  directory: \"routes\",\n  appMount: \"/api\"\n});\n\n// or\n\nrouteEngine.setOptions(\n  Object.assign({}, routeEngine.options, {\n    directory: \"routes\",\n    appMount: \"/api\"\n  })\n); // this will merge the options instead of overriding them\n\nconst registry = await routeEngine.run();\n```\n\nAfter calling `run`, the engine will return a `RouteRegistry` object. This object contains all the registered routes and their corresponding metadata. This is useful if you wish to perform any additional actions on the routes.\n\n### Engine Options\n\n\u003cdetails\u003e\n\u003csummary\u003eSee options interface\u003c/summary\u003e\n\n```typescript\nexport interface RegistrationOptions\u003cT extends MetaData = any\u003e {\n  /**\n   * The root directory that contains all routes you wish to register.\n   * You may pass a relative path, or an absolute path. If you pass a relative path,\n   * it will be resolved relative to `process.cwd()`.\n   *\n   * @default \"routes\"\n   */\n  directory: FilePath;\n\n  /**\n   * An optional app mount that is appended to the start of each route.\n   *\n   * For example, if you are building an application that will be hosted at\n   * `https://example.com/api`, you would set this to `/api` to indicate that\n   * all routes should be mounted at `/api`.\n   *\n   * This is designed to eliminate the need to specify a directory for app mounts.\n   *\n   * @default \"\"\n   */\n  appMount?: string | null;\n\n  /**\n   * Specify default route metadata that will be passed to all\n   * routes. Existing route metadata will be merged with this value.\n   *\n   * @default {}\n   */\n  routeMetadata?: T;\n\n  /**\n   * Define any routes that are specific to a certain environment. This\n   * is resolved relative to the `directory` option.\n   *\n   * ```\n   * {\n   *   environmentRoutes: {\n   *     development: [\"users\", \"posts\"],\n   *     production: [\"users\"],\n   *     test: [\"users\", \"posts\", \"comments\"],\n   *     staging: [\"users\", \"posts\"],\n   *     custom_env: [\"foo\", \"bar\"]\n   *   }\n   * }\n   * ```\n   *\n   * If you instead wish to use the root directory as the environment, you must\n   * instead pass an absolute path. E.g. `path.join(__dirname, \"routes\")`.\n   *\n   * Note: Only accepts directories.\n   *\n   * @default undefined\n   */\n  environmentRoutes?: EnvironmentRoutes;\n\n  /**\n   * Sometimes you may want to specify routes that act upon the root\n   * of a directory.\n   *\n   * For example, if you have a directory structure like this:\n   *\n   * ```\n   * routes/\n   *  users/\n   *    index.js\n   *    retrieve.js\n   * ```\n   *\n   * You can tell `registerRoutes` to treat `index.js` as the root of the\n   * `users` directory.\n   *\n   * Note: Only accepts filenames.\n   *\n   * @default [\"index.js\"]\n   */\n  indexNames?: string[];\n\n  /**\n   * Specify a directory to save a JSON file that contains a tree of all\n   * registered routes, and a registry of all route handlers. This is useful\n   * for debugging purposes.\n   *\n   * Set this to `false` to disable this feature.\n   *\n   * @default \".fs-routes\"\n   */\n  output?: string | false | null;\n\n  /**\n   * Specifies whether the route registration process should run in strict mode.\n   * When strict mode is enabled, additional checks and validations can be performed\n   * to ensure that the routes being registered meet certain criteria or follow specific\n   * guidelines.\n   *\n   * - The directory must exist.\n   * - The required route must return a function.\n   *\n   * When strict mode is enabled, any errors that occur will be thrown and the registration\n   * process will be aborted.\n   *\n   * @default false\n   */\n  strictMode?: boolean;\n\n  /**\n   * Whether errors should be thrown. If this is set to `false`, operations will\n   * continue as normal.\n   *\n   * @default false\n   *\n   * @deprecated Use `strictMode` instead.\n   */\n  silent?: boolean;\n\n  /**\n   * Choose if you wish to redact the file output paths for security reasons.\n   *\n   * @default false\n   */\n  redactOutputFilePaths?: boolean;\n  /**\n   * A function that is called before a route undergoes registration. This\n   * is called before environment based checks are performed, and before the route\n   * is conditionally checked for registration. Any changes made to the route\n   * object will be reflected in the registration process and the file output.\n   *\n   * **This is not middleware**. This will only be called once per route and won't\n   * be called for each request.\n   *\n   * @param route The route schema object.\n   * @returns The route schema object.\n   *\n   * @default (route) =\u003e route\n   */\n  beforeRegistration?(route: RouteSchema\u003cT\u003e): RouteSchema\u003cT\u003e;\n\n  /**\n   * Intercept the layer stack that is registered to the Express app and provided\n   * your own custom handler for a given path. You can either return a\n   * new handler, or the original handler.\n   *\n   * Note: The `layer` that is passed is a clone of the original layer, and will not\n   * affect the original layer stack.\n   *\n   * @param layer The layer that is registered to the Express app.\n   * @param handle The handle that is registered to the Express app.\n   * @param currentIdx The current index of the layer stack.\n   * @param stackSize The total size of the layer stack.\n   *\n   * @returns The middleware that will be registered to the Express app.\n   *\n   * @default null\n   */\n  interceptLayerStack?(\n    layer: RouteLayer,\n    handle: ExpressMiddleware,\n    currentIdx: number,\n    stackSize: number\n  ): ExpressMiddleware;\n\n  /**\n   * Manage the middleware that is responsible for calling the route handler. By\n   * providing this value, you are required to call the route handler yourself\n   * and assign the route metadata to the request object.\n   *\n   * Note: The `route` object is a clone of the original route object, and will not\n   * affect the original route object.\n   *\n   * @param route The route schema object.\n   * @param handler The route handler that is registered to the Express app.\n   * @returns An Express middleware function.\n   *\n   * @example\n   * ```typescript\n   * const routeEngine = new RouteEngine(app, \"module\");\n   *\n   * routeEngine.setOptions({\n   *  customMiddleware: (route, handler) =\u003e {\n   *   return (req, res, next) =\u003e {\n   *    req.routeMetadata = route.route_options.metadata ?? {};\n   *\n   *    return handler.call(app, req, res, next);\n   *   }\n   *  }\n   * })\n   * ```\n   *\n   * @default null\n   */\n  customMiddleware?(route: RouteSchema\u003cT\u003e, handler: RouteHandler): ExpressMiddleware;\n}\n```\n\u003c/details\u003e\n\n### Routing\n\nRouting works similiar to how [Next.js](https://nextjs.org/docs/routing/introduction) handles routing. Each file in the `directory` is treated as a route. The file name is used as the route path. For example, if you have a file called `users.ts` in the `directory`, it will be registered as `/users`.\n\nDynamic routes are also supported and this is denoted using square brackets. For example, if you have a file called `[id].ts` in the `directory`, it will be registered as `/:id` and the `id` parameter will be available in the `req.params` object.\n\nOnly TypeScript and JavaScript files are supported. Everything else will be ignored.\n\n## Router Options\n\nEach file can have a `routeOptions` export. This is an optional export that allows you to specify additional options for the route. As of version **2.0.0**, all options are purely for registration purposes. There are plans to include support for dynamic route options in the future.\n\n```typescript\n// routes/users/login.ts\n\nimport express from \"express\";\n\nimport type { RouterOptions } from \"express-fs-routes\";\n\nconst router = express.Router();\n\nrouter.post(\"/\", async (req, res) =\u003e {\n    const { email, password } = req.body;\n\n    const newUser = await User.create({ email, password });\n\n    res.json(newUser);\n});\n\nexport default router;\nexport const routeOptions: RouterOptions = {\n    environments: [\"production\"] // only available in these environments\n};\n```\n\nThe `RouterOptions` interface accepts a generic type which is used to specify the `metadata` property. See below for more information.\n\n\u003cdetails\u003e\n\u003csummary\u003eSee RouterOptions interface\u003c/summary\u003e\n\n```typescript\nexport interface RouterOptions\u003cT extends MetaData = MetaData\u003e {\n  /**\n   * Specify certain environments you want this route to be registered in. If\n   * you wish to register a route in all environments, you can omit this property\n   * or provide a wild card token `*`.\n   *\n   * This value takes precedence over `environmentRoutes` when both are present.\n   *\n   * @default null\n   */\n  environments?: string | string[];\n\n  /**\n   * Whether this route should be treated as an index route. This route\n   * will be instead mounted at the parent directory.\n   *\n   * This value takes precedence over `indexNames`.\n   *\n   * @default null\n   */\n  isIndex?: boolean;\n\n  /**\n   * Control whether the route should be registered. The route will still be scanned and under go\n   * all the same checks, but will bypass express registration.\n   *\n   * @default false\n   */\n  skip?: boolean;\n\n  /**\n   * Specify a custom parameter regex that will be used when\n   * registering the route to the express app.\n   *\n   * It supports nested parameters, and will be used to replace\n   * the default regex.\n   *\n   * ```ts\n   * export const routeOptions: RouterOptions = {\n   *  paramsRegex: {\n   *    post_id: /post_id_[a-z]+/,\n   *    user_id: /user_id_[a-z]+/\n   *  }\n   * }\n   * ```\n   *\n   * Accepts either a string or a RegExp. If a RegExp is provided,\n   * it will be converted to a string using `.source`.\n   *\n   * @default {}\n   */\n  paramsRegex?: ParamsRegex;\n\n  /**\n   * Metadata that is passed to the route and is available\n   * in the `req` object as `req.routeMetadata`.\n   *\n   * This is useful for passing data to middleware that is\n   * specific to a given route where you want to have request\n   * based context or conditional logic.\n   *\n   * @default {}\n   */\n  metadata?: T;\n}\n```\n\n\u003c/details\u003e\n\n#### `environments`\n\nControls which environments this route should be registered in. This is not standardised, so you can specify any environment you want. As long as `NODE_ENV` is set to one of the values, the route will be registered.\n\nThis value coincides with the `environmentRoutes` option. If this option is set, it will take precedence over `environmentRoutes`.\n\nRules this property follows:\n\n-   When omitted, registration is controlled depending on the `environmentRoutes` option.\n-   Providing any environment will **win** over `environmentRoutes`.\n-   Setting this to `*` will register the route in all environments, regardless of `environmentRoutes`.\n\nDefault: `undefined`\n\n#### `isIndex`\n\nWhether this route should be treated as an index route. This route will be instead mounted at the parent directory, or will \"navigate up\" a directory.\n\nThis value takes precedence over `indexNames`.\n\nDefault: `false`\n\n#### `skip`\n\nWhether to skip this route entirely.\n\nDefault: `false`\n\n#### `paramsRegex`\n\nSpecify a custom regex pattern to use when a known parameter is found. This is useful if you want to use a different regex pattern for a specific parameter.\n\n```typescript\n// routes/users/[id].ts\n\nexport const routeOptions: RouterOptions = {\n    paramsRegex: {\n        id: /user_[a-z]+/\n    }\n};\n```\n\n#### `metadata`\n\nMetadata can be defined per route file that will be passed onto the request object. This value will be available on the `req.routeMetadata` property.\n\nDefault: `{}`\n\n```typescript\n// routes/account/register.ts\n\ninterface RegisterMetadata {\n    title: string;\n    description: string;\n}\n\napp.get(\"/\", (req, res) =\u003e {\n    res.send(req.routeMetadata.title); // Register\n});\n\nexport const routeOptions: RouterOptions\u003cRegisterMetadata\u003e = {\n    metadata: {\n        title: \"Register\",\n        description: \"Register a new account\"\n    }\n};\n```\n\nSee the [examples](examples) for more information.\n\n## Caveats\n\nCurrently, when exporting the `routeOptions` object, if your file contains multiple http methods, all routes will be affected by the options. This is a limitation of the current implementation and will be addressed in a future release.\n\n```typescript\nimport express from \"express\";\n\nimport type { RouterOptions } from \"express-fs-routes\";\n\nconst router = express.Router();\n\nrouter.get(\"/foo\", (req, res) =\u003e {\n    res.json({ message: \"foo\" });\n});\n\nrouter.get(\"/bar\", (req, res) =\u003e {\n    res.json({ message: \"bar\" });\n});\n\nexport default router;\n\nexport const routeOptions: RouterOptions = {\n    environments: [\"production\"],\n    skip: true\n};\n\n// all routes, both GET /foo and GET /bar will be affected by the options\n```\n\n## FAQ\n\nComing soon...\n\n## TypeScript\n\nThis package is written in TypeScript and provides type definitions for the exported functions.\n\n## Resources\n\n-   [Express](https://expressjs.com/)\n-   [Change Log](CHANGELOG.md)\n-   [License](LICENSE)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fitsmichaelbtw%2Fexpress-fs-routes","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fitsmichaelbtw%2Fexpress-fs-routes","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fitsmichaelbtw%2Fexpress-fs-routes/lists"}