Skip to content

feat: add optional option to EnvVarConfig for optional environment variables#16336

Closed
Rich-Harris wants to merge 3 commits into
version-3from
optional-env-vars
Closed

feat: add optional option to EnvVarConfig for optional environment variables#16336
Rich-Harris wants to merge 3 commits into
version-3from
optional-env-vars

Conversation

@Rich-Harris

@Rich-Harris Rich-Harris commented Jul 14, 2026

Copy link
Copy Markdown
Member

This is an alternative approach to #16267. Rather than having a three-way enum, this adds a boolean, optional: true, alongside the existing public: true and static: true. (Credit to @elliott-with-the-longest-name-on-github for realising that there's no reason a static variable can't be optional — this is why a boolean matrix makes more sense than an enum.)

When a variable is marked optional, its type is T | undefined (where T is usually string). SvelteKit will not throw an error if the value is missing when the app runs. This is effectively a shorthand for using a schema:

export const variables = defineEnvVars({
  MY_OPTIONAL_THING: {
-   schema: v.optional(v.string())
+   optional: true
  }
});

Note that this isn't quite the same as the 'runtime' option in #16267 — if you want variables to be required when building is false, you would still need to do something like this...

export const variables = defineEnvVars({
  MY_RUNTIME_ONLY_THING: {
-   schema: building ? v.undefined() : v.string()
  }
});

...which does leave open a valid question about whether this change is truly worthwhile. I leave it here for others to discuss.

Another possible design would be to flip it: instead of saying 'this variable is not needed at build time', we could make that the default (stubbing in the empty string for anything that wasn't present) and add an option that says 'this is needed at build time', for things needed during prerendering etc:

export const variables = defineEnvVars({
  MY_RUNTIME_ONLY_THING: {},
  MY_PRERENDER_TIME_THING: {
+   build: true
  }
});

The type of both MY_RUNTIME_ONLY_THING and MY_PRERENDER_TIME_THING would be string; the value of MY_RUNTIME_ONLY_THING would be the empty string during build.

One small wrinkle here is that if you had a custom schema, we would have to use it to parse the empty string in case the value was transformed, and that would fail in some cases:

export const variables = defineEnvVars({
  MY_RUNTIME_ONLY_THING: {
+   schema: v.pipe(v.string(), v.parseJson())
  },
  MY_PRERENDER_TIME_THING: {
    build: true
  }
});

So the developer would have to jump through hoops in these cases:

export const variables = defineEnvVars({
  MY_RUNTIME_ONLY_THING: {
+   schema: v.pipe(building ? v.optional(v.string(), '{}') : v.string()), v.parseJson())
  },
  MY_PRERENDER_TIME_THING: {
    build: true
  }
});

Maybe that's an unusual enough case that it doesn't matter?


Please don't delete this checklist! Before submitting the PR, please make sure you do the following:

  • It's really useful if your PR references an issue where it is discussed ahead of time. In many cases, features are absent for a reason. For large changes, please create an RFC: https://github.com/sveltejs/rfcs
  • This message body should clearly illustrate what problems it solves.
  • Ideally, include a test that fails without this PR but passes with it.

Tests

  • Run the tests with pnpm test and lint the project with pnpm lint and pnpm check

Changesets

  • If your PR makes a change that should be noted in one or more packages' changelogs, generate a changeset by running pnpm changeset and following the prompts. Changesets that add features should be minor and those that fix bugs should be patch. Please prefix changeset messages with feat:, fix:, or chore:.

Edits

  • Please ensure that 'Allow edits from maintainers' is checked. PRs without this option may be closed.

@pkg-svelte-dev

pkg-svelte-dev Bot commented Jul 14, 2026

Copy link
Copy Markdown

Install the latest version of @sveltejs/kit from adacf99:

pnpm add https://pkg.svelte.dev/@sveltejs/kit/c/adacf99c94a25b44c141e82ad128ebb830ca31a4

Open in pkg.svelte.dev: https://pkg.svelte.dev/repos/kit/pr/16336

@changeset-bot

changeset-bot Bot commented Jul 14, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: adacf99

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
@sveltejs/kit Minor

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@svelte-docs-bot

Copy link
Copy Markdown

Comment thread packages/kit/src/exports/public.d.ts
…e variable is required.", which is inverted and contradicts the property name and its own bullet points.

This commit fixes the issue reported at packages/kit/src/exports/public.d.ts:2478

## Bug

In `packages/kit/src/exports/public.d.ts` (line ~2476) the JSDoc for the `optional?: boolean` property begins with:

```
Whether the variable is required.
```

This summary is semantically inverted:

- The property is named `optional`.
- The bullet points state that `true` allows the value to be `undefined` (i.e. makes it optional) and `false` requires the value to be present.
- `@default false`.

So a value of `true` makes the variable **optional**, not required. The summary line describes the opposite of what the property does. Anyone hovering over `optional` in their editor gets a misleading one-line description.

## Fix

Changed the summary line to `Whether the variable is optional.` in both:

- `packages/kit/src/exports/public.d.ts` (source)
- `packages/kit/types/index.d.ts` (generated output, kept in sync as required by the guideline to commit generated types)

The bullet points and `@default` were already correct and were left unchanged.

Co-authored-by: Vercel <vercel[bot]@users.noreply.github.com>
Co-authored-by: Rich-Harris <hello@rich-harris.dev>
@teemingc

Copy link
Copy Markdown
Member

One of the original concerns from the issue was having to do the building ? dance for every runtime env var. Also, having the type as possibly undefined nullifies the schema’s usefulness since a check is needed in the runtime code again (we can probably easily fix this with TypeScript though)

@Rich-Harris

Copy link
Copy Markdown
Member Author

We decided against doing any of these options, because it's just extremely easy to get whatever behaviour you want with the schema option. We could do a better job of documenting certain patterns but the feature itself is fine the way it is

@dummdidumm
dummdidumm deleted the optional-env-vars branch July 17, 2026 14:07
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add a more straightforward method of opting dynamic explicit environment variables out of build-time validation

2 participants