Skip to content

Commit 2ec89c0

Browse files
committed
feat: add build-time environment variable validation
1 parent 0723dc2 commit 2ec89c0

4 files changed

Lines changed: 112 additions & 3 deletions

File tree

next.config.mjs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import "./src/env.mjs";
2+
13
/** @type {import('next').NextConfig} */
24
const nextConfig = {
35
reactStrictMode: true

package-lock.json

Lines changed: 59 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
"dependencies": {
3131
"@albedo-link/intent": "^0.13.0",
3232
"@stellar/freighter-api": "^1.7.1",
33+
"@t3-oss/env-nextjs": "^0.13.11",
3334
"next": "^14.2.6",
3435
"next-themes": "^0.4.6",
3536
"react": "^18.3.1",
@@ -38,7 +39,7 @@
3839
"sonner": "^2.0.7",
3940
"stellar-sdk": "^12.1.0",
4041
"web-vitals": "^5.2.0",
41-
"zod": "^3.22.4"
42+
"zod": "^3.25.76"
4243
},
4344
"devDependencies": {
4445
"@hookform/resolvers": "^3.3.2",

src/env.mjs

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
import { createEnv } from "@t3-oss/env-nextjs";
2+
import { z } from "zod";
3+
4+
export const env = createEnv({
5+
/**
6+
* Specify your server-side environment variables schema here. This way you can ensure the app
7+
* isn't built with invalid env vars.
8+
*/
9+
server: {},
10+
11+
/**
12+
* Specify your client-side environment variables schema here. This way you can ensure the app
13+
* isn't built with invalid env vars. To expose them to the client, prefix them with
14+
* `NEXT_PUBLIC_`.
15+
*/
16+
client: {
17+
NEXT_PUBLIC_STELLAR_NETWORK: z.enum(["testnet", "mainnet", "futurenet"]),
18+
NEXT_PUBLIC_SOROBAN_RPC_URL: z.string().url(),
19+
NEXT_PUBLIC_HORIZON_URL: z.string().url(),
20+
NEXT_PUBLIC_AXIONVERA_VAULT_CONTRACT_ID: z
21+
.string()
22+
.regex(/^C[A-Z0-9]{55}$/, "Contract ID must start with 'C' and be 56 characters long"),
23+
NEXT_PUBLIC_AXIONVERA_TOKEN_CONTRACT_ID: z
24+
.string()
25+
.regex(/^C[A-Z0-9]{55}$/, "Contract ID must start with 'C' and be 56 characters long"),
26+
},
27+
28+
/**
29+
* You can't destruct `process.env` as a regular object in the Next.js edge runtimes (e.g.
30+
* middlewares) or client-side so we need to destruct manually.
31+
*/
32+
runtimeEnv: {
33+
NEXT_PUBLIC_STELLAR_NETWORK: process.env.NEXT_PUBLIC_STELLAR_NETWORK,
34+
NEXT_PUBLIC_SOROBAN_RPC_URL: process.env.NEXT_PUBLIC_SOROBAN_RPC_URL,
35+
NEXT_PUBLIC_HORIZON_URL: process.env.NEXT_PUBLIC_HORIZON_URL,
36+
NEXT_PUBLIC_AXIONVERA_VAULT_CONTRACT_ID: process.env.NEXT_PUBLIC_AXIONVERA_VAULT_CONTRACT_ID,
37+
NEXT_PUBLIC_AXIONVERA_TOKEN_CONTRACT_ID: process.env.NEXT_PUBLIC_AXIONVERA_TOKEN_CONTRACT_ID,
38+
},
39+
/**
40+
* Run `build` or `dev` with `SKIP_ENV_VALIDATION` to skip env validation. This is especially
41+
* useful for Docker builds.
42+
*/
43+
skipValidation: !!process.env.SKIP_ENV_VALIDATION,
44+
/**
45+
* Makes it so that empty strings are treated as undefined.
46+
* `SOME_VAR: z.string()` and `SOME_VAR=''` will throw an error.
47+
*/
48+
emptyStringAsUndefined: true,
49+
});

0 commit comments

Comments
 (0)