I believe the issue with environment variables is generally that you don't know you need them until something breaks, then you need to find out what the values should be. It is simply pain, and if not documented properly you'll just cry yourself to sleep at night.
Been ripping ct3a zod env stuff for awhile now, so it's great to have this. Also, how is the Next starting template sooo bad??? Like ct3a without ANY of the options feels waaay better than the Next default one.
Oh my god. Please, don't you ever get bothered by the boilerplate? Like micro-optimizing everything makes everything esoteric and that's just terrible.
One thing i’ve been looking for is how to detect changes on the settings and have the system reactively adopt the new setting. For ex - new timeout setting just applies it the api client. But a database url change re-establishes a db connection pool to a new server.
I frequently use env variables to tree shake in different envs at compile time. For example, any place you have process.env.NODE_ENV compiles to the actual value like "development", which tree shaking will interpret as a literal, which means "if ("development" === "production")" will tree shake out any code in this conditional. The approach in this package requires a runtime check which does not allow for tree shaking. Any thoughts on this tradeoff for this approach? A common example is for things like integrated devtools that I don't want shipped to production
Env vars are a mess in React. This just makes me really appreciate the SvelteKit way (fully typed, checked at build because they're just direct imports, server/public separation). I like how this library has validation tho.
I wonder if dotenv cannot be simirarly augmented. They already have checks and a loading mechanism, and it looks like zod could be used to check either the result or the initial environment variables.
I'm a systems guy, not a web dev, so maybe I'm out of touch, but were people not doing this kind of validation anyway? I've done several projects that have been configurable with environment variables, and I always did validation checks when starting the program. It seems strange to me that you would need a library to do this. I mean, maybe it could cut down on a bit of boilerplate, but don't you still have to specify the validation logic somehow? Also, I thought environment variables were conventionally optional. If you absolutely must provide them because they don't have default variables, they're usually better off as either program arguments or in a config file.
@@prestonrasmussen1758 config files should be for default values that don't change much per environment. Anything that has to change per environment (e.g. api endpoints, db server, etc) should be in the env file. The env file should also only be handled by your build tool and not checked into the code repository.
@@darylphuah I understand what you’re saying and assuming you’re a newer engineer. I’m not talking about a config file in the main repo. I’m talking about config files that end up populating the .env file upon deployment, along with secrets in your secret manager. At my current company we use GCP so we are using a config.yaml file along with the GCP secret manager for secret values to populate the env vars using k8s during deployment
@@prestonrasmussen1758 i'm far from being new, but perhaps try to re-read your original comment from the perspective of someone who is new. It would easily be misunderstood.. then you'll be seeing things like "config_production.yml, config_staging.yml, config_dev.yml" files in the code repo together with its credentials. These are unfortunately things I've actually seen in codebases.
I agree, env vars should be validated as early as possible and throw an error if they don't exist. Then the server won't even start up or a build will fail if they are missing. It is funny how overcomplicated this has become with .env, .env.local, .env. and .env..local, and process.env and people defaulting values instead of throwing errors when they are missing. IMO .env files should only really be used locally for convenience and everything should come off process.env at build or run time. If they are needed on the FE they should be replaced at build time or explicitly returned from the backend in a single place and put on the window object.
I still don't really understand what "runtimeEnv" is used for, or why we have to copy/paste everything in there. More importantly, I wanted to verify that adding secret keys here doesn't pass them along to the client. Can someone confirm? This stuff doesn't seem to be documented anywhere; I only see mention of server: and client: bits but not "runtimeEnv". Edit: I tested for myself to verify accessing server env var on the client gives an error. But I still don't understand runtimeEnv. Also in create-t3-app we still have env.js instead of env.mjs -- not sure why that is.
Well, the obvious answer is for security, since using arbitrary user input is asking for trouble. Also, your statement is a bit of an oversimplification. Environments can get manipulated in lots of ways. It's common for CI/CD tooling to use them to inject things like access tokens, so validation could effectively be a test to ensure those pipelines are working as intended.
@@davidboeger6766 I don't agree, there's no way you can "manipulate" env variables unless you had access to the server where the app is running or the Dashboard where your service is hosted, but if someone with bad intentions got that far you have a huge problem somewhere else. About validating the CI/CD pipelines work as intended, this is like saying we don't trust how GitHub or whatever service you want to use work. Therefore I don't see your point.
I've been trying to figure out why my .env.local file isn't working for days and you made me realize its because of not using 'export default' in next config. thank god you were lazy!
6:04 I too wanna die when I run into issues with .js .mjs .cjs .ts .jsx .tsx .mjsx .cjsx I don't even know if .mjsx or .cjsx are real extensions but I am sure we'll invent them as we go.
Why would I use that if I can just add 4 more lines of code instead of importing an external framework to do something easy af? Please guys, just write "You're typing process.env wrong" by Matt.
My problem is environment variables that are not known until practically the moment the app is deployed. For example, an MS Azure "Marketplace Offering" might deploy a React SPA, and that SPA needs to have an Azure AD "app registration client id" for an OAuth flow it has implemented. Unfortunately, the "app registration client id" isn't known at build-time...only during deploy. So, in short, now my SPA app is deployed to an Azure App Service where the "app registration client id" is indeed within an environment variable...but the SPA app (being purely post-build static/bundled files) doesn't have access to that environment variable. FAIL. My current solution is to have the docker container (holding the SPA app) have a startup script which grabs the environment variable and then does a search-replace on the static SPA files before they are served. I wonder if anyone has a better approach.
@@d.sherman8563 Nice!!! How??? Remember, a SPA is just a collection of static files; when serving static files there is no server-side rendering which can reference environment variables.
I used to have to `export FOO=bar`
But now I can add a new library, boilerplates, types, and build steps!
Job security achieved.
Thanks for giving a shout out to the engineer that actually built it
Man I was hoping to find this outside T3 😂
znv
I believe the issue with environment variables is generally that you don't know you need them until something breaks, then you need to find out what the values should be.
It is simply pain, and if not documented properly you'll just cry yourself to sleep at night.
In Django we have django-env package. With it you could setup variables so the project wont start until you set correct values
So you've reinvented config files again? Good job, it only took you 40 years 🥳
This package seems promising enough. I had similar issues with env files. I just used the cleanEnv function from the envalid package to fix them.
How is everyone OK with this... .env could be troublesome sometimes, but importing two new libs to just type check and pre-build validation???
Mabey on really medium to big projects this would really shine
That red swiggly line is one of the best creative thing, give a pat yourself on the back
It'll be inspired by the typewind logo
Guys is this not over engineering
Been ripping ct3a zod env stuff for awhile now, so it's great to have this.
Also, how is the Next starting template sooo bad??? Like ct3a without ANY of the options feels waaay better than the Next default one.
6:04 the infamous dev pain
Oh my god. Please, don't you ever get bothered by the boilerplate? Like micro-optimizing everything makes everything esoteric and that's just terrible.
bloatware...
And of course nexxel is already there with the Nuxt adapter/integration PR! 🥵
0:43 little things like giving credit where credit is due...it's super important. thanks for being a good dude.
One thing i’ve been looking for is how to detect changes on the settings and have the system reactively adopt the new setting.
For ex - new timeout setting just applies it the api client. But a database url change re-establishes a db connection pool to a new server.
Such useful info! Thank you😊😊
I've been using this for years 😂
Does your package support merging of .env, .env.local, .env. and .env..local ?
I frequently use env variables to tree shake in different envs at compile time. For example, any place you have process.env.NODE_ENV compiles to the actual value like "development", which tree shaking will interpret as a literal, which means "if ("development" === "production")" will tree shake out any code in this conditional. The approach in this package requires a runtime check which does not allow for tree shaking. Any thoughts on this tradeoff for this approach?
A common example is for things like integrated devtools that I don't want shipped to production
Env vars are a mess in React. This just makes me really appreciate the SvelteKit way (fully typed, checked at build because they're just direct imports, server/public separation). I like how this library has validation tho.
I'm not sure who faces this, but I'm using nextjs 14 and I want my env to be configurable at runtime rather than build time. Does this solve it?
They suck ass in NextJs for sure, but work great in SvelteKit.
Love it. SvelteKit also has something similar.
I wonder if dotenv cannot be simirarly augmented. They already have checks and a loading mechanism, and it looks like zod could be used to check either the result or the initial environment variables.
Nestjs already does verify environment variables with a joi schema. Maybe, they could move it to dotenv somehow
I'm a systems guy, not a web dev, so maybe I'm out of touch, but were people not doing this kind of validation anyway? I've done several projects that have been configurable with environment variables, and I always did validation checks when starting the program. It seems strange to me that you would need a library to do this. I mean, maybe it could cut down on a bit of boilerplate, but don't you still have to specify the validation logic somehow? Also, I thought environment variables were conventionally optional. If you absolutely must provide them because they don't have default variables, they're usually better off as either program arguments or in a config file.
In my experience, env vars are generally put in a config file for deployments, and we use env vars for our local environments
@@prestonrasmussen1758 config files should be for default values that don't change much per environment. Anything that has to change per environment (e.g. api endpoints, db server, etc) should be in the env file. The env file should also only be handled by your build tool and not checked into the code repository.
@@darylphuah I understand what you’re saying and assuming you’re a newer engineer.
I’m not talking about a config file in the main repo. I’m talking about config files that end up populating the .env file upon deployment, along with secrets in your secret manager.
At my current company we use GCP so we are using a config.yaml file along with the GCP secret manager for secret values to populate the env vars using k8s during deployment
@@prestonrasmussen1758 i'm far from being new, but perhaps try to re-read your original comment from the perspective of someone who is new. It would easily be misunderstood.. then you'll be seeing things like "config_production.yml, config_staging.yml, config_dev.yml" files in the code repo together with its credentials.
These are unfortunately things I've actually seen in codebases.
I agree, env vars should be validated as early as possible and throw an error if they don't exist. Then the server won't even start up or a build will fail if they are missing.
It is funny how overcomplicated this has become with .env, .env.local, .env. and .env..local, and process.env and people defaulting values instead of throwing errors when they are missing.
IMO .env files should only really be used locally for convenience and everything should come off process.env at build or run time.
If they are needed on the FE they should be replaced at build time or explicitly returned from the backend in a single place and put on the window object.
Over-engineering 💯
I still don't really understand what "runtimeEnv" is used for, or why we have to copy/paste everything in there. More importantly, I wanted to verify that adding secret keys here doesn't pass them along to the client. Can someone confirm? This stuff doesn't seem to be documented anywhere; I only see mention of server: and client: bits but not "runtimeEnv".
Edit: I tested for myself to verify accessing server env var on the client gives an error. But I still don't understand runtimeEnv. Also in create-t3-app we still have env.js instead of env.mjs -- not sure why that is.
How do you do quick cuts with ur short vids? Lossless cut seems to maybe do that
"env vars are hard" well u just made them 10 times harder
It doesn't make sense to me, environment variables are controlled values set by the system owner, why should add complexity by validating them!
Well, the obvious answer is for security, since using arbitrary user input is asking for trouble. Also, your statement is a bit of an oversimplification. Environments can get manipulated in lots of ways. It's common for CI/CD tooling to use them to inject things like access tokens, so validation could effectively be a test to ensure those pipelines are working as intended.
@@davidboeger6766 I don't agree, there's no way you can "manipulate" env variables unless you had access to the server where the app is running or the Dashboard where your service is hosted, but if someone with bad intentions got that far you have a huge problem somewhere else.
About validating the CI/CD pipelines work as intended, this is like saying we don't trust how GitHub or whatever service you want to use work. Therefore I don't see your point.
What is hard about env variables? I don't get it
nothing really, this is just nonsense
This took just about as long as building an entire app so…
This is a really awesome solution, my company uses infisical which is another really cool env variable solution. Would recommend!
Theo, any way to use enums (strings) instead of just string?
I've been trying to figure out why my .env.local file isn't working for days and you made me realize its because of not using 'export default' in next config. thank god you were lazy!
I wish JS devs could stop fixing things
Theo talk about Pulumi! I just went to a GDG meet where the spokesperson talked about it and how versatile it is with many different languages!
What is the difference to just plain Zod?
How’s it work with eas and react native?
What the difference between znv and t3-env? Libraries almost identical
T3 -env built on znv,
T3 OSS
What's the extension at the bottom of the terminal?
Tmux statusbar
Man, more crap to do basic stuff. Just stop. Less is more!
I agree, over-engineering at its finest
This is like the Pokémon evolution of dotenv
i use env-var but i will try this
You can't call it a fix when there's no problem to begin with.
please make a new fullstack project with nextjs, somethings changed :(
Wrapper around zod parse(prosess.env) 🤷♂️ treeshake issue = next only
Audio is out of sync for me
6:04 I too wanna die when I run into issues with .js .mjs .cjs .ts .jsx .tsx .mjsx .cjsx
I don't even know if .mjsx or .cjsx are real extensions but I am sure we'll invent them as we go.
Or just use a toml file ??
Team effort
Why would I use that if I can just add 4 more lines of code instead of importing an external framework to do something easy af? Please guys, just write "You're typing process.env wrong" by Matt.
My problem is environment variables that are not known until practically the moment the app is deployed. For example, an MS Azure "Marketplace Offering" might deploy a React SPA, and that SPA needs to have an Azure AD "app registration client id" for an OAuth flow it has implemented. Unfortunately, the "app registration client id" isn't known at build-time...only during deploy. So, in short, now my SPA app is deployed to an Azure App Service where the "app registration client id" is indeed within an environment variable...but the SPA app (being purely post-build static/bundled files) doesn't have access to that environment variable. FAIL.
My current solution is to have the docker container (holding the SPA app) have a startup script which grabs the environment variable and then does a search-replace on the static SPA files before they are served. I wonder if anyone has a better approach.
can you file an issue with a repro and your deployment steps? really curious to see if we can improve your situation.
ugh that's rough..... I'll follow this comment in case something pops up haha
@@juliusmarminge file an issue where? Give me an address (of a github repo?) and I'll post something.
You can use env variables at runtime without issue, they don’t have to be hardcoded.
@@d.sherman8563 Nice!!! How??? Remember, a SPA is just a collection of static files; when serving static files there is no server-side rendering which can reference environment variables.
*something on javascriptian*
Cool package. Embarrassing demo.
Lollll
omg 7:27 💀
first?
zodSchema.parse(process.env)