@karmaniverous/get-dotenv 4.5.2 → 5.0.0-0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (49) hide show
  1. package/LICENSE +28 -0
  2. package/README.md +369 -215
  3. package/dist/cliHost.cjs +1078 -0
  4. package/dist/cliHost.d.cts +193 -0
  5. package/dist/cliHost.d.mts +193 -0
  6. package/dist/cliHost.d.ts +193 -0
  7. package/dist/cliHost.mjs +1074 -0
  8. package/dist/config.cjs +247 -0
  9. package/dist/config.d.cts +53 -0
  10. package/dist/config.d.mts +53 -0
  11. package/dist/config.d.ts +53 -0
  12. package/dist/config.mjs +242 -0
  13. package/dist/env-overlay.cjs +163 -0
  14. package/dist/env-overlay.d.cts +50 -0
  15. package/dist/env-overlay.d.mts +50 -0
  16. package/dist/env-overlay.d.ts +50 -0
  17. package/dist/env-overlay.mjs +161 -0
  18. package/dist/getdotenv.cli.mjs +2817 -40874
  19. package/dist/index.cjs +1482 -40965
  20. package/dist/index.d.cts +206 -67
  21. package/dist/index.d.mts +206 -67
  22. package/dist/index.d.ts +206 -67
  23. package/dist/index.mjs +1454 -40939
  24. package/dist/plugins-aws.cjs +618 -0
  25. package/dist/plugins-aws.d.cts +178 -0
  26. package/dist/plugins-aws.d.mts +178 -0
  27. package/dist/plugins-aws.d.ts +178 -0
  28. package/dist/plugins-aws.mjs +616 -0
  29. package/dist/plugins-batch.cjs +569 -0
  30. package/dist/plugins-batch.d.cts +200 -0
  31. package/dist/plugins-batch.d.mts +200 -0
  32. package/dist/plugins-batch.d.ts +200 -0
  33. package/dist/plugins-batch.mjs +567 -0
  34. package/dist/plugins-init.cjs +282 -0
  35. package/dist/plugins-init.d.cts +182 -0
  36. package/dist/plugins-init.d.mts +182 -0
  37. package/dist/plugins-init.d.ts +182 -0
  38. package/dist/plugins-init.mjs +280 -0
  39. package/getdotenv.config.json +19 -0
  40. package/package.json +228 -139
  41. package/templates/cli/ts/index.ts +9 -0
  42. package/templates/cli/ts/plugins/hello.ts +17 -0
  43. package/templates/config/js/getdotenv.config.js +15 -0
  44. package/templates/config/json/local/getdotenv.config.local.json +7 -0
  45. package/templates/config/json/public/getdotenv.config.json +12 -0
  46. package/templates/config/public/getdotenv.config.json +13 -0
  47. package/templates/config/ts/getdotenv.config.ts +16 -0
  48. package/templates/config/yaml/local/getdotenv.config.local.yaml +7 -0
  49. package/templates/config/yaml/public/getdotenv.config.yaml +10 -0
