More options to indicate public environment variable then simple publicPrefix
#12375
Development PR
Today, environment variables are implicitly available: anything in process.env can be imported directly (as long as the name is a valid identifier) from $env/static/private, or accessed via env imported from $env/dynamic/private. Environment variables beginning with publicPrefix are available from the public counterparts.
This is... fine, but there is some room for improvement:
- You get random auto-import suggestions — if I type
Hto begin importingHeader.svelte, my editor will helpfully suggest that I meantHOMEBREW_CELLARor something else improbable - There's inconsistency between static (named imports) and dynamic (
env.BLAH), which feels weird. If for some reason you use both$env/dynamic/publicand$env/dynamic/privatein the same module, you will need to rename them since you can't have two imports calledenv - It's weird that you can reference a given env var both statically (inlined into the build) and dynamically (evaluated at runtime)
- There's a lot of modules!
- There's no central place that describes which environment variables are expected
- No validation — if a critical env var is missing or malformed, you might not find out until you start seeing errors in your production logs
- No type safety or inline documentation. Everything is just a string whose purpose you have to infer from the name
This PR presents an explicit alternative. Opt in by adding the following flag to your svelte.config.js...
export default {
kit: {
experimental: {
explicitEnvironmentVariables: true
}
}
};
...and creating a src/env.ts (or src/env.js) that exports variables:
import { defineEnvVars } from '@sveltejs/kit/hooks';
import * as v from 'valibot';
export const variables = defineEnvVars({
// by default, env vars are a) secret, b) evaluated when the app starts, and c) required
POSTGRES_URL: {},
// some environment variables are safe to be used in the client
GOOGLE_ANALYTICS_ID: {
public: true,
// env vars can be validated, using any https://standardschema.dev library
// (here, we're using https://valibot.dev)
schema: v.pipe(v.string(), v.regex(/G-[A-Z0-9]+/))
},
// some can be evaluated at build time, meaning they can be used for dead code elimination
SHOW_DEBUGGING_OVERLAY: {
public: true,
static: true,
// if a description is provided, it will be visible when the imported variable is hovered
description: 'If enabled, will show a FPS meter in the corner of the page',
// validators can transform inputs, e.g. to a boolean
schema: v.pipe(
v.optional(v.string(), ''),
v.transform((str) => str !== '')
)
}
});
The
defineEnvVarshelper just returns its argument, but is useful as it enforces the correct types (and provides autocomplete, etc). I'm tempted to add similar helpers for otherhooks, though that's a conversation for another time.
With those variables defined, we can import them via two new modules — $app/env/private and $app/env/public. As with existing server-only modules, $app/env/private cannot be imported into code that can run in the client.
Types are inferred from validators, where provided, and inline documentation is attached to the variables:
If environment variables are missing, the app errors on startup (or build, for static env vars).
The validators (and indeed the entire src/env module) only ever run on the server. Public variables are sent to the client with the initial server rendered HTML, or (if the initial document is prerendered) by importing a generated module, the same as happens today.
The $app/environment module is aliased as $app/env, to make everything feel a bit more cohesive. The goal is to remove $app/environment and the four $env/* modules (and the associated configuration) in SvelteKit 3.
TODO:
-
generateEnvModuleforadapter-static - Populate
%sveltekit.env%with this rather than the existing env vars, where appropriate - I just realised that public static vars don't work as advertised right now — need to fix that
- Don't bother sending static vars from the server to the client
- Make the docs nice
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 testand lint the project withpnpm lintandpnpm check
Changesets
- If your PR makes a change that should be noted in one or more packages' changelogs, generate a changeset by running
pnpm changesetand following the prompts. Changesets that add features should beminorand those that fix bugs should bepatch. Please prefix changeset messages withfeat:,fix:, orchore:.
Edits
- Please ensure that 'Allow edits from maintainers' is checked. PRs without this option may be closed.
Issue
Describe the problem
i like sveltekit support array for publicPrefix config. I have to deal with a vendor lib that expect public environment variables prefixed with NHOST_* and rest used PUBLIC_* . With current limitation, I have to define duplicate variables
my usecase : https://github.com/xmlking/spectacular/blob/916ef57220c6ef451dc9317e26201bb75a1641c3/.env.example#L42****
Describe the proposed solution
While using some 3rd party service provides ( CMS, Backend-as-a-Service, payment systems) with SvelteKit, we have to use vender provided libraries to interact with their system, sometime they have some Convention-over-configuration to use environment variables that are prefixed with certain text (e.g., NHOST_, VERCEL_ etc) . If those environment variables are needed on both client-side as well as server-side, we have to duplicate them once with vendor prefix and PUBLIC_which leads to duplication.
It will be nice to allow multiple patterns/prefixes to indicate public variables in SvelteKit to support such use-cases.
Alternatives considered
Inspired from Astro astro:env , methodology described here seams more flexible
Importance
nice to have
Additional Information
Ref
What if the prefix could accept an array so that you could specify both PUBLIC and NHOST?
What if the prefix could accept an array so that you could specify both
PUBLICandNHOST?
Yes that could solve my needs
I also need the publicPrefix option to be an array, just like in vite.
Any timeline for when this issue will be picked up?
This problem is quite annoying because we now have to send our env vars via a load function to the client side.
But this will make sharing code via the client side & server side super annoying.
Because svelte will complain that I can't sure page.data.env.MY_ENV on the server side.
Could we please prioritise this?
Please prioritize this. Allowing publicPrefix: string[] is a tiny change with a huge impact.
As a temp workaround, is there some place we can rename env vars and add the prefix ??? Because it doesn't work inside the hooks.server.ts file
In SvelteKit 3, you can name your public environment variables anything