Hey guys, have you ever had this happen to you? You ask your agent to work on some comics code and generally these days it does a really great job, but occasionally it will trip up on some stupid type error when accessing environment variables. Well, hopefully this issue shall appear no more as a new feature silently dropped in Convex 1.39 a couple of weeks ago and has largely flown underneath the radar, but I think is really awesome. So that's why I want to dive into it a little bit deeper in this video. So, first make sure you're running the latest version of Convex. As of the time of making this video, it's 1.41, but you need at least 1.39 or later for this new feature. And then in your convex directory, you can open your convex.config.ts file or create it. And then as part of your define app call, um you can now declare what environment variables in here your app expects. So here for example you can see that I've defined two environment variables uh open AAI API key and log level and you can see that I've defined open AI key as being a string using the comics validators and log level is an optional environment variable that could be either the value debug info or error. This is really nice that comx is going to catch our types here a little bit. But do just note that because environment variables like by default have to always be strings, comx is only going to support a subset of validators here. So no numbers or objects or anything like that for now unfortunately. Now after you've done that, you can run npxconvexdev and what comments is going to do is generate a typed envend functions files. So here we're now doing envi API key and you can see that it's got our two environment variables on here. Very very nice. Now obviously you still need to define these environment variables in your convex deployment because if you don't convex is just going to yell at you required environment variables are not set blah blah blah blah blah blah and then yeah it's also going to yell at you if uh your values don't match the validator correctly. Environment variable log level does not match this declare validator blah blah blah blah blah. So, we can go ahead and change this. And u by the way, do you know that you can set environment variables on the terminal with the convex CLI? And extra bonus points, you can keep a a secret value out of your bash history by not providing the value as part of the initial call. Instead, you provide it after you press enter like this. And by the way, notice as I change the environment variable, the the convex dev process immediately rebuilds, which is just such a nice little quality of life thing. And obviously if in the future we were to change a value again then comx is not going to let us deploy if it doesn't match our environment variables expected environment variables. Super nice. Now just channeling my future prediction skills. I'm imagining that you guys are without doubt going to ask me why can't you use Zod or some other favorite validator of yours here instead of the convex validators. Well, it's limited to convex uh validators right now because this validation of the environment variables happens at the Rust layer of [music] convex and thus we can't just run arbitrary JavaScript there. Maybe in the future we could shell out to a V8 process to do the validation. If there's enough demand for that kind of thing, drop me a comment down below if you'd like to see Zod or one other validator there. And if we get enough comments, maybe we'll make it happen. Oh, I almost forgot to mention components also got a big upgrade here, too. So when you define a component, you can also declare certain environment variables you expect to be there in the parent application. [music] Then when you come to use a given component in application, you can directly pass specific environment variables down if you don't want it to be inherited from the p the parents environment. So this is super nice because it means that you're no longer wondering what environment variables a given component expects and then just having it crash at runtime. All right, so just to recap, you can now tell Convex that you expect some environment variables to be set for your deployment and expect that they take a particular type. I personally love this because it feels very like convexy, doesn't it? Like everything in convex is just code like your schema or your generated API. So it feels very natural that the kind of missing bl missing piece of state which is your environment variables also get that same treatment. And this is also obviously very good for agents as well for the same reason that agents love schemas and generator APIs because they can get immediate context on what they should be expect here at runtime and it also allows them to get feedback when they [ __ ] something up. And by the way, if you do for some reason still want to use process.en then go ahead. This new typed environment variable stuff um isn't a breaking change. So you can still use the old way if you'd like. But anyways, I think that's enough for me for today. I hope you enjoyed this video and if you did, please do drop me a like and sub. And until next time, thanks for watching. Cheerio.
Have you ever had this happen to you? You (or your coding agent) are working away on some Convex code, everything is going great with the schemas, queries and mutations, then someone reaches for process.env.OPEN_AI_KEY instead of OPENAI_API_KEY. TypeScript says nothing, and you only find out at runtime.
That's because process.env is stringly typed. There's no way for the type system (or an agent) to know which variables exist or what shape their values should take.
Well NO MORE, as a new feature silently dropped in Convex 1.39.0 a couple of weeks ago that has largely flown under the radar but I think is really awesome. You can now declare your deployment's environment variables in code, with validators, and get a fully typed env object to use in your backend functions:
So first make sure you are running Convex 1.39.0 or later. Then pop open your convex/convex.config.ts file and as part of your defineApp call you can now declare what environment variables your app expects:
You can use validators from convex/values to declare what sort of shape you expect your vars to take, the same ones you already know from schemas and function arguments. One thing to note though: because env var values are always strings, only a subset of validators is supported here:
v.string(): any string value
v.literal("value"): an exact string value
v.union(v.literal("a"), v.literal("b")): one of several exact values
v.optional(...): wraps any of the above to mark a variable as optional
So no v.number() I'm afraid, at least for now.
Now after you run npx convex dev, Convex is going to generate a typed env object that you can import inside your backend functions:
Super cool! Autocomplete works, typos are compile errors, and the value's type matches its validator.
Setting the variables
Now you obviously still need to set these environment variables on your Convex deployment, declaring them just tells Convex what to expect. You can set them in the dashboard:
Convex dashboard environment variable settings
Or via the CLI:
1npx convex envset OPENAI_API_KEY
2
If you don't set a required variable, Convex is going to yell at you when you push:
1Error: Unable to finish push to https://secret-buzzard-634.convex.cloud
2Error fetching POST https://secret-buzzard-634.convex.cloud/api/deploy2/finish_push 400 Bad Request: MissingEnvironmentVariables: Hit an error while pushing:
3Required environment variables are not set: OPENAI_API_KEY. Set them in the Convex dashboard or CLI before pushing.
4
And it's also going to yell at you if a value doesn't match its validator:
1Error fetching POST https://secret-buzzard-634.convex.cloud/api/deploy2/finish_push 400 Bad Request: InvalidEnvironmentVariable: Hit an error while pushing:
2Environment variable LOG_LEVEL does not match its declared validator: Value does not match validator.
34Value: "foo"5Validator: v.union(v.literal("debug"), v.literal("info"), v.literal("error"))6
Also really good.
By the way, notice that as you change an env var the dev process immediately picks it up and rebuilds, such a nice little quality of life thing:
109:49:27 Convex functions ready!(2.92s)2
And this isn't just a push-time thing either. If you were to later change or remove a variable from the dashboard or CLI in a way that breaks the declaration, Convex isn't going to let that through, which protects us. Noice!
Why not Zod?
A natural question is why you can't use Zod or other validation libraries for the env var validation?
Environment variable validation happens in the Rust layer of Convex, where arbitrary JavaScript can't run, so right now we are limiting it to Convex validators.
And the parent app can wire those up when it uses the component, either by reference to one of its own variables or with a literal value:
1// convex/convex.config.ts2import{ defineApp }from"convex/server";3import{ v }from"convex/values";4import myComponent from"@example/my-component/convex.config";56const app =defineApp({7 env:{8OPENAI_API_KEY: v.string(),9MY_COMPONENT_API_KEY: v.string(),10},11});1213app.use(myComponent,{14 env:{15// Pass by reference: stays in sync with the app's variable,16// even when it changes between deploys17API_KEY: app.env.MY_COMPONENT_API_KEY,18// Or pass a literal value19MODE:"live",20},21});2223exportdefault app;24
If a component declares required env vars then the app that installs it has to provide them, or the push fails. So no longer do you have to wonder whether you have set all the environment variables a component needs, only to have it crash on you at runtime!
Conclusion
So just to recap: you can now tell Convex that you expect some environment variables to be set for your deployment and that they take a particular type, and Convex enforces it in your editor, at push time, and on any later changes to those variables.
I love this because it feels very Convex-y doesn't it? Everything in Convex is just code, like your schema and your generated API, so it feels natural that the missing piece of state, the environment variables, gets the same treatment.
This is also obviously great for agents, for the same reason agents love Convex schemas and generated APIs: they get immediate context on what they can expect to be there at runtime and fast feedback when they get something wrong.
By the way, if you do still want to use process.env then go ahead, it ain't going anywhere, this new typed env stuff isn't a breaking change.
Until next time, cheerio!
Build in minutes, scale forever.
Convex is the backend platform with everything you need to build your full-stack AI project. Cloud functions, a database, file storage, scheduling, workflow, vector search, and realtime updates fit together seamlessly.