├── .eslintrc.json
├── .github
└── FUNDING.yml
├── .gitignore
├── LICENSE
├── README.md
├── env.mjs
├── examples
├── with-manual-implementation
│ ├── .env.example
│ ├── .eslintrc.json
│ ├── .gitignore
│ ├── env.d.ts
│ ├── env.mjs
│ ├── next.config.mjs
│ ├── package.json
│ ├── pages
│ │ ├── _app.tsx
│ │ └── index.tsx
│ ├── postcss.config.js
│ ├── public
│ │ └── favicon.ico
│ ├── styles
│ │ └── globals.css
│ ├── tailwind.config.js
│ └── tsconfig.json
└── with-package
│ ├── .env.example
│ ├── .eslintrc.json
│ ├── .gitignore
│ ├── env.d.ts
│ ├── env.mjs
│ ├── next.config.mjs
│ ├── package.json
│ ├── pages
│ ├── _app.tsx
│ └── index.tsx
│ ├── postcss.config.js
│ ├── public
│ └── favicon.ico
│ ├── styles
│ └── globals.css
│ ├── tailwind.config.js
│ └── tsconfig.json
├── index.ts
├── package.json
├── rollup.config.js
└── tsconfig.json
/.eslintrc.json:
--------------------------------------------------------------------------------
1 | {
2 | "parserOptions": {
3 | "ecmaVersion": 2018,
4 | "sourceType": "module"
5 | },
6 | "extends": [
7 | "plugin:prettier/recommended",
8 | "plugin:@typescript-eslint/recommended"
9 | ],
10 | "overrides": [{ "files": ["*.mjs", "*.ts", "*.tsx"] }]
11 | }
12 |
--------------------------------------------------------------------------------
/.github/FUNDING.yml:
--------------------------------------------------------------------------------
1 | github: jacobadevore
2 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | ### STANDARD GIT IGNORE FILE ###
2 |
3 | # DEPENDENCIES
4 | node_modules/
5 | /.pnp
6 | .pnp.js
7 | package-lock.json
8 | yarn.lock
9 |
10 | # TESTING
11 | /coverage
12 | *.lcov
13 | .nyc_output
14 |
15 | # BUILD
16 | build/
17 | public/build/
18 | dist/
19 | generated/
20 |
21 | # ENV FILES
22 | .env
23 | .env.local
24 | .env.development.local
25 | .env.test.local
26 | .env.production.local
27 |
28 | # LOGS
29 | logs
30 | *.log
31 | npm-debug.log*
32 | yarn-debug.log*
33 | yarn-error.log*
34 |
35 | # MISC
36 | .idea
37 | .turbo/
38 | .cache/
39 | .next/
40 | .nuxt/
41 | tmp/
42 | temp/
43 | .docusaurus
44 |
45 | # MAC
46 | ._*
47 | .DS_Store
48 | Thumbs.db
49 |
50 | .turbo
51 | .vercel
52 | .rollup.cache
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2023 Jacob Devore
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
Next-ValidEnv
2 | Typesafe environment variables for Next.js
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
16 |
17 |
18 | Created by
19 |
24 |
25 | ---
26 |
27 | ### Installation
28 |
29 | ```sh
30 | npm install zod next-validenv
31 |
32 | yarn add zod next-validenv
33 | ```
34 |
35 | ```sh
36 | npm install --save-dev @typescript-eslint/parser @typescript-eslint/eslint-plugin eslint typescript
37 |
38 | yarn add --dev @typescript-eslint/parser @typescript-eslint/eslint-plugin eslint typescript
39 | ```
40 |
41 | ### First, modify `.eslintrc.json`
42 |
43 | Append `"extends"` with `"plugin:@typescript-eslint/recommended"`
44 |
45 | ```js
46 | {
47 | "extends": ["plugin:@typescript-eslint/recommended"]
48 | }
49 | ```
50 |
51 | ### Create `env.mjs`
52 |
53 | Where your server and client schemas live for typesafe environment variables
54 |
55 | ```js
56 | //@ts-check
57 | import { validateEnvironmentVariables } from "next-validenv";
58 |
59 | import { z } from "zod";
60 |
61 | /**
62 | * Specify your environment variables schema here.
63 | * This way, you can ensure the app isn't built with invalid environment variables.
64 | * By default, environment variables are only available in the Node.js environment, meaning they won't be exposed to the browser. In order to expose a variable to the browser you have to prefix the variable with NEXT_PUBLIC_.
65 | * -> Don't use any Zod .transform() methods in the schema (will cause `implicitly has type 'any'` error) <-
66 | */
67 | export const schema = z.object({
68 | NODE_ENV: z.enum(["development", "test", "production"]),
69 | });
70 |
71 | /**
72 | * Environment variable declarations based on the schema help structure your environment variables programmatically.
73 | * @type {{ [k in keyof z.infer]: z.infer[k] | undefined }}
74 | */
75 | export const env = {
76 | NODE_ENV: process.env.NODE_ENV,
77 | };
78 |
79 | validateEnvironmentVariables(schema, env);
80 | ```
81 |
82 | ### Update ~~`next.config.js`~~ to `next.config.mjs`
83 |
84 | ```js
85 | // @ts-check
86 | /**
87 | * Run `build` or `dev` with `SKIP_ENV_VALIDATION` to skip env validation.
88 | * This is especially useful for Docker builds.
89 | */
90 | !process.env.SKIP_ENV_VALIDATION && (await import("./env.mjs"));
91 |
92 | /** @type {import("next").NextConfig} */
93 | const config = {
94 | reactStrictMode: true,
95 | };
96 | export default config;
97 | ```
98 |
99 | ### Create `env.d.ts`
100 |
101 | ```js
102 | import { env } from "./env.mjs";
103 |
104 | type EnvType = typeof env;
105 |
106 | export {};
107 |
108 | declare global {
109 | namespace NodeJS {
110 | interface ProcessEnv extends EnvType, NodeJS.ProcessEnv {}
111 | }
112 | }
113 | ```
114 |
115 | ### That's it! Now you can use `process.env` and get typesafe environment variables
116 |
117 | ```js
118 | process.env.NODE_ENV; // Typesafe environment variables
119 | ```
120 |
121 | ---
122 |
123 | ## Manual Implementation
124 |
125 | Follow the below guide to manually implement typesafe environment variables in Next.js without installing the Next-ValidEnv library
126 |
127 | ### Installation
128 |
129 | ```sh
130 | npm install zod
131 |
132 | yarn add zod
133 | ```
134 |
135 | ```sh
136 | npm install --save-dev @typescript-eslint/parser @typescript-eslint/eslint-plugin eslint typescript
137 |
138 | yarn add --dev @typescript-eslint/parser @typescript-eslint/eslint-plugin eslint typescript
139 | ```
140 |
141 | ### First, modify `.eslintrc.json`
142 |
143 | Append `"extends"` with `"plugin:@typescript-eslint/recommended"`
144 |
145 | ```js
146 | {
147 | "extends": ["plugin:@typescript-eslint/recommended"]
148 | }
149 | ```
150 |
151 | ### Create `env.mjs`
152 |
153 | Where your server and client schemas live for typesafe environment variables
154 |
155 | ```js
156 | // @ts-check
157 | import { z } from "zod";
158 |
159 | /**
160 | * Specify your environment variables schema here.
161 | * This way, you can ensure the app isn't built with invalid environment variables.
162 | * By default, environment variables are only available in the Node.js environment, meaning they won't be exposed to the browser. In order to expose a variable to the browser you have to prefix the variable with NEXT_PUBLIC_.
163 | * -> Don't use any Zod .transform() methods in the schema (will cause `implicitly has type 'any'` error) <-
164 | */
165 | export const schema = z.object({
166 | NODE_ENV: z.enum(["development", "test", "production"]),
167 | });
168 |
169 | /**
170 | * Environment variable declarations based on the schema help structure your environment variables programmatically.
171 | * @type {{ [k in keyof z.infer]: z.infer[k] | undefined }}
172 | */
173 | export const env = {
174 | NODE_ENV: process.env.NODE_ENV,
175 | };
176 |
177 | /**
178 | * --------------------------------
179 | * --------------------------------
180 | * Next-ValidEnv Manual Implementation
181 | * --------------------------------
182 | * --------------------------------
183 | */
184 |
185 | export const formatZodErrors = (
186 | /** @type z.ZodFormattedError