Skip to content

Astro

While Astro has astro:env to help with environment variables, we think Varlock has more to offer:

  • Your .env.schema is not tied to JavaScript, and is a better place to store this schema info versus your astro.config.* file
  • Facilitates loading and composing multiple .env files
  • You can use validated env vars right away within your astro.config.* file
  • Facilitates setting values and handling multiple environments, not just setting defaults
  • More data types and options available
  • Leak detection, log redaction, and more security guardrails

To integrate varlock into an Astro application, you must use our @varlock/astro-integration package, which is an Astro integration.

  1. Install varlock and the Astro integration package

    Terminal window
    npm install @varlock/astro-integration varlock
  2. Run varlock init to set up your .env.schema file

    This will guide you through setting up your .env.schema file, based on your existing .env file(s). Make sure to review it carefully.

    Terminal window
    npm exec -- varlock init
  3. Enable the Astro integration

    You must add our varlockAstroIntegration to your astro.config.* file:

    astro.config.ts
    import { defineConfig } from 'astro/config';
    import varlockAstroIntegration from '@varlock/astro-integration';
    export default defineConfig({
    integrations: [varlockAstroIntegration(), otherIntegration()],
    });

You can continue to use import.meta.env.SOMEVAR as usual, but we recommend using varlock’s imported ENV object for better type-safety and improved developer experience:

example.ts
import { ENV } from 'varlock/env';
console.log(import.meta.env.SOMEVAR); // 🆗 still works
console.log(ENV.SOMEVAR); // ✨ recommended
  • Non-string values (e.g., number, boolean) are properly typed and coerced
  • All non-sensitive items are replaced at build time (not just VITE_ prefixed ones)
  • Better error messages for invalid or unavailable keys
  • Enables future DX improvements and tighter control over what is bundled

It’s often useful to be able to access env vars in your Astro config. Without varlock, it’s a bit awkward, but varlock makes it dead simple - in fact it’s already available! Just import varlock’s ENV object and reference env vars via ENV.SOME_ITEM like you do everywhere else.

astro.config.ts
import { defineConfig } from 'astro/config';
import varlockAstroIntegration from '@varlock/astro-integration';
import { ENV } from 'varlock/env';
doSomethingWithEnvVar(ENV.FOO);
export default defineConfig({ /* ... */ });

Even in a static front-end project, you may have other scripts in your project that rely on sensitive config.

You can use varlock run to inject resolved config into other scripts as regular env vars.

Terminal window
npm exec -- varlock run -- node ./script.js

To enable type-safety and IntelliSense for your env vars, enable the @generateTypes root decorator in your .env.schema. Note that if your schema was created using varlock init, it will include this by default.

.env.schema
# @generateTypes(lang='ts', path='env.d.ts')
# ---
# your config items...

Varlock can load multiple environment-specific .env files (e.g., .env.development, .env.preview, .env.production).

By default, Astro relies on Vite’s MODE flag to determine which env file(s) to load.

With varlock, instead you set your own environment flag using the @envFlag root decorator, e.g. APP_ENV. See the environments guide for more information.

Astro uses the PUBLIC_ prefix to determine which env vars are public (bundled for the browser). Varlock decouples the concept of being sensitive from key names, and instead you control this with the @defaultSensitive root decorator and the @sensitive item decorator. See the secrets guide for more information.

Set a default and explicitly mark items:

.env.schema
# @defaultSensitive=false
# ---
NON_SECRET_FOO= # sensitive by default
# @sensitive
SECRET_FOO=

Or if you’d like to continue using Astro’s prefix behavior:

.env.schema
# @defaultSensitive=inferFromPrefix('PUBLIC_')
# ---
FOO= # sensitive
PUBLIC_FOO= # non-sensitive, due to prefix

This integration will automatically inject a new middleware that scans outgoing http responses for any sensitive values.