package/LICENSE ADDED
@@ -0,0 +1,28 @@
1
+ BSD 3-Clause License
2
+
3
+ Copyright (c) 2025, Jason Williscroft
4
+
5
+ Redistribution and use in source and binary forms, with or without
6
+ modification, are permitted provided that the following conditions are met:
7
+
8
+ 1. Redistributions of source code must retain the above copyright notice, this
9
+ list of conditions and the following disclaimer.
10
+
11
+ 2. Redistributions in binary form must reproduce the above copyright notice,
12
+ this list of conditions and the following disclaimer in the documentation
13
+ and/or other materials provided with the distribution.
14
+
15
+ 3. Neither the name of the copyright holder nor the names of its
16
+ contributors may be used to endorse or promote products derived from
17
+ this software without specific prior written permission.
18
+
19
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
23
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
25
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
26
+ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
27
+ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package/README.md CHANGED
@@ -1,215 +1,369 @@
1
- # get-dotenv
2
-
3
- Load environment variables with a cascade of environment-aware dotenv files. You can:
4
-
5
- Asynchronously load environment variables from multiple dotenv files.
6
-
7
- Segregate variables info distinct files:
8
-
9
- - Public files (e.g. `.env`, `env.dev`, `env.test`) are synced with your git repository.
10
- - Private files (e.g. `.env.local`, `env.dev.local`, `env.test.local`) are protected by `.gitignore`.
11
- - Global files (e.g. `.env`, `env.local`) apply to all environments.
12
- - Env files (e.g. `.env.dev`, `.env.dev.local`, `.env.test`, `.env.test.local`) apply to a specific environment.
13
- - [Dynamic files](#dynamic-processing) (`.env.js`) export logic that dynamically & progressively generates new variables or overrides current ones.
14
-
15
- Dynamically specify which variables to load by type.
16
-
17
- Explicitly add variables to the loaded set.
18
-
19
- Extract the resulting variables to an object, `process.env`, a dotenv file, or a logger object, in any combination.
20
-
21
- Customize your dotenv file directories & naming patterns.
22
-
23
- Perform all of the above either programmatically or [from the command line](#command-line-interface), where you can also execute additional commands within the resulting context... including nested `getdotenv` commands that inherit the parent command's settings & context!
24
-
25
- [Execute batched CLI commands](#batch-command) across multiple working directories, with each command inheriting the `getdotenv` context.
26
-
27
- Set defaults for all options in a `getdotenv.config.json` file in your project root directory.
28
-
29
- [Generate an extensible `getdotenv`-based CLI](https://github.com/karmaniverous/get-dotenv-child) for use in your own projects.
30
-
31
- `getdotenv` relies on the excellent [`dotenv`](https://www.npmjs.com/package/dotenv) parser and somewhat improves on [`dotenv-expand`](https://www.npmjs.com/package/dotenv-expand) for recursive variable expansion.
32
-
33
- You can always use `getdotenv` directly on the command line, but its REAL power comes into play when you use it as the foundation of your own CLI. This lets you set defaults globally and configure pre- and post-hooks that mutate your `getdotenv` context and do useful things like grab an AWS session from your dev environment and add it to the command execution context.
34
-
35
- When you plug your own [`commander`](https://www.npmjs.com/package/commander) CLI commands into the `getdotenv` base, they will execute within all of the environmental context created above!
36
-
37
- ## Breaking Changes
38
-
39
- In version 4.0.0, in addition to a full TypeScript refactor, I replaced the use of the unsafe `Function` constructor for dynamic variable processing with a MUCH safer dynamic module import.
40
-
41
- Dynamic importing is intrinsically asynchronous, and so far I haven't been able to figure out how to cram that into the synchronous `getDotenvSync` function. There really aren't THAT many users of this library, so rather than have async & sync versions that do different things, I just eliminated the sync version entirely.
42
-
43
- If you have a use case for sync dotenv processing and DON'T need dynamic variables, let me know and I'll put the restricted version back in. If you have an idea of how to make dynamic imports synchronous, I'm all ears!
44
-
45
- ## Installation
46
-
47
- ```bash
48
- npm install @karmaniverous/get-dotenv
49
- ```
50
-
51
- ## Usage
52
-
53
- ```js
54
- import { getDotenv } from '@karmaniverous/get-dotenv';
55
-
56
- const dotenv = await getDotenv(options);
57
- ```
58
-
59
- Options can be passed programmatically or set in a `getdotenv.config.json` file in your project root directory. The same file also sets default options for the `getdotenv` CLI or any child CLI you spawn from it.
60
-
61
- See the [child CLI example repo](https://github.com/karmaniverous/get-dotenv-child#configuration) for an extensiive discussion of the various config options and how & where to set them.
62
-
63
- ## Dynamic Processing
64
-
65
- This package supports the full [`dotenv-expand`](https://www.npmjs.com/package/dotenv-expand) syntax, with some internal performance improvements.
66
-
67
- Use the `dynamicPath` option to add a relative path to a Javascript module with a default export like this:
68
-
69
- ```js
70
- export default {
71
- SOME_DYNAMIC_VARIABLE: (dotenv) => someLogic(dotenv),
72
- ANOTHER_DYNAMIC_VARIABLE: (dotenv) =>
73
- someOtherLogic(dotenv.SOME_DYNAMIC_VARIABLE),
74
- ONE_MORE_TIME: ({ DESTRUCTRED_VARIABLE, ANOTHER_DYNAMIC_VARIABLE }) =>
75
- DESTRUCTRED_VARIABLE + ANOTHER_DYNAMIC_VARIABLE,
76
- };
77
- ```
78
-
79
- If the value corresponding to a key is a function, it will be executed with the current state of `dotenv` as its single argument and the result applied back to the `dotenv` object. Otherwise, the value will just be applied back to `dotenv`. (Although if you're going to do that then you might as well just create a public global variable in the first place.)
80
-
81
- Since keys will be evaluated progressively, each successive key function will have access to any previous ones. These keys can also override existing variables.
82
-
83
- ### Dynamic Processing with TypeScript
84
-
85
- Even though the rest of your project is in TypeScript, the dynamic processing module SHOULD be in JavasScript.
86
-
87
- Think about it: the module is loaded via a dynamic import, with the file name determined at run time. If you write this module in TS, you'll have to jump through some hoops to get your bundler to compile this file, and you'll have to be careful to set `dynamicPath` to reference the compiled file. That's a lot of work to do for some very simple logic.
88
-
89
- BUT... if you must, then your dynamic module's default export should be of the `GetDotenvDynamic` type, which is defined [here](./src/GetDotenvOptions.ts) and looks like this:
90
-
91
- ```ts
92
- export type ProcessEnv = Record<string, string | undefined>;
93
-
94
- export type GetDotenvDynamicFunction = (
95
- vars: ProcessEnv,
96
- env: string | undefined,
97
- ) => string | undefined;
98
-
99
- export type GetDotenvDynamic = Record<
100
- string,
101
- GetDotenvDynamicFunction | ReturnType<GetDotenvDynamicFunction>
102
- >;
103
- ```
104
-
105
- The second argumnt `env` of the `GetDotenvDynamicFunction` type is the environment token (if any) specified in the controlling `getDotenv` call.
106
-
107
- ## Command Line Interface
108
-
109
- You can also use `getdotenv` from the command line:
110
-
111
- ```bash
112
- > npx getdotenv -h
113
-
114
- # Usage: getdotenv [options] [command]
115
- #
116
- # Base CLI.
117
- #
118
- # Options:
119
- # -e, --env <string> target environment (dotenv-expanded)
120
- # -v, --vars <string> extra variables expressed as delimited key-value pairs (dotenv-expanded): KEY1=VAL1 KEY2=VAL2
121
- # -c, --command <string> command executed according to the --shell option, conflicts with cmd subcommand (dotenv-expanded)
122
- # -o, --output-path <string> consolidated output file (dotenv-expanded)
123
- # -s, --shell [string] command execution shell, no argument for default OS shell or provide shell string (default OS shell)
124
- # -S, --shell-off command execution shell OFF
125
- # -p, --load-process load variables to process.env ON (default)
126
- # -P, --load-process-off load variables to process.env OFF
127
- # -a, --exclude-all exclude all dotenv variables from loading ON
128
- # -A, --exclude-all-off exclude all dotenv variables from loading OFF (default)
129
- # -z, --exclude-dynamic exclude dynamic dotenv variables from loading ON
130
- # -Z, --exclude-dynamic-off exclude dynamic dotenv variables from loading OFF (default)
131
- # -n, --exclude-env exclude environment-specific dotenv variables from loading
132
- # -N, --exclude-env-off exclude environment-specific dotenv variables from loading OFF (default)
133
- # -g, --exclude-global exclude global dotenv variables from loading ON
134
- # -G, --exclude-global-off exclude global dotenv variables from loading OFF (default)
135
- # -r, --exclude-private exclude private dotenv variables from loading ON
136
- # -R, --exclude-private-off exclude private dotenv variables from loading OFF (default)
137
- # -u, --exclude-public exclude public dotenv variables from loading ON
138
- # -U, --exclude-public-off exclude public dotenv variables from loading OFF (default)
139
- # -l, --log console log loaded variables ON
140
- # -L, --log-off console log loaded variables OFF (default)
141
- # -d, --debug debug mode ON
142
- # -D, --debug-off debug mode OFF (default)
143
- # --default-env <string> default target environment
144
- # --dotenv-token <string> dotenv-expanded token indicating a dotenv file (default: ".env")
145
- # --dynamic-path <string> dynamic variables path
146
- # --paths <string> dotenv-expanded delimited list of paths to dotenv directory (default: "./")
147
- # --paths-delimiter <string> paths delimiter string (default: " ")
148
- # --paths-delimiter-pattern <string> paths delimiter regex pattern
149
- # --private-token <string> dotenv-expanded token indicating private variables (default: "local")
150
- # --vars-delimiter <string> vars delimiter string (default: " ")
151
- # --vars-delimiter-pattern <string> vars delimiter regex pattern
152
- # --vars-assignor <string> vars assignment operator string (default: "=")
153
- # --vars-assignor-pattern <string> vars assignment operator regex pattern
154
- # -h, --help display help for command
155
- #
156
- # Commands:
157
- # batch [options] Batch shell commands across multiple working directories.
158
- # cmd Batch execute command according to the --shell option, conflicts with --command option (default command)
159
- # help [command] display help for command
160
- ```
161
-
162
- By default, commands (`-c` or `--command` or the `cmd` subcommand either in the base CLI or in the `batch` subcommand) execute in the default OS shell with the `dotenv` context applied. The `-S` or `--shell-off` options will turn this off, and Execa will [execute your command as Javascript](https://github.com/sindresorhus/execa/blob/main/docs/bash.md).
163
-
164
- Alternatively, you can use the `-s` or `--shell` option to specify a different shell [following the Execa spec](https://github.com/sindresorhus/execa/blob/main/docs/shell.md). This is useful if you're running a command that requires a specific shell, like `bash` or `zsh`.
165
-
166
- Finally, you can set the [`shell`](https://github.com/karmaniverous/get-dotenv-child?tab=readme-ov-file#options) default globally in your `getdotenv.config.json` file.
167
-
168
- See [this example repo](https://github.com/karmaniverous/get-dotenv-child) for a deep dive on using the `getDotenv` CLI and how to extend it for your own projects.
169
-
170
- ### Batch Command
171
-
172
- The `getdotenv` base CLI includes one very useful subcommand: `batch`.
173
-
174
- This command lets you execute a shell command across multiple working directories. Executions occur within the loaded `dotenv` context. Might not be relevant to your specific use case, but when you need it, it's a game-changer!
175
-
176
- My most common use case for this command is a microservice project where release day finds me updating dependencies & performing a release in well over a dozen very similar repositories. The sequence of steps in each case is exactly the same, but I need to respond individually as issues arise, so scripting the whole thing out would fail more often than it would work.
177
-
178
- I use the `batch` command to perform each step across all repositories at once. Once you get used to it, it feels like a superpower!
179
-
180
- Lest you doubt what that kind of leverage can do for you, consider this:
181
-
182
- [![batch superpower in action](./doc/contributions.png)](https://github.com/karmaniverous)
183
-
184
- ```bash
185
- > getdotenv batch -h
186
-
187
- # Usage: getdotenv batch [options] [command]
188
- #
189
- # Batch command execution across multiple working directories.
190
- #
191
- # Options:
192
- # -p, --pkg-cwd use nearest package directory as current working directory
193
- # -r, --root-path <string> path to batch root directory from current working directory (default: "./")
194
- # -g, --globs <string> space-delimited globs from root path (default: "*")
195
- # -c, --command <string> command executed according to the base --shell option, conflicts with cmd subcommand (dotenv-expanded)
196
- # -l, --list list working directories without executing command
197
- # -e, --ignore-errors ignore errors and continue with next path
198
- # -h, --help display help for command
199
- #
200
- # Commands:
201
- # cmd execute command, conflicts with --command option (default subcommand)
202
- # help [command] display help for command
203
- ```
204
-
205
- Note that `batch` executes its commands in sequence, rather than in parallel!
206
-
207
- To understand why, imagine running `npm install` in a dozen repos from the same command line. The visual feedback would be impossible to follow, and if something broke you'd have a really hard time figuring out why.
208
-
209
- Instead, everything runs in sequence, and you get a clear record of exactly what heppened and where. Also worth noting that many complex processes are resource hogs: you would not _want_ to run a dozen Serverless deployments at once!
210
-
211
- Meanwhile, [this issue](https://github.com/karmaniverous/get-dotenv/issues/7) documents the parallel-processing option requirement. Feel free to submit a PR!
212
-
213
- ---
214
-
215
- See more great templates & tools on [my GitHub Profile](https://github.com/karmaniverous)!
1
+ # get-dotenv
2
+
3
+ ## Requirements
4
+
5
+ - Node.js >= 20 (this repository pins 22.19.0 for CI/reproducibility)
6
+
7
+ ## API Reference
8
+ Generated API documentation is hosted at:
9
+ - https://docs.karmanivero.us/get-dotenv
10
+
11
+ The site is built with TypeDoc from the source code in this repository.
12
+
13
+ Load environment variables with a cascade of environment-aware dotenv files. You can:
14
+
15
+ Asynchronously load environment variables from multiple dotenv files.
16
+
17
+ Segregate variables info distinct files:
18
+
19
+ - Public files (e.g. `.env`, `env.dev`, `env.test`) are synced with your git repository.
20
+ - Private files (e.g. `.env.local`, `env.dev.local`, `env.test.local`) are protected by `.gitignore`.
21
+ - Global files (e.g. `.env`, `env.local`) apply to all environments.
22
+ - Env files (e.g. `.env.dev`, `.env.dev.local`, `.env.test`, `.env.test.local`) apply to a specific environment.
23
+ - [Dynamic files](#dynamic-processing) (`.env.js`) export logic that dynamically & progressively generates new variables or overrides current ones.
24
+
25
+ Dynamically specify which variables to load by type.
26
+
27
+ Explicitly add variables to the loaded set.
28
+
29
+ Extract the resulting variables to an object, `process.env`, a dotenv file, or a logger object, in any combination.
30
+
31
+ Customize your dotenv file directories & naming patterns.
32
+
33
+ Perform all of the above either programmatically or [from the command line](#command-line-interface), where you can also execute additional commands within the resulting context... including nested `getdotenv` commands that inherit the parent command's settings & context!
34
+
35
+ [Execute batched CLI commands](#batch-command) across multiple working directories, with each command inheriting the `getdotenv` context.
36
+
37
+ Set defaults for all options in a `getdotenv.config.json` file in your project root directory.
38
+
39
+ [Generate an extensible `getdotenv`-based CLI](https://github.com/karmaniverous/get-dotenv-child) for use in your own projects.
40
+
41
+ `getdotenv` relies on the excellent [`dotenv`](https://www.npmjs.com/package/dotenv) parser and somewhat improves on [`dotenv-expand`](https://www.npmjs.com/package/dotenv-expand) for recursive variable expansion.
42
+
43
+ You can always use `getdotenv` directly on the command line, but its REAL power comes into play when you use it as the foundation of your own CLI. This lets you set defaults globally and configure pre- and post-hooks that mutate your `getdotenv` context and do useful things like grab an AWS session from your dev environment and add it to the command execution context.
44
+
45
+ When you plug your own [`commander`](https://www.npmjs.com/package/commander) CLI commands into the `getdotenv` base, they will execute within all of the environmental context created above!
46
+
47
+ ## Testing
48
+
49
+ This project uses Vitest with the V8 coverage provider. Run:
50
+
51
+ ```bash
52
+ npm run test
53
+ ```
54
+
55
+ ## Installation
56
+
57
+ ```bash
58
+ npm install @karmaniverous/get-dotenv
59
+ ```
60
+
61
+ ## Scaffold
62
+
63
+ You can scaffold config files and a host-based CLI skeleton using the built-in
64
+ init command. Templates are shipped with the package and copied verbatim.
65
+
66
+ Examples:
67
+
68
+ ```bash
69
+ # JSON config + .local variant, and a CLI skeleton named "acme"
70
+ npx getdotenv init . \
71
+ --config-format json \
72
+ --with-local \
73
+ --cli-name acme \
74
+ --force
75
+ ```
76
+
77
+ ```bash
78
+ # TypeScript config with a dynamic example; CLI named "toolbox"
79
+ npx getdotenv init ./apps/toolbox \
80
+ --config-format ts \
81
+ --cli-name toolbox
82
+ ```
83
+
84
+ Collision flow (when a destination file exists):
85
+
86
+ - Interactive prompt: [o]verwrite, [e]xample, [s]kip, or their “all” variants
87
+ [O]/[E]/[S].
88
+ - Non-interactive detection:
89
+ - Treated as `--yes` (Skip All) unless `--force` is provided (Overwrite All).
90
+ - Considered non-interactive when stdin or stdout is not a TTY OR when a
91
+ CI-like environment variable is present (`CI`, `GITHUB_ACTIONS`,
92
+ `BUILDKITE`, `TEAMCITY_VERSION`, `TF_BUILD`).
93
+ - Precedence:
94
+ - `--force` > `--yes` > auto-detect (non-interactive => Skip All).
95
+ - Options overview:
96
+ - `--config-format <json|yaml|js|ts>`
97
+ - `--with-local` to generate `.local` alongside public config (JSON/YAML)
98
+ - `--cli-name <string>` for token substitution (`__CLI_NAME__`) in the CLI
99
+ skeleton
100
+ - `--force` to overwrite all; `--yes` to skip all
101
+
102
+ Notes:
103
+
104
+ - Templates are shipped with the package and copied verbatim.
105
+ - The CLI skeleton replaces `__CLI_NAME__` tokens with your chosen name.
106
+
107
+ ## Usage
108
+
109
+ ````js
110
+ import { getDotenv } from '@karmaniverous/get-dotenv';
111
+
112
+ const dotenv = await getDotenv(options);```
113
+
114
+ Options can be passed programmatically or set in a `getdotenv.config.json` file in your project root directory. The same file also sets default options for the `getdotenv` CLI or any child CLI you spawn from it.
115
+
116
+ See the [child CLI example repo](https://github.com/karmaniverous/get-dotenv-child#configuration) for an extensiive discussion of the various config options and how & where to set them.
117
+
118
+ ## Dynamic Processing
119
+
120
+ This package supports the full [`dotenv-expand`](https://www.npmjs.com/package/dotenv-expand) syntax, with some internal performance improvements. Dynamic variables can be authored in JS or TS.
121
+
122
+ Use the `dynamicPath` option to add a relative path to a Javascript module with a default export like this:
123
+
124
+ ```js
125
+ export default {
126
+ SOME_DYNAMIC_VARIABLE: (dotenv) => someLogic(dotenv),
127
+ ANOTHER_DYNAMIC_VARIABLE: (dotenv) =>
128
+ someOtherLogic(dotenv.SOME_DYNAMIC_VARIABLE),
129
+ ONE_MORE_TIME: ({ DESTRUCTRED_VARIABLE, ANOTHER_DYNAMIC_VARIABLE }) =>
130
+ DESTRUCTRED_VARIABLE + ANOTHER_DYNAMIC_VARIABLE,
131
+ };
132
+ ````
133
+
134
+ If the value corresponding to a key is a function, it will be executed with the current state of `dotenv` as its single argument and the result applied back to the `dotenv` object. Otherwise, the value will just be applied back to `dotenv`. (Although if you're going to do that then you might as well just create a public global variable in the first place.)
135
+
136
+ Since keys will be evaluated progressively, each successive key function will have access to any previous ones. These keys can also override existing variables.
137
+
138
+ ### TypeScript-first dynamic processing
139
+
140
+ You can write your dynamic module in TypeScript and point `dynamicPath` at a `.ts` file. Install [`esbuild`](https://esbuild.github.io/) as a dev dependency to enable automatic compilation:
141
+
142
+ ```ts
143
+ // dynamic.ts
144
+ export default {
145
+ MY_DYNAMIC: ({ APP_SETTING = '' }) => `${APP_SETTING}-ts`,
146
+ };
147
+ ```
148
+
149
+ If `esbuild` is not installed and a direct import fails, get-dotenv attempts a
150
+ simple fallback for single-file `.ts` modules without imports; otherwise it will
151
+ throw with clear guidance to install `esbuild`.
152
+
153
+ Programmatic users can skip files entirely and pass dynamic variables directly:
154
+
155
+ ```ts
156
+ import { getDotenv, defineDynamic } from '@karmaniverous/get-dotenv';
157
+
158
+ const dynamic = defineDynamic({
159
+ MY_DYNAMIC(vars, env) {
160
+ return `${vars.APP_SETTING}-${env ?? ''}`;
161
+ },
162
+ });
163
+
164
+ const vars = await getDotenv({ dynamic, paths: ['./'], env: 'dev' });
165
+ ```
166
+
167
+ Notes:
168
+
169
+ - Programmatic `dynamic` takes precedence over `dynamicPath` when both are provided.
170
+ - Dynamic keys are evaluated progressively, so later keys can reference earlier results.
171
+
172
+ #### Troubleshooting
173
+
174
+ - “Unknown file extension '.ts'” when loading `dynamic.ts`:
175
+ - Install `esbuild` (`npm i -D esbuild`).
176
+
177
+ - “Unable to load dynamic TypeScript file …”:
178
+ - Install `esbuild`. A simple transpile fallback exists only for trivial
179
+ single-file modules; any imports in `dynamic.ts` require `esbuild` bundling.
180
+
181
+ ## Command Line Interface
182
+
183
+ You can also use `getdotenv` from the command line:
184
+
185
+ ```bash
186
+ > npx getdotenv -h
187
+
188
+ # Usage: getdotenv [options] [command]
189
+ #
190
+ # Base CLI.
191
+ #
192
+ # Options:
193
+ # -e, --env <string> target environment (dotenv-expanded)
194
+ # -v, --vars <string> extra variables expressed as delimited key-value pairs (dotenv-expanded): KEY1=VAL1 KEY2=VAL2
195
+ # -o, --output-path <string> consolidated output file (dotenv-expanded)
196
+ # -s, --shell [string] command execution shell, no argument for default OS shell or provide shell string (default OS shell)
197
+ # -S, --shell-off command execution shell OFF
198
+ # -p, --load-process load variables to process.env ON (default)
199
+ # -P, --load-process-off load variables to process.env OFF
200
+ # -a, --exclude-all exclude all dotenv variables from loading ON
201
+ # -A, --exclude-all-off exclude all dotenv variables from loading OFF (default)
202
+ # -z, --exclude-dynamic exclude dynamic dotenv variables from loading ON
203
+ # -Z, --exclude-dynamic-off exclude dynamic dotenv variables from loading OFF (default)
204
+ # -n, --exclude-env exclude environment-specific dotenv variables from loading
205
+ # -N, --exclude-env-off exclude environment-specific dotenv variables from loading OFF (default)
206
+ # -g, --exclude-global exclude global dotenv variables from loading ON
207
+ # -G, --exclude-global-off exclude global dotenv variables from loading OFF (default)
208
+ # -r, --exclude-private exclude private dotenv variables from loading ON
209
+ # -R, --exclude-private-off exclude private dotenv variables from loading OFF (default)
210
+ # -u, --exclude-public exclude public dotenv variables from loading ON
211
+ # -U, --exclude-public-off exclude public dotenv variables from loading OFF (default)
212
+ # -l, --log console log loaded variables ON
213
+ # -L, --log-off console log loaded variables OFF (default)
214
+ # -d, --debug debug mode ON
215
+ # -D, --debug-off debug mode OFF (default)
216
+ # --default-env <string> default target environment
217
+ # --dotenv-token <string> dotenv-expanded token indicating a dotenv file (default: ".env")
218
+ # --dynamic-path <string> dynamic variables path (.js or .ts; .ts is auto-compiled when esbuild is available, otherwise precompile)
219
+ # --paths <string> dotenv-expanded delimited list of paths to dotenv directory (default: "./")
220
+ # --paths-delimiter <string> paths delimiter string (default: " ")
221
+ # --paths-delimiter-pattern <string> paths delimiter regex pattern# --private-token <string> dotenv-expanded token indicating private variables (default: "local")
222
+ # --vars-delimiter <string> vars delimiter string (default: " ")
223
+ # --vars-delimiter-pattern <string> vars delimiter regex pattern
224
+ # --vars-assignor <string> vars assignment operator string (default: "=")
225
+ # --vars-assignor-pattern <string> vars assignment operator regex pattern
226
+ # -h, --help display help for command
227
+ #
228
+ # Commands:
229
+ # batch [options] Batch shell commands across multiple working directories.
230
+ # cmd Batch execute command according to the --shell option, conflicts with --command option (default command)
231
+ # help [command] display help for command
232
+ ```
233
+
234
+ ### Default shell behavior
235
+
236
+ To normalize behavior across platforms, the CLI resolves a default shell when `--shell` is true or omitted:
237
+
238
+ - POSIX: `/bin/bash`
239
+ - Windows: `powershell.exe`
240
+
241
+ ### Batch Command
242
+
243
+ The `getdotenv` base CLI includes one very useful subcommand: `batch`.
244
+
245
+ This command lets you execute a shell command across multiple working directories. Executions occur within the loaded `dotenv` context. Might not be relevant to your specific use case, but when you need it, it's a game-changer!
246
+
247
+ My most common use case for this command is a microservice project where release day finds me updating dependencies & performing a release in well over a dozen very similar repositories. The sequence of steps in each case is exactly the same, but I need to respond individually as issues arise, so scripting the whole thing out would fail more often than it would work.
248
+
249
+ I use the `batch` command to perform each step across all repositories at once. Once you get used to it, it feels like a superpower!
250
+
251
+ Lest you doubt what that kind of leverage can do for you, consider this:
252
+
253
+ [![batch superpower in action](./assets/contributions.png)](https://github.com/karmaniverous)
254
+
255
+ ```bash
256
+ > getdotenv batch -h
257
+
258
+ # Usage: getdotenv batch [options] [command]
259
+ #
260
+ # Batch command execution across multiple working directories.
261
+ #
262
+ # Options:
263
+ # -p, --pkg-cwd use nearest package directory as current working directory
264
+ # -r, --root-path <string> path to batch root directory from current working directory (default: "./")
265
+ # -g, --globs <string> space-delimited globs from root path (default: "*")
266
+ # -c, --command <string> command executed according to the base --shell option, conflicts with cmd subcommand (dotenv-expanded)
267
+ # -l, --list list working directories without executing command
268
+ # -e, --ignore-errors ignore errors and continue with next path
269
+ # -h, --help display help for command
270
+ #
271
+ # Commands:
272
+ # cmd execute command, conflicts with --command option (default subcommand)
273
+ # help [command] display help for command
274
+ ```
275
+
276
+ Note that `batch` executes its commands in sequence, rather than in parallel!
277
+
278
+ To understand why, imagine running `npm install` in a dozen repos from the same command line. The visual feedback would be impossible to follow, and if something broke you'd have a really hard time figuring out why.
279
+
280
+ Instead, everything runs in sequence, and you get a clear record of exactly what heppened and where. Also worth noting that many complex processes are resource hogs: you would not _want_ to run a dozen Serverless deployments at once!
281
+
282
+ Meanwhile, [this issue](https://github.com/karmaniverous/get-dotenv/issues/7) documents the parallel-processing option requirement. Feel free to submit a PR!
283
+
284
+ ---
285
+
286
+ ### Authoring npm scripts and the `-c`/`--cmd` alias
287
+
288
+ When you run commands via `npm run`, flags after `--` are forwarded to your script
289
+ and may be applied to the inner shell command instead of `getdotenv` unless you
290
+ structure your script carefully.
291
+
292
+ - Anti-pattern:
293
+
294
+ ```json
295
+ { "scripts": { "script": "getdotenv echo $APP_SETTING" } }
296
+ ```
297
+
298
+ Then `npm run script -- -e dev` applies `-e` to `echo`, not to `getdotenv`.
299
+
300
+ - Recommended:
301
+ ```json
302
+ { "scripts": { "script": "getdotenv -c 'echo $APP_SETTING'" } }
303
+ ```
304
+ Now `npm run script -- -e dev` applies `-e` to `getdotenv`, which loads and expands
305
+ variables before executing the inner command.
306
+
307
+ Notes:
308
+
309
+ - `-c`/`--cmd` is an alias of the `cmd` subcommand; do not use both in a single invocation.
310
+ - On POSIX shells, prefer single quotes to prevent the outer shell from expanding `$VAR`
311
+ before Node sees it. On PowerShell, single quotes are also literal.
312
+ - Script-level shell overrides (`scripts[name].shell`) still take precedence over the global
313
+ `--shell`.
314
+
315
+ Important:
316
+
317
+ - When using the parent alias `--cmd` with a Node eval payload, quote the entire
318
+ payload as a single token so Commander does not treat `-e/--eval` as
319
+ getdotenv’s `-e, --env` flag.
320
+ - POSIX example:
321
+ ```
322
+ getdotenv --cmd 'node -e "console.log(process.env.APP_SETTING ?? \"\")"'
323
+ ```
324
+ - PowerShell example (single quotes are literal in PowerShell):
325
+ ```
326
+ getdotenv --cmd 'node -e "console.log(process.env.APP_SETTING ?? \"\")"'
327
+ ```
328
+ - If you do not need to pass additional parent flags after the command, you can
329
+ prefer the subcommand form instead:
330
+ ```
331
+ getdotenv --shell-off cmd node -e "console.log(process.env.APP_SETTING ?? '')"
332
+ ```
333
+
334
+ Diagnostics and CI capture:
335
+
336
+ - To capture child stdout/stderr deterministically (e.g., in CI), either set
337
+ the environment variable `GETDOTENV_STDIO=pipe` or pass `--capture`. Outputs
338
+ are buffered and re-emitted after completion.
339
+ - For debugging environment composition, use:
340
+ ```
341
+ getdotenv --trace [keys...] cmd node -e "0"
342
+ ```
343
+ When provided without keys, `--trace` emits a concise origin line for every
344
+ key (parent | dotenv | unset) to stderr before the child process launches.
345
+
346
+ ---
347
+
348
+ ## Guides
349
+
350
+ - [Cascade and precedence](./guides/cascade.md)
351
+ - [Shell execution behavior and quoting](./guides/shell.md)
352
+
353
+ The guides are also included in the [hosted API docs](https://docs.karmanivero.us/get-dotenv).
354
+
355
+ ---
356
+
357
+ ## Generated CLI
358
+
359
+ This package still supports generating a standalone CLI for your projects.
360
+ For most use cases we recommend the new plugin-first host because it resolves
361
+ dotenv context once per invocation, supports composable plugins, and provides
362
+ better subprocess control and diagnostics. If you prefer a thin, fixed
363
+ command surface with defaults baked into config, the generated CLI can be a
364
+ good fit.
365
+
366
+ See the Generated CLI guide for details:
367
+ https://docs.karmanivero.us/get-dotenv/guides/generated-cli
368
+
369
+ See more great templates & tools on [my GitHub Profile](https://github.com/karmaniverous)!