{"id":29045574,"url":"https://github.com/hyperse-io/config-loader","last_synced_at":"2026-01-16T10:19:44.352Z","repository":{"id":297413614,"uuid":"996694414","full_name":"hyperse-io/config-loader","owner":"hyperse-io","description":"A config loader that searches for and loads configuration files for your program, with support for `type:module`, `esm`, and `cjs` module formats","archived":false,"fork":false,"pushed_at":"2026-01-14T09:01:48.000Z","size":2979,"stargazers_count":3,"open_issues_count":0,"forks_count":1,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-01-14T12:21:59.036Z","etag":null,"topics":["config","config-loader","cosmiconfig","esm","esm-config-loader","hyperse","loader","ts-config-loader"],"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/hyperse-io.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":".github/CODE_OF_CONDUCT.md","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,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null},"funding":{"github":["hyperse-net"]}},"created_at":"2025-06-05T10:18:47.000Z","updated_at":"2026-01-14T09:01:18.000Z","dependencies_parsed_at":"2025-06-05T11:00:00.079Z","dependency_job_id":"e6e3db3c-41f0-4ab6-bdb0-35144777c4c6","html_url":"https://github.com/hyperse-io/config-loader","commit_stats":null,"previous_names":["hyperse-io/config-loader"],"tags_count":8,"template":false,"template_full_name":null,"purl":"pkg:github/hyperse-io/config-loader","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hyperse-io%2Fconfig-loader","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hyperse-io%2Fconfig-loader/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hyperse-io%2Fconfig-loader/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hyperse-io%2Fconfig-loader/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/hyperse-io","download_url":"https://codeload.github.com/hyperse-io/config-loader/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hyperse-io%2Fconfig-loader/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28478049,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-16T06:30:42.265Z","status":"ssl_error","status_checked_at":"2026-01-16T06:30:16.248Z","response_time":107,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"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":["config","config-loader","cosmiconfig","esm","esm-config-loader","hyperse","loader","ts-config-loader"],"created_at":"2025-06-26T16:37:54.241Z","updated_at":"2026-01-16T10:19:39.340Z","avatar_url":"https://github.com/hyperse-io.png","language":"TypeScript","funding_links":["https://github.com/sponsors/hyperse-net"],"categories":[],"sub_categories":[],"readme":"# @hyperse/config-loader\n\nA config loader that searches for and loads configuration files for your program, with support for `type:module`, `esm`, and `cjs` module formats\n\n\u003cp align=\"left\"\u003e\n  \u003ca aria-label=\"Build\" href=\"https://github.com/hyperse-io/config-loader/actions?query=workflow%3ACI\"\u003e\n    \u003cimg alt=\"build\" src=\"https://img.shields.io/github/actions/workflow/status/hyperse-io/config-loader/ci-integrity.yml?branch=main\u0026label=ci\u0026logo=github\u0026style=flat-quare\u0026labelColor=000000\" /\u003e\n  \u003c/a\u003e\n  \u003ca aria-label=\"stable version\" href=\"https://www.npmjs.com/package/@hyperse/config-loader\"\u003e\n    \u003cimg alt=\"stable version\" src=\"https://img.shields.io/npm/v/%40hyperse%2Fconfig-loader?branch=main\u0026label=version\u0026logo=npm\u0026style=flat-quare\u0026labelColor=000000\" /\u003e\n  \u003c/a\u003e\n  \u003ca aria-label=\"Top language\" href=\"https://github.com/hyperse-io/config-loader/search?l=typescript\"\u003e\n    \u003cimg alt=\"GitHub top language\" src=\"https://img.shields.io/github/languages/top/hyperse-io/config-loader?style=flat-square\u0026labelColor=000\u0026color=blue\"\u003e\n  \u003c/a\u003e\n  \u003ca aria-label=\"Licence\" href=\"https://github.com/hyperse-io/config-loader/blob/main/LICENSE\"\u003e\n    \u003cimg alt=\"Licence\" src=\"https://img.shields.io/github/license/hyperse-io/config-loader?style=flat-quare\u0026labelColor=000000\" /\u003e\n  \u003c/a\u003e\n\u003c/p\u003e\n\nThe config loader is a powerful utility that searches for and loads configuration files for your JavaScript/TypeScript applications. It automatically handles multiple file formats and module systems while providing type safety.\n\nBuilt on top of cosmiconfig, it implements smart defaults aligned with JavaScript ecosystem conventions, while remaining highly configurable. You can customize search paths, file formats, and loading behavior to match your specific needs.\n\n## Features\n\n- 🔍 Automatic config file resolution with support for multiple formats (JSON, YAML, JS, TS)\n- 🎯 Flexible configuration search across multiple file locations\n- 🚀 ESM and CommonJS module support\n- 🔧 TypeScript configuration with full type inference\n- ⚡️ Built on top of cosmiconfig for reliable config loading\n- 🧪 Well-tested and production-ready\n- 🔄 Automatic resolution of TypeScript path aliases from tsconfig.json\n- 🔗 Smart handling of external modules and dependencies\n- 📦 Automatically marks package.json dependencies and devDependencies as external\n- 🏗️ Built-in support for monorepo setups and workspace packages\n\n## Installation\n\n```bash\nnpm install --save @hyperse/config-loader\n```\n\n## API Reference\n\n### `searchConfig\u003cT\u003e(moduleName: string, searchFrom?: string, options?: LoaderOptions)`\n\nSearches up the directory tree for configuration files, checking multiple locations in each directory until it finds a valid configuration or reaches the home directory.\n\n**Parameters:**\n\n- `moduleName` (string): Your module name. Used to create default search places and package properties\n- `searchFrom` (string, optional): Directory to start searching from. Defaults to `process.cwd()`\n- `options` (LoaderOptions, optional): Configuration options for the loader\n\n**Returns:** Promise\u003cConfigLoadResult\u003cT\u003e | null\u003e\n\n**Example:**\n\n```typescript\nimport { searchConfig } from '@hyperse/config-loader';\n\n// Search for a config file named 'myapp'\nconst result = await searchConfig\u003c{\n  port: number;\n  database: {\n    url: string;\n  };\n}\u003e('myapp');\n\nif (result) {\n  console.log(result.config.port); // Access the loaded config\n}\n```\n\n### `loadConfig\u003cT\u003e(configFile: string, options?: LoaderOptions)`\n\nLoads a configuration file from a specific path.\n\n**Parameters:**\n\n- `configFile` (string): Path to the configuration file\n- `options` (LoaderOptions, optional): Configuration options for the loader\n\n**Returns:** Promise\u003cConfigLoadResult\u003cT\u003e | null\u003e\n\n**Example:**\n\n```typescript\nimport { loadConfig } from '@hyperse/config-loader';\n\n// Load a specific config file\nconst result = await loadConfig\u003c{\n  port: number;\n  database: {\n    url: string;\n  };\n}\u003e('./config/myapp.config.ts');\n\nif (result) {\n  console.log(result.config.port);\n}\n```\n\n### `mergeOptions\u003cT\u003e(target: T, source: DeepPartial\u003cT\u003e, mergeUndefined?: boolean)`\n\nPerforms a deep merge of two configuration objects. Unlike `Object.assign()`, the target object is not mutated.\n\n**Parameters:**\n\n- `target` (T): The target object to merge into\n- `source` (DeepPartial\u003cT\u003e): The source object to merge from\n- `mergeUndefined` (boolean, optional): Whether to merge undefined values. Defaults to false\n\n**Returns:** T (new merged object)\n\n**Example:**\n\n```typescript\nimport { mergeOptions } from '@hyperse/config-loader';\n\nconst defaultConfig = {\n  server: {\n    port: 3000,\n    host: 'localhost',\n  },\n  database: {\n    url: 'postgres://localhost:5432/mydb',\n    pool: {\n      min: 0,\n      max: 10,\n    },\n  },\n};\n\nconst userConfig = {\n  server: {\n    port: 4000,\n  },\n  database: {\n    pool: {\n      max: 20,\n    },\n  },\n};\n\nconst mergedConfig = mergeOptions(defaultConfig, userConfig);\n// Result:\n// {\n//   server: {\n//     port: 4000,\n//     host: 'localhost'\n//   },\n//   database: {\n//     url: 'postgres://localhost:5432/mydb',\n//     pool: {\n//       min: 0,\n//       max: 20\n//     }\n//   }\n// }\n```\n\n### `defineConfig\u003cT, ConfigEnv extends ConfigEnvBase = ConfigEnvBase\u003e`\n\nA type helper for defining configuration objects with proper typing and environment support.\n\n**Example:**\n\n```typescript\nimport { defineConfig } from '@hyperse/config-loader';\n\ninterface MyConfig {\n  port: number;\n  database: {\n    url: string;\n  };\n}\n\ninterface MyConfigEnv {\n  mode: 'development' | 'production';\n}\n\nexport default defineConfig\u003cMyConfig, MyConfigEnv\u003e((env) =\u003e {\n  return {\n    port: env.mode === 'production' ? 80 : 3000,\n    database: {\n      url:\n        env.mode === 'production'\n          ? 'postgres://prod:5432/mydb'\n          : 'postgres://localhost:5432/mydb',\n    },\n  };\n});\n```\n\n### LoaderOptions\n\nConfiguration options for the loader:\n\n```typescript\ninterface LoaderOptions {\n  // Project root directory\n  projectCwd?: string;\n  // Path to tsconfig.json\n  tsconfig?: string;\n  // Additional plugins\n  plugins?: Plugin[];\n  // External dependencies to exclude\n  externals?: Array\u003cRegExp | string\u003e;\n  // The function to exclude aggregated externals, if the function returns true, the module will be excluded.\n  externalExclude?: (moduleId: RegExp | string) =\u003e boolean;\n  // The function to create your custom loaders.\n  createLoaders?: (\n    options?: LoaderOptions,\n    searchFrom?: string\n  ) =\u003e ConfigLoaders;\n}\n```\n\n#### Custom Loaders Options\n\n`externalExclude` - A function to exclude specific modules from being marked as external. Takes a module ID (string or RegExp) and returns true if the module should be excluded from externalization. This is useful for keeping certain dependencies bundled even if they match the external patterns.\n\n```typescript\nimport { searchConfig } from '@hyperse/config-loader';\n\n// Example 1: Basic usage with string patterns\nconst result1 = await searchConfig('myapp', undefined, {\n  // Default external pattern\n  externals: ['@hyperse/ts-node'],\n  externalExclude: (moduleId) =\u003e {\n    // Don't exclude modules that match these patterns\n    if (typeof moduleId === 'string') {\n      return !(\n        moduleId.includes('@myorg/') || moduleId.includes('my-local-package')\n      );\n    }\n    return true;\n  },\n});\n\n// Example 2: Advanced usage with RegExp patterns\nconst result2 = await searchConfig('myapp', undefined, {\n  // Multiple external patterns\n  externals: ['@hyperse/ts-node', /^@vendor\\//],\n  externalExclude: (moduleId) =\u003e {\n    if (typeof moduleId === 'string') {\n      // Exclude specific packages from being marked as external\n      return (\n        moduleId.includes('@myorg/shared-utils') ||\n        moduleId.includes('internal-tools')\n      );\n    }\n    // For RegExp patterns, check specific module names\n    return (\n      moduleId.test('@myorg/shared-utils') || moduleId.test('internal-tools')\n    );\n  },\n});\n```\n\n`createLoaders` - You can create custom loaders to handle specific file formats or add custom loading logic. Here's an example of how to create a custom loader for `.toml` files:\n\n```typescript\nimport { readFile } from 'fs/promises';\nimport {\n  type ConfigLoaders,\n  type LoaderOptions,\n  searchConfig,\n} from '@hyperse/config-loader';\nimport { parse } from '@iarna/toml';\n\n// Create a custom loader for TOML files\nconst createTomlLoader = (\n  options?: LoaderOptions,\n  searchFrom?: string\n): ConfigLoaders =\u003e {\n  return {\n    '.toml': async (filepath: string) =\u003e {\n      try {\n        const content = await readFile(filepath, 'utf-8');\n        const config = parse(content);\n        return { config, filepath };\n      } catch (error) {\n        throw new Error(\n          `Failed to load TOML config from ${filepath}: ${error.message}`\n        );\n      }\n    },\n  };\n};\n\n// Use the custom loader\nconst result = await searchConfig('myapp', undefined, {\n  createLoaders: createTomlLoader,\n});\n```\n\nYou can also reuse existing loaders from `@hyperse/config-loader`. The package exports several built-in loaders like `tsLoader`, `jsonLoader`, and `yamlLoader` that you can compose together to create custom loading behavior.\n\n```typescript\nimport type { ConfigLoaders, LoaderOptions } from '@hyperse/config-loader';\nimport { searchConfig, tsLoader } from '@hyperse/config-loader';\n\n// Create a custom loader for TOML files\nfunction createJsLoader(\n  options?: LoaderOptions,\n  searchFrom?: string\n): ConfigLoaders {\n  return {\n    // Override JavaScript file resolver using tsLoader for better TypeScript support\n    '.js': async (path: string, content: string) =\u003e {\n      const { projectCwd, ...restLoaderOptions } = options || {};\n      return tsLoader({\n        plugins: [],\n        externals: [],\n        ...restLoaderOptions,\n        projectCwd: projectCwd || searchFrom,\n      })(path, content);\n    },\n  };\n}\n\n// Use the custom loader\nconst result = await searchConfig('myapp', undefined, {\n  createLoaders: createJsLoader,\n});\n```\n\n### Supported File Formats\n\nThe config loader supports the following file formats:\n\n- `.js` (ESM and CommonJS)\n- `.mjs` (ESM)\n- `.cjs` (CommonJS)\n- `.ts` (TypeScript)\n- `.mts` (TypeScript ESM)\n- `.json`\n- `.yaml`/`.yml`\n\nThe loader will search for files in the following order:\n\n1. `package.json` (in the `[moduleName]` field)\n2. `.[moduleName]rc`\n3. `.[moduleName]rc.json`\n4. `.[moduleName]rc.yaml`\n5. `.[moduleName]rc.yml`\n6. `.[moduleName]rc.js`\n7. `.[moduleName]rc.mjs`\n8. `.[moduleName]rc.cjs`\n9. `.[moduleName]rc.ts`\n10. `[moduleName].config.js`\n11. `[moduleName].config.mjs`\n12. `[moduleName].config.cjs`\n13. `[moduleName].config.ts`\n14. `[moduleName].config.mts`\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhyperse-io%2Fconfig-loader","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fhyperse-io%2Fconfig-loader","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhyperse-io%2Fconfig-loader/lists"}