|
2 | 2 |
|
3 | 3 | This package helps you integrate [varlock](https://varlock.dev) into a [Next.js](https://nextjs.org) project. |
4 | 4 |
|
5 | | -It is designed as a drop-in replacement for `@next/env`, which is the internal package that Next.js uses to load `.env` files. |
| 5 | +It is designed as a drop-in replacement for [`@next/env`](https://www.npmjs.com/package/@next/env), which is the internal package that Next.js uses to load `.env` files, as well as a small plugin for your `next.config.*` file that enables additional security features. |
6 | 6 |
|
7 | | -It also provides a plugin for your `next.config.*` file to enable additional security features, such as: |
8 | | -- Redacting sensitive config values from logs |
9 | | -- Preventing sensitive config values from being leaked – both at build time and runtime |
| 7 | +Compared to the default `@next/env` behavior, this package provides: |
10 | 8 |
|
| 9 | +- validation of your env vars against your `.env.schema` |
| 10 | +- type-generation and type-safe env var access with built-in docs |
| 11 | +- redaction of sensitive values from application logs |
| 12 | +- leak detection and prevention, both at build and runtime |
| 13 | +- more flexible multi-env handling - you can load env-specific files other than `.env.development`/`.env.production` |
11 | 14 |
|
12 | | -## Installation |
13 | | - |
14 | | -First install this module and `varlock` using your package manager of choice: |
15 | | -> `npm install @varlock/nextjs-integration varlock` (or pnpm, yarn, etc) |
16 | | -
|
17 | | -### Step 1: Install `@next/env` override |
18 | | - |
19 | | -You must tell your package manager to override all resolution of `@next/env` with `@varlock/nextjs-integration`. |
20 | | - |
21 | | -The method for doing this depends on your package manager: |
22 | | - |
23 | | -**NPM** |
24 | | -See [NPM overrides docs](https://docs.npmjs.com/cli/v9/configuring-npm/package-json#overrides) |
25 | | - |
26 | | -NPM lets you reference another installed dependency in overrides. For example: `"dep-to-override": "$other-installed-dep"`. |
27 | | - |
28 | | -_package.json_ |
29 | | -``` |
30 | | - "overrides": { |
31 | | - "@next/env": "npm:@varlock/nextjs-integration" |
32 | | - } |
33 | | -``` |
34 | | - |
35 | | -**Yarn** |
36 | | -See [yarn resolutions docs](https://yarnpkg.com/configuration/manifest#resolutions) |
37 | | - |
38 | | -_root package.json_ |
39 | | -``` |
40 | | - "resolutions": { |
41 | | - "**/@next/env": "npm:@varlock/nextjs-integration" |
42 | | - } |
43 | | -``` |
44 | | - |
45 | | -> ⚠️ If in a monorepo, this must be done in the monorepo root `package.json` file |
46 | | -
|
47 | | -**pnpm (version 10+)** |
48 | | -See [pnpm overrides docs](https://pnpm.io/settings#overrides) |
49 | | - |
50 | | -> ⚠️ This must be set in `pnpm-workspace.yaml`, regardless of whether you are using a monorepo or not |
51 | | -
|
52 | | -_pnpm-workspace.yaml_ |
53 | | -``` |
54 | | -overrides: |
55 | | - "@next/env": "npm:@varlock/nextjs-integration" |
56 | | -``` |
57 | | - |
58 | | -**pnpm (version 9)** |
59 | | -See [pnpm overrides docs](https://pnpm.io/settings#overrides) |
60 | | - |
61 | | -> ⚠️ If in a monorepo, this must be set in the root `package.json` file |
62 | | -
|
63 | | -_root package.json_ |
64 | | -``` |
65 | | - "pnpm": { |
66 | | - "overrides": { |
67 | | - "@next/env": "npm:@varlock/nextjs-integration" |
68 | | - } |
69 | | - } |
70 | | -``` |
71 | | - |
72 | | - |
73 | | -### Step 2: Enable `next.config.*` plugin |
74 | | - |
75 | | -While using _only_ the override will swap `.env` loading duties over to varlock, to get the full benefits, you must also add a config plugin in your `next.config.ts` (or `next.config.js`) file. |
76 | | - |
77 | | -Next.js does not have a proper plugin system, but we can add a small transformation function on top of your existing config, which will install the necessary adjustments. |
78 | | - |
79 | | -Here is an example of how to do this: |
80 | | - |
81 | | -```ts |
82 | | -import type { NextConfig } from "next"; |
83 | | -import { varlockNextConfigPlugin } from '@varlock/nextjs-integration/plugin'; |
84 | | - |
85 | | -const nextConfig: NextConfig = { |
86 | | - // your existing config... |
87 | | -}; |
88 | | - |
89 | | -export default varlockNextConfigPlugin()(nextConfig); |
90 | | -``` |
91 | | - |
92 | | - |
93 | | - |
94 | | -## Accessing env vars in your code |
95 | | -While your resolved config will be re-injected as normal env vars and you can continue to use `process.env.SOMEVAR` as usual, we recommend using varlock's imported `ENV` object instead. For example: |
96 | | - |
97 | | -```ts |
98 | | -import { ENV } from 'varlock/env'; |
99 | | - |
100 | | -console.log(process.env.SOMEVAR); // 🆗 still works |
101 | | -console.log(ENV.SOMEVAR); // ✨ but this is recommended |
102 | | -``` |
103 | | - |
104 | | -### Type-safety |
105 | | - |
106 | | -To enable type-safety and IntelliSense for your env vars, you must enable the [`@generateTypes` root decorator](https://varlock.dev/reference/root-decorators/#generatetypes) in your `.env.schema`. |
107 | | -> ⚠️ If you ran `npx varlock init`, this will likely already be enabled for you. |
108 | | -
|
109 | | -```env-spec |
110 | | -# @generateTypes(lang='ts', path='env.d.ts') |
111 | | -# --- |
112 | | -# your config items... |
113 | | -``` |
114 | | - |
115 | | -This will make types available both for `process.env` and for varlock's `ENV` object. |
116 | | - |
117 | | -### Why use `ENV` instead of `process.env`? |
118 | | -- Any non-string values (e.g., number, boolean) will actually be their coerced value, rather than a string |
119 | | -- _All_ non-sensitive items will be replaced at build time, not just `NEXT_PUBLIC_` prefixed items |
120 | | -- Better error messages when using invalid keys, or server-side keys that are not available on the client |
121 | | -- Enables further DX improvements in the future, such as tighter control over which items are bundled at build time. |
122 | | - |
123 | | - |
124 | | - |
125 | | -## Managing multiple environments (dev, preview, prod, etc) |
126 | | - |
127 | | -Varlock excels at managing multiple environments and can load multiple _environment-specific_ .env files (e.g., `.env.development`, `.env.preview`, `.env.production`, etc.). |
128 | | - |
129 | | -While `.env.schema`, `.env`, and `.env.local` will always be loaded, loading env-specific files is controlled by a notion of an _environment flag_. |
130 | | - |
131 | | -[Next.js .env handling](https://nextjs.org/docs/pages/guides/environment-variables#loading-environment-variables-with-nextenv) has the following behavior to set the env flag and control loading env-specific .env files: |
132 | | -- use `test` if `NODE_ENV` is set to `test` |
133 | | -- otherwise use `development` if running `next dev` |
134 | | -- otherwise use `production` |
135 | | - |
136 | | -By default, this module will match that behaviour, but we recommend using the [`@envFlag` root decorator](https://varlock.dev/reference/root-decorators/#envflag) in your `.env.schema` to specify your own _custom environment flag_, such as `APP_ENV`. |
137 | | - |
138 | | -**⚠️ Without a custom env flag, you will not have the ability to use a non-production env file (e.g., `.env.preview`, `.env.staging`, etc) for your non-prod deployments.** |
139 | | - |
140 | | -How we set the value of our env flag will depend on your deployment platform. |
141 | | - |
142 | | -When running locally, or building and deploying your next app on a platform you control, you can set it explicitly, often passed in via `package.json` scripts. For example: |
143 | | -```json |
144 | | -// package.json |
145 | | -"scripts": { |
146 | | - "build:preview": "APP_ENV=preview next build", |
147 | | - "start:preview": "APP_ENV=preview next start", |
148 | | - "build:prod": "APP_ENV=production next build", |
149 | | - "start:prod": "APP_ENV=production next start", |
150 | | - "test": "APP_ENV=test jest" |
151 | | -} |
152 | | -``` |
153 | | - |
154 | | -However on some cloud platforms (e.g., Vercel, Cloudflare, etc), you may not have control over a boot command, or even the ability to vary environment variables as you would like. |
155 | | -Even if you do, it's not always ideal to have this configuration buried in a UI rather than your code. |
156 | | - |
157 | | -In these cases, we can set the value of `APP_ENV` (or whatever you name your env flag) using resolver functions to transform existing env vars that the platform's CI/CD pipeline provides (e.g., branch name, platform's notion of env, etc) |
158 | | - |
159 | | -The following examples show how you could do this, but note that you could segment your environments (and name them) however you like. |
160 | | - |
161 | | -### Vercel |
162 | | - |
163 | | -In Vercel, you can set `APP_ENV` explicitly in their env vars UI. But to keep everything contained in your schema, you can use the injected `VERCEL_ENV`. |
164 | | - |
165 | | -```env-spec |
166 | | -# @envFlag=APP_ENV |
167 | | -# --- |
168 | | -# current environment type, injected by vercel during deployments |
169 | | -# @type=enum(development, preview, production) |
170 | | -# @docsUrl="https://vercel.com/docs/environment-variables/system-environment-variables#system-environment-variables" |
171 | | -VERCEL_ENV= |
172 | | -# Our env flag, used to toggle loading of env-specific files |
173 | | -APP_ENV=fallback($VERCEL_ENV, development) |
174 | | -``` |
175 | | - |
176 | | -If you need more specific environments based on branch names, you can use `VERCEL_GIT_COMMIT_REF` instead. See the Cloudflare example below for more details. |
177 | | - |
178 | | -### Cloudflare Workers Build |
179 | | - |
180 | | -In Cloudflare Workers Builds, it is not possible to alter our build command for prod versus non-prod builds, and there is no concept of branch-specific env vars. |
181 | | - |
182 | | -We must rely on the current branch name, injected as `WORKERS_CI_BRANCH`, to determine what our env flag should be. |
183 | | - |
184 | | -We can use the following strategy to set our env flag: |
185 | | -- `production` – if `WORKERS_CI_BRANCH` is set to `main`, this is a production deployment |
186 | | -- `preview` – if `WORKERS_CI_BRANCH` is set to anything else, this is a preview deployment |
187 | | -- `development` – if `WORKERS_CI_BRANCH` is not set, this means we are not within CI, so we must be doing local development |
188 | | -- `test` – we can set this explicitly in our test command. For example, in our `package.json` scripts, we could use `"test": "APP_ENV=test jest"`. |
189 | | - |
190 | | -```env-spec |
191 | | -# @envFlag=APP_ENV |
192 | | -# --- |
193 | | -# current branch set by Cloudflare Workers Build |
194 | | -# @docsUrl="https://developers.cloudflare.com/workers/ci-cd/builds/configuration/#environment-variables" |
195 | | -WORKERS_CI_BRANCH= |
196 | | -# Our env flag, used to toggle loading of env-specific files |
197 | | -# @type=enum(development, preview, production, test) |
198 | | -APP_ENV=remap($WORKERS_CI_BRANCH, production="main", preview=regex(.*), development=undefined) |
199 | | -``` |
200 | | - |
201 | | -## Managing Sensitive Config Values |
202 | | - |
203 | | -Next.js itself uses the [`NEXT_PUBLIC_` prefix](https://nextjs.org/docs/pages/guides/environment-variables#bundling-environment-variables-for-the-browser) to determine which env vars can be considered _public_ (i.e., not sensitive). These public vars will be bundled at build-time made available in the browser. |
204 | | - |
205 | | -Varlock controls the default sensitive behavior via the [`@defaultSensitive` root decorator](https://varlock.dev/reference/root-decorators/#defaultsensitive). |
206 | | - |
207 | | -If you want to continue using the prefix, you can use `# @defaultSensitive=inferFromPrefix('NEXT_PUBLIC_')` in your `.env.schema` file. |
208 | | - |
209 | | -```env-spec |
210 | | -# @defaultSensitive=inferFromPrefix('NEXT_PUBLIC_') |
211 | | -# --- |
212 | | -FOO= # sensitive |
213 | | -NEXT_PUBLIC_FOO= # non-sensitive, due to prefix |
214 | | -``` |
215 | | - |
216 | | -However, we recommend you set `@defaultSensitive` to `true` or `false` and then explicitly tag individual items using the [`@sensitive`](https://varlock.dev/reference/item-decorators/#sensitive) item decorator. For example: |
217 | | - |
218 | | -```env-spec |
219 | | -# @defaultSensitive=true |
220 | | -# --- |
221 | | -SECRET_FOO= # will be sensitive, due to default |
222 | | -# @sensitive=false |
223 | | -NON_SECRET_FOO= |
224 | | -``` |
225 | | - |
226 | | -> ⚠️ NOTE - All non-sensitive items will be bundled at build-time via varlock's `ENV` object, while `process.env` replacements will only include `NEXT_PUBLIC_` prefixed items. |
| 15 | +See [our docs site](https://varlock.dev/integrations/nextjs/) for complete installation and usage instructions. |
227 | 16 |
|
228 | 17 |
|
0 commit comments