#[EnvInvalidVariables] [astro-env-plugin] The following environment variables defined in `env.schema`
16 messages · Page 1 of 1 (latest)
Yes, Astro provides a way to handle your use case: you can delay the validation of secret (private) environment variables to runtime, but public variables are always validated at build/start time.
Secret (private) variables
By default, secret server variables (those with access: "secret") are only validated at runtime, not at build time. You can control this behavior with the validateSecrets option in your astro.config.mjs. If you leave validateSecrets as false (the default), secret variables will not be required at build time—they will only be checked when your app runs, which is what you want for runtime-only secrets in Docker or similar environments:
import { defineConfig, envField } from "astro/config";
export default defineConfig({
env: {
schema: {
DATABASE_URL: envField.string({ context: "server", access: "secret" }),
// ...other variables
},
// validateSecrets: false // This is the default
}
});
Type safe environment variables
Variable types
env.validateSecrets
Public variables
However, public variables (those with access: "public") are always validated at build/start time. This means you must provide them during the build, or Astro will throw an error. There is currently no built-in way to delay validation of public variables to runtime. This is by design, as public variables are intended to be statically embedded in your client/server bundles.
If you want to avoid baking sensitive data into your image, make sure only non-sensitive values are marked as public. For sensitive values, use access: "secret" and context: "server".
Workarounds for public variables
If you must have public variables set only at runtime, you can:
- Make them optional in your schema (using
optional: true), and handle the absence of these variables in your code. - Or, provide placeholder values at build time (e.g.,
PUBLIC_APP_NAME=placeholder pnpm run build), and then set the real values at runtime. Astro will use the runtime values if they are present, but the placeholder will be embedded in the build output for client-side code.
See the Node adapter standalone mode docs for a workflow where you provide placeholder values at build time and real values at runtime.
If an
.envfile containing environment variables is present when the build process is run, these values will be hard-coded in the output, just as when generating a static website.
During the build, the runtime variables must be absent from the.envfile, and you must provide Astro with every environment variable to expect at run-time:VARIABLE_1=placeholder astro build. This signals to Astro that the actual value will be available when the built application is run. The placeholder value will be ignored by the build process, and Astro will use the value provided at run-time.
Node adapter: Runtime environment variables
Summary
- Secret variables: You can delay validation to runtime (default behavior).
- Public variables: Must be present at build time, or marked as optional.
- No built-in way to delay public variable validation to runtime.
If you need true runtime-only public variables, you may need to reconsider your architecture or use only server-side variables for sensitive data.
If you have further questions or need a specific workaround, let me know!
Note: you can ask me a follow up question by @ mentioning me again :speech_balloon:
@untold arch Kapa.ai is still learning and improving, please let me know how I did by reacting below.
Let me check the knowledge base for you again. One moment! :books:
You are correct in your understanding: public environment variables (like PUBLIC_APP_NAME, PUBLIC_APP_URL, and BETTER_AUTH_URL in your schema) are always validated and embedded at build time. This means their values will be baked into your final Docker image and available in client-side code. There is currently no built-in way in Astro to delay or skip validation of public variables to runtime—this is by design for security and static optimization reasons. Only secret server variables (access: "secret", context: "server") can be delayed to runtime validation, and you have already set validateSecrets: true for stricter checking, which is fine for secrets but does not affect public variables see docs.
Workarounds:
- Placeholders at build time: You can provide placeholder values for public variables during the build (e.g.,
PUBLIC_APP_URL=placeholder pnpm run build). At runtime, you can override these with real values via Docker Compose, but for client-side code, the value embedded at build time will be used, not the runtime value see Node adapter docs. - Mark as optional: If you mark public variables as
optional: truein your schema, you can build without them, but your client-side code must handle the case where they are missing. This does not solve the embedding issue, but it allows the build to proceed without values.
Summary:
- Public variables: Always embedded at build time; cannot be delayed to runtime.
- Secret variables: Can be provided at runtime and are not embedded in the client bundle.
If you need to keep certain values out of the image for security, ensure they are only used as secret server variables. For anything that must be available on the client, Astro will always embed the value at build time see docs.
I'm sorry, but there is no clean way in Astro to achieve runtime-only public environment variables for client-side code. This is a current limitation of Astro’s environment variable handling.
Note: you can ask me a follow up question by @ mentioning me again :speech_balloon:
@untold arch Kapa.ai is still learning and improving, please let me know how I did by reacting below.
Let me check the knowledge base for you again. One moment! :books:
Based on the official Astro documentation, public environment variables (those with access: "public") must be provided at build time and will be embedded in your client bundle. There is no supported way to delay their injection to runtime. For secret server variables (access: "secret", context: "server"), you can provide them at runtime via Docker Compose or .env files, and they will not be embedded in the client bundle see docs.
Refactored Dockerfile
Below is a multi-stage Dockerfile that follows best practices from the Astro documentation. It uses placeholder values for public variables at build time (which will be embedded in the client bundle), and expects secret variables to be provided at runtime.
# Dockerfile
FROM node:20-alpine AS base
WORKDIR /app
# Disable Astro telemetry
ENV ASTRO_TELEMETRY_DISABLED=1
# Install PNPM
ENV PNPM_HOME="/pnpm"
ENV PATH="$PNPM_HOME:$PATH"
RUN corepack enable
# Copy only package files first for better caching
COPY package.json pnpm-lock.yaml ./
FROM base AS prod-deps
RUN --mount=type=cache,id=pnpm,target=/pnpm/store pnpm install --prod --frozen-lockfile --ignore-scripts
FROM base AS build-deps
RUN --mount=type=cache,id=pnpm,target=/pnpm/store pnpm install --frozen-lockfile --ignore-scripts
FROM build-deps AS build
COPY . .
# Provide placeholder values for public variables at build time
ENV PUBLIC_APP_NAME=placeholder
ENV PUBLIC_APP_URL=placeholder
ENV BETTER_AUTH_URL=placeholder
RUN pnpm run build
FROM base AS runtime
COPY --from=prod-deps /app/node_modules ./node_modules
COPY --from=build /app/dist ./dist
ENV HOST=0.0.0.0
ENV PORT=4321
EXPOSE 4321
CMD ["pnpm", "preview", "--host"]
Refactored docker-compose.yml
Your Docker Compose file should provide secret variables (and can override public ones, but only server-side code will see the runtime values):
services:
ksiniin:
build:
context: .
ports:
- '4321:4321'
env_file:
- .env
environment:
- ASTRO_TELEMETRY_DISABLED=1
# Optionally override public variables for server-side code
# - PUBLIC_APP_NAME=MyApp
# - PUBLIC_APP_URL=<https://example.com>
# - BETTER_AUTH_URL=<https://auth.example.com>
# Provide secret variables at runtime
- DATABASE_URL=${DATABASE_URL}
- BETTER_AUTH_SECRET=${BETTER_AUTH_SECRET}
networks:
- app-network
restart: unless-stopped
.env (example for runtime secrets, not included in the image):
DATABASE_URL=your_real_database_url
BETTER_AUTH_SECRET=your_real_secret
Key points:
- Public variables must be set at build time and will be embedded in the client bundle.
- Secret variables can be set at runtime and will not be exposed to the client.
- There is no way to delay public variable injection to runtime in Astro see docs.
If you need to keep values out of the image, ensure they are only used as secret server variables.
Note: you can ask me a follow up question by @ mentioning me again :speech_balloon:
@untold arch Kapa.ai is still learning and improving, please let me know how I did by reacting below.
Let me check the knowledge base for you again. One moment! :books:
Your error occurs because Astro requires all environment variables defined in env.schema to be present at build time, even for secret variables, when you set validateSecrets: true in your config. According to the documentation:
By default, only public variables are validated on the server when starting the dev server or a build, and private variables are validated at runtime only. If enabled, private variables will also be checked on start. This is useful in some continuous integration (CI) pipelines to make sure all your secrets are correctly set before deploying.
export default defineConfig({ env: { schema: { /* ... */ }, validateSecrets: true } })
Because you have validateSecrets: true, Astro will require DATABASE_URL and BETTER_AUTH_SECRET to be set at build time. If you want to skip this check at build time and only validate secrets at runtime, you must set validateSecrets: false (or remove it, since false is the default):
env: {
schema: {
PUBLIC_APP_NAME: envField.string({ context: 'client', access: 'public' }),
PUBLIC_APP_URL: envField.string({ context: 'client', access: 'public' }),
DATABASE_URL: envField.string({ context: 'server', access: 'secret' }),
BETTER_AUTH_SECRET: envField.string({ context: 'server', access: 'secret' }),
BETTER_AUTH_URL: envField.string({ context: 'client', access: 'public' })
}
// validateSecrets: false // default, can be omitted
}
Summary of what to do:
- Remove
validateSecrets: truefrom yourastro.config.mjsto allow secret variables to be provided only at runtime. - Public variables must still be provided at build time.
This matches the documented behavior:
By default, secrets are only validated at runtime. You can enable validating private variables on start by configuring
validateSecrets: trueVariable types.
If you need to validate secrets at runtime only, do not enable validateSecrets: true.
If you need public variables to be runtime-only, that is not possible in Astro as per the documentation.