{"id":13725455,"url":"https://github.com/lukeed/ley","last_synced_at":"2025-10-09T18:23:55.954Z","repository":{"id":43105650,"uuid":"239457169","full_name":"lukeed/ley","owner":"lukeed","description":"(WIP) Driver-agnostic database migrations","archived":false,"fork":false,"pushed_at":"2024-03-24T10:24:40.000Z","size":129,"stargazers_count":266,"open_issues_count":13,"forks_count":14,"subscribers_count":4,"default_branch":"master","last_synced_at":"2025-09-18T10:28:47.521Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","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/lukeed.png","metadata":{"files":{"readme":"readme.md","changelog":null,"contributing":null,"funding":".github/FUNDING.yml","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},"funding":{"github":"lukeed"}},"created_at":"2020-02-10T07:58:53.000Z","updated_at":"2025-09-07T01:56:05.000Z","dependencies_parsed_at":"2024-01-06T01:53:55.019Z","dependency_job_id":"d52992cc-17d3-4267-9566-f01e43d5b089","html_url":"https://github.com/lukeed/ley","commit_stats":{"total_commits":97,"total_committers":4,"mean_commits":24.25,"dds":"0.12371134020618557","last_synced_commit":"0cf486e06090696405ab7e82b6d54eff408fe4e5"},"previous_names":[],"tags_count":11,"template":false,"template_full_name":null,"purl":"pkg:github/lukeed/ley","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lukeed%2Fley","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lukeed%2Fley/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lukeed%2Fley/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lukeed%2Fley/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/lukeed","download_url":"https://codeload.github.com/lukeed/ley/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lukeed%2Fley/sbom","scorecard":{"id":604485,"data":{"date":"2025-08-11","repo":{"name":"github.com/lukeed/ley","commit":"0cf486e06090696405ab7e82b6d54eff408fe4e5"},"scorecard":{"version":"v5.2.1-40-gf6ed084d","commit":"f6ed084d17c9236477efd66e5b258b9d4cc7b389"},"score":3.6,"checks":[{"name":"Packaging","score":-1,"reason":"packaging workflow not detected","details":["Warn: no GitHub/GitLab publishing workflow detected."],"documentation":{"short":"Determines if the project is published as a package that others can easily download, install, easily update, and uninstall.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#packaging"}},{"name":"Code-Review","score":2,"reason":"Found 7/30 approved changesets -- score normalized to 2","details":null,"documentation":{"short":"Determines if the project requires human code review before pull requests (aka merge requests) are merged.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#code-review"}},{"name":"Maintained","score":0,"reason":"0 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project is \"actively maintained\".","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#maintained"}},{"name":"Binary-Artifacts","score":10,"reason":"no binaries found in the repo","details":null,"documentation":{"short":"Determines if the project has generated executable (binary) artifacts in the source repository.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#binary-artifacts"}},{"name":"Dangerous-Workflow","score":10,"reason":"no dangerous workflow patterns detected","details":null,"documentation":{"short":"Determines if the project's GitHub Action workflows avoid dangerous patterns.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#dangerous-workflow"}},{"name":"Token-Permissions","score":0,"reason":"detected GitHub workflow tokens with excessive permissions","details":["Warn: no topLevel permission defined: .github/workflows/ci.yml:1","Info: no jobLevel write permissions found"],"documentation":{"short":"Determines if the project's workflows follow the principle of least privilege.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#token-permissions"}},{"name":"Pinned-Dependencies","score":0,"reason":"dependency not pinned by hash detected -- score normalized to 0","details":["Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/ci.yml:14: update your workflow using https://app.stepsecurity.io/secureworkflow/lukeed/ley/ci.yml/master?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/ci.yml:15: update your workflow using https://app.stepsecurity.io/secureworkflow/lukeed/ley/ci.yml/master?enable=pin","Warn: npmCommand not pinned by hash: .github/workflows/ci.yml:21","Warn: npmCommand not pinned by hash: .github/workflows/ci.yml:25","Warn: downloadThenRun not pinned by hash: .github/workflows/ci.yml:37","Info:   0 out of   2 GitHub-owned GitHubAction dependencies pinned","Info:   0 out of   2 npmCommand dependencies pinned","Info:   0 out of   1 downloadThenRun dependencies pinned"],"documentation":{"short":"Determines if the project has declared and pinned the dependencies of its build process.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#pinned-dependencies"}},{"name":"CII-Best-Practices","score":0,"reason":"no effort to earn an OpenSSF best practices badge detected","details":null,"documentation":{"short":"Determines if the project has an OpenSSF (formerly CII) Best Practices Badge.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#cii-best-practices"}},{"name":"Security-Policy","score":0,"reason":"security policy file not detected","details":["Warn: no security policy file detected","Warn: no security file to analyze","Warn: no security file to analyze","Warn: no security file to analyze"],"documentation":{"short":"Determines if the project has published a security policy.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#security-policy"}},{"name":"Fuzzing","score":0,"reason":"project is not fuzzed","details":["Warn: no fuzzer integrations found"],"documentation":{"short":"Determines if the project uses fuzzing.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#fuzzing"}},{"name":"Vulnerabilities","score":10,"reason":"0 existing vulnerabilities detected","details":null,"documentation":{"short":"Determines if the project has open, known unfixed vulnerabilities.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#vulnerabilities"}},{"name":"License","score":10,"reason":"license file detected","details":["Info: project has a license file: license:0","Info: FSF or OSI recognized license: MIT License: license:0"],"documentation":{"short":"Determines if the project has defined a license.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#license"}},{"name":"Signed-Releases","score":-1,"reason":"no releases found","details":null,"documentation":{"short":"Determines if the project cryptographically signs release artifacts.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#signed-releases"}},{"name":"Branch-Protection","score":0,"reason":"branch protection not enabled on development/release branches","details":["Warn: branch protection not enabled for branch 'master'"],"documentation":{"short":"Determines if the default and release branches are protected with GitHub's branch protection settings.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#branch-protection"}},{"name":"SAST","score":0,"reason":"SAST tool is not run on all commits -- score normalized to 0","details":["Warn: 0 commits out of 7 are checked with a SAST tool"],"documentation":{"short":"Determines if the project uses static code analysis.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#sast"}}]},"last_synced_at":"2025-08-21T01:15:49.007Z","repository_id":43105650,"created_at":"2025-08-21T01:15:49.007Z","updated_at":"2025-08-21T01:15:49.007Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":279001940,"owners_count":26083226,"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","status":"online","status_checked_at":"2025-10-09T02:00:07.460Z","response_time":59,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"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":[],"created_at":"2024-08-03T01:02:23.934Z","updated_at":"2025-10-09T18:23:55.939Z","avatar_url":"https://github.com/lukeed.png","language":"JavaScript","funding_links":["https://github.com/sponsors/lukeed"],"categories":["JavaScript"],"sub_categories":[],"readme":"\u003cdiv align=\"center\"\u003e\n  \u003cimg src=\"shots/logo.png\" alt=\"ley\" height=\"200\" /\u003e\n\u003c/div\u003e\n\n\u003cdiv align=\"center\"\u003e\n  \u003ca href=\"https://npmjs.org/package/ley\"\u003e\n    \u003cimg src=\"https://badgen.net/npm/v/ley\" alt=\"version\" /\u003e\n  \u003c/a\u003e\n  \u003ca href=\"https://github.com/lukeed/ley/actions\"\u003e\n    \u003cimg src=\"https://github.com/lukeed/ley/workflows/CI/badge.svg\" alt=\"CI\" /\u003e\n  \u003c/a\u003e\n  \u003ca href=\"https://npmjs.org/package/ley\"\u003e\n    \u003cimg src=\"https://badgen.net/npm/dm/ley\" alt=\"downloads\" /\u003e\n  \u003c/a\u003e\n\u003c/div\u003e\n\n\u003cdiv align=\"center\"\u003eDriver agnostic database migrations\u003c/div\u003e\n\n## TODO\n\n\u003e **WIP:** What's here is the end of Night #1\n\n- [ ] driver support:\n  - [x] [`pg`](https://www.npmjs.com/package/pg)\n  - [x] [`postgres`](https://www.npmjs.com/package/postgres)\n  - [x] [`mysql`](https://www.npmjs.com/package/mysql)\n  - [x] [`mysql2`](https://www.npmjs.com/package/mysql2)\n  - [x] [`better-sqlite3`](https://www.npmjs.com/package/better-sqlite3)\n  - [ ] [`sqlite`](https://www.npmjs.com/package/sqlite)\n- [ ] complete test coverage\n- [ ] complete documentation\n\n## Features\n\n* **Agnostic**\u003cbr\u003e\n  _Supports [`postgres`](https://www.npmjs.com/package/postgres), [`pg`](https://www.npmjs.com/package/pg), [`better-sqlite3`](https://www.npmjs.com/package/better-sqlite3), [`sqlite`](https://www.npmjs.com/package/sqlite), [`mysql`](https://www.npmjs.com/package/mysql), [`mysql2`](https://www.npmjs.com/package/mysql2), and [custom drivers!](#drivers)_\n\n* **Lightweight**\u003cbr\u003e\n  _Does **not** include any driver dependencies._\n\n* **Transactional**\u003cbr\u003e\n  _Runs all migration files within a transaction for rollback safety._\n\n* **Familiar**\u003cbr\u003e\n  _Does **not** invent new syntax or abstractions.\u003cbr\u003eYou're always working directly with your driver of choice._\n\n* **Flexible**\u003cbr\u003e\n  _Find the CLI to restrictive? You may require `ley` for your own scripting!_\n\n\n## Install\n\n```\n$ npm install --save-dev ley\n```\n\n\n## Usage\n\n\u003e Both [Programmatic](#programmatic) and [CLI](#cli) usages are supported.\n\n### Setup\n\nYou must have a `migrations` directory created, preferably in your project's root.\n\n\u003e **Note:** You may configure the target directory and location.\n\nYour filenames within this directory determine _the order of their execution._\u003cbr\u003e\nBecause of this, it's often recommended to prefix migrations with a timestamp or numerical sequence.\n\n***Numerical Sequence***\n\n```\n/migrations\n  |-- 000-users.js\n  |-- 001-teams.js\n  |-- 002-seats.js\n```\n\n\u003e **Note**: You may create the next file via `ley new todos --length 3` where `todos` is a meaningful name.\u003cbr\u003eThe above command will create the `migrations/003-todos.js` filepath.\n\n***Timestamped***\n\n```\n/migrations\n  |-- 1581323445-users.js\n  |-- 1581323453-teams.js\n  |-- 1581323458-seats.js\n```\n\n\u003e **Note**: You may create the next file via `ley new todos --timestamp` where `todos` is a meaningful name.\u003cbr\u003eThe above command will create the `migrations/1584389617-todos.js` filepath...or similar.\n\n\n**The order of your migrations is critically important!**\u003cbr\u003eMigrations must be treated as an append-only immutable task chain. Without this, there's no way to _reliably_ rollback or recreate your database.\n\n\u003e **Example:** (Above) You cannot apply/create `001-teams.js` _after_ `002-seats.js` has already been applied.\u003cbr\u003eDoing so would force your teammates or database replicas to recreate \"the world\" in the wrong sequence.\u003cbr\u003eThis may not _always_ pose a problem (eg, unrelated tasks) but it **often does** and so `ley` enforces this practice.\n\nLastly, each migration file must have an `up` and a `down` task.\u003cbr\u003e\nThese must be exported functions \u0026mdash; `async` okay! \u0026mdash; and will receive your pre-installed client driver as its only argument:\n\n```js\nexports.up = async function (DB) {\n  // with `pg` :: DB === pg.Client\n  await DB.query(`select * from users`);\n\n  // with `postgres` :: DB === sql``\n  await DB`select * from users`;\n}\n\nexports.down = async function (DB) {\n  // My pre-configured \"undo\" function\n}\n```\n\n### CLI\n\n  1) Add `ley` as one of your `package.json` scripts; `\"migrate\"`, for example:\n\n      ```js\n      // package.json\n      {\n        \"scripts\": {\n          \"migrate\": \"ley\"\n        }\n      }\n      ```\n\n  2) Invoke `ley up` to apply new migrations, or `ley down` to rollback previous migrations.\n\n      ```sh\n      $ npm run migrate up\n      $ yarn migrate up\n      ```\n\n      \u003cimg width=\"300\" src=\"shots/up1.png\" alt=\"ley up screenshot #1\"\u003e\u003cbr\u003e\n      \u003cimg width=\"300\" src=\"shots/up2.png\" alt=\"ley up screenshot #2\"\u003e\u003cbr\u003e\n      \u003cimg width=\"300\" src=\"shots/up3.png\" alt=\"ley up screenshot #3\"\u003e\u003cbr\u003e\n\n### Programmatic\n\n\u003e **Note:** See [API](#api) for documentation\n\nWith programmatic/scripting usage, you will not inherit any of `ley`'s CLI tooling, which includes all colors and error formatting. Instead, you must manually catch \u0026 handle all thrown Errors.\n\n```js\nconst ley = require('ley');\n\nconst successes = await ley.up({ ... });\n```\n\n## Config\n\n\u003e **TL;DR:** The contents of a `ley.config.js` file (default file name) is irrelevant to `ley` itself!\n\nA config file is entirely optional since `ley` assumes that you're providing the correct environment variable(s) for your client driver. However, that may not always be possible. In those instances, a `ley.config.js` file (default file name) can be used to adjust your [driver](#drivers)'s `connect` method – the file contents are passed directly to this function.\n\nFor example, if your hosting provider sets non-standard environment variables for the client driver (like Heroku does), you could extract the information and set the standard environment variables:\n\n```js\n// ley.config.js\nif (process.env.DATABASE_URL) {\n  const { parse } = require('pg-connection-string');\n\n  // Extract the connection information from the Heroku environment variable\n  const { host, database, user, password } = parse(process.env.DATABASE_URL);\n\n  // Set standard environment variables\n  process.env.PGHOST = host;\n  process.env.PGDATABASE = database;\n  process.env.PGUSERNAME = user;\n  process.env.PGPASSWORD = password;\n}\n```\n\nOr, if your database provider requires certain SSL connection options to be set in production, you could do that:\n\n```js\n// ley.config.js\nconst options = {};\n\nif (process.env.NODE_ENV === 'production') {\n  options.ssl = true;\n}\n\nmodule.exports = options;\n```\n\nWhen the config filename uses the `.js` extension, then `ley` will attempt to auto-load a `.mjs` or a `.cjs` variant of the file if/when the original `.js` file was not found. This means that, by default, these files are searched (in order):\n\n* `ley.config.js`\n* `ley.config.mjs`\n* `ley.config.cjs`\n\n## ES Modules\n\nAs of `ley@0.7.0` and Node.js 12+, you may choose to use [ECMAScript modules (ESM)](https://nodejs.org/api/esm.html). There are a few ways to take advantage of this:\n\n\u003e **Note:** These are _separate_ options. You **do not** need to perform both items\n\n1. Define [`\"type\": \"module\"`](https://nodejs.org/api/packages.html#packages_type) in your root `package.json` file. \u003cbr\u003eThis signals the Node.js runtime that _all_ `*.js` files in the project should be treated as ES modules. With this setting, you may only use CommonJS format within `.cjs` files.\n\n      ```js\n      // package.json\n      {\n        \"type\": \"module\",\n        \"scripts\": {\n          \"migrate\": \"ley\"\n        }\n      }\n      ```\n\n2. Author ES modules _only_ in `.mjs` files. \u003cbr\u003eRegardless of the value of the `\"type\"` field (above), `.mjs` files are always treated as ES modules and `.cjs` files are always treated as CommonJS.\n\nIn terms of `ley` usage, this means that your [config file](#config) may use ESM syntax. Similarly, by default, both `ley.config.mjs` and `ley.config.cjs` will be auto-loaded, if found and `ley.config.js` is missing.\n\n```js\n// ley.config.mjs\n// or w/ \"type\": \"module\" ~\u003e ley.config.js\nexport default {\n\thost: 'localhost',\n\tport: 5432,\n\t// ...\n}\n```\n\nFinally, migration files may also be written using ESM syntax:\n\n```js\n// migrations/000-example.mjs\n// or w/ \"type\": \"module\" ~\u003e migrations/000-example.js\nexport async function up(DB) {\n  // with `pg` :: DB === pg.Client\n  await DB.query(`select * from users`);\n\n  // with `postgres` :: DB === sql``\n  await DB`select * from users`;\n}\n\nexport async function down(DB) {\n  // My pre-configured \"undo\" function\n}\n```\n\nYou may generate new migration files in ESM syntax by passing the `--esm` flag to the `ley new` command:\n\n```sh\n$ ley new todos --esm\n#=\u003e migrations/003-todos.mjs\n\n$ cat migrations/003-todos.mjs\n#=\u003e export async function up(client) {\n#=\u003e }\n#=\u003e \n#=\u003e export async function down(client) {\n#=\u003e }\n```\n\n## Drivers\n\nOut of the box, `ley` includes drivers for the following npm packages:\n\n* [`postgres`](https://www.npmjs.com/package/postgres)\n* [`pg`](https://www.npmjs.com/package/pg)\n* [`mysql`](https://www.npmjs.com/package/mysql)\n* [`mysql2`](https://www.npmjs.com/package/mysql2)\n* [`better-sqlite3`](https://www.npmjs.com/package/better-sqlite3)\n\nWhen no driver is specified, `ley` will attempt to autodetect usage of these libraries in the above order.\n\nHowever, should you need a driver that's not listed – or should you need to override a supplied driver – you may easily do so via a number of avenues:\n\n1) CLI users can add `--driver \u003cfilename\u003e` to any command; or\n2) Programmatic users can pass [`opts.driver`](#optsdriver) to any command; or\n3) A `ley.config.js` file can export a special `driver` config key.\n\nWith any of these, if `driver` is a string then it will be passed through `require()` automatically. Otherwise, with the latter two, the `driver` is assumed to be a [`Driver`](/ley.d.ts#L45-L67) class and is validated as such.\n\n\u003e **Important:** All drivers must adhere to the [`Driver` interface](/ley.d.ts#L45-L67)!\n\n\n## Typed Migrations\n\nFor extra confidence while writing your migration file(s), there are two options:\n\n### TypeScript\n\n1. Ensure [`tsm`](https://www.npmjs.com/package/tsm) is installed\n\n2. Run `ley` with the [`require`](#optsrequire) option so that `tsm` can process file(s)\n\n   ```sh\n   $ ley -r tsm \u003ccmd\u003e\n   # or\n   $ ley --require tsm \u003ccmd\u003e\n   ```\n\n### JSDoc\n\nYou may also use [JSDoc](https://jsdoc.app/) annotations throughout your file to achieve (most) of the benefits of TypeScript, but without installing and configuring TypeScript.\n\n```js\n/** @param {import('pg').Client} DB */\nexports.up = async function (DB) {\n  await DB.query(...)\n}\n```\n\n## API\n\n\u003e **Important:** See [Options](#options) for common options shared all commands. \u003cbr\u003eIn this `API` section, you will only find **command-specific** options listed.\n\n\n### ley.up(opts?)\nReturns: `Promise\u003cstring[]\u003e`\n\nReturns a list of the _relative filenames_ (eg, `000-users.js`) that were successfully applied.\n\n#### opts.single\nType: `boolean`\u003cbr\u003e\nDefault: `false`\n\nEnable to apply **only one** migration file's `up` task.\u003cbr\u003e\nBy default, all migration files will be queue for application.\n\n\n\n### ley.down(opts?)\nReturns: `Promise\u003cstring[]\u003e`\n\nReturns a list of the _relative filenames_ (eg, `000-users.js`) that were successfully applied.\n\n#### opts.all\nType: `boolean`\u003cbr\u003e\nDefault: `false`\n\nEnable to apply **all** migration files' `down` task.\u003cbr\u003e\nBy default, only the most recently-applied migration file is invoked.\n\n\n### ley.status(opts?)\nReturns: `Promise\u003cstring[]\u003e`\n\nReturns a list of the _relative filenames_ (eg, `000-users.js`) that have not yet been applied.\n\n\n### ley.new(opts?)\nReturns: `Promise\u003cstring\u003e`\n\nReturns the newly created _relative filename_ (eg, `000-users.js`).\n\n#### opts.filename\nType: `string`\n\n**Required.** The name of the file to be created.\n\n\u003e **Note:** A prefix will be prepended based on [`opts.timestamp`](#optstimestamp) and [`opts.length`](#optslength) values.\u003cbr\u003eIf your input does not already end with an extension, then `.js` or `.mjs` will be appended.\n\n#### opts.esm\nType: `boolean`\u003cbr\u003e\nDefault: `false`\n\nCreate a migration file with ESM syntax.\n\n\u003e **Note:** When true, the `opts.filename` will contain the `.mjs` file extension unless your input already has an extension.\n\n#### opts.timestamp\nType: `boolean`\u003cbr\u003e\nDefault: `false`\n\nShould the migration file have a timestamped prefix?\u003cbr\u003e\nIf so, will use `Date.now()` floored to the nearest second.\n\n#### opts.length\nType: `number`\u003cbr\u003e\nDefault: `5`\n\nWhen **not** using a timestamped prefix, this value controls the prefix total length.\u003cbr\u003e\nFor example, `00000-users.js` will be followed by `00001-teams.js`.\n\n\n## Options\n\n\u003e **Note:** These are available to _all_ `ley` commands. \u003cbr\u003e_See [API](#api) for programmatic command documentation._\n\n#### opts.cwd\nType: `string`\u003cbr\u003e\nDefault: `.`\n\nA target location to treat as the current working directory.\n\n\u003e **Note:** This value is `path.resolve()`d from the current `process.cwd()` location.\n\n#### opts.dir\nType: `string`\u003cbr\u003e\nDefault: `migrations`\n\nThe directory (relative to `opts.cwd`) to find migration files.\n\n#### opts.driver\nType: `string` or `Driver`\u003cbr\u003e\nDefault: `undefined`\n\nWhen defined and a `string`, this can be (a) the **name** of an internal driver, (b) the **name** of a third-party [driver](#drivers) module, or (c) a **filepath** to a local [driver](#drivers) implementation. It will pass through `require()` as written.\n\nWhen defined an _not_ a `string`, it's expected to match the [`Driver` interface](/ley.d.ts#L45-L67) and will be validated immediately.\n\nWhen undefined, `ley` searches for all supported client drivers in this order:\n\n```js\n['postgres', 'pg', 'mysql', 'mysql2', 'better-sqlite3']\n```\n\n#### opts.config\nType: `object`\u003cbr\u003e\nDefault: `undefined`\n\nA configuration object for your client driver to establish a connection.\u003cbr\u003e\nWhen unspecified, `ley` assumes that your client driver is able to connect through `process.env` variables.\n\n\u003e **Note:** The `ley` CLI will search for a `ley.config.js` config file (configurable). \u003cbr\u003e\nIf found, this file may contain an object or a function that resolves to _anything_ of your chosing. \u003cbr\u003e\nPlease see [Config](#config) for more information.\n\n#### opts.require\nType: `string` or `string[]`\u003cbr\u003e\nDefault: `undefined`\n\nA module name (or list of names) to be `require`d by `ley` at startup.\n\nFor example, you may want to use [`dotenv`](http://npmjs.com/package/dotenv) to load existing `.env` file(s) in your project:\n\n```js\nconst ley = require('ley');\n\nconst files = await ley.status({\n  require: ['dotenv/config']\n});\n```\n\nThrough [CLI](#cli) usage, this is equivalent to:\n\n```sh\n$ ley -r dotenv/config status\n# or\n$ ley --require dotenv/config status\n```\n\n\n## License\n\nMIT © [Luke Edwards](https://lukeed.com)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flukeed%2Fley","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Flukeed%2Fley","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flukeed%2Fley/lists"}