Skip to content
masterclassBuddyTech Buzz5 fresh blogs · 5:00 AM IST

Technology handbook

T3 environment

Validated, type-safe environment variables split cleanly between server and client.

Topics
18
Sections
3

Defining the schema

createEnv

Declare server and client variables with their schemas in one place.

  • One createEnv call returns the object the whole application imports.
  • Server and client keys are declared in separate blocks of the same call.
  • Validation runs once at module load, so a bad value stops the process early.

Server variables

Keep secrets in a group the client bundle cannot import.

  • Server keys stay out of the client bundle and carry no public prefix.
  • Importing one from a client component is a build error, not undefined at runtime.
  • Database URLs, API secrets and signing keys belong in this group.

Client variables

Expose only values that are safe to publish, with the required prefix.

  • Every client key must start with the framework's public prefix.
  • The prefix is what tells the bundler the value may be inlined.
  • Assume anything declared here is readable by any visitor to the site.

Shared variables

Declare values both sides legitimately need, such as NODE_ENV.

  • A shared key validates once and is available to both halves of the app.
  • The runtime mode and a public application name are the usual members.
  • A value needing a secret half and a public half is two variables, not one.

runtimeEnv mapping

Map each key explicitly so bundler inlining works.

  • List each key against its literal process.env reference explicitly.
  • Bundlers only inline a literal property access, never a computed lookup.
  • A key missing from the map passes in development and fails in the build.

Type inference

Consume validated values with types derived from the schema.

  • The returned object is typed from the schemas, so keys autocomplete.
  • A renamed variable surfaces as a type error at every place that reads it.
  • Consumers read the validated object instead of reaching for process.env.

Validation rules

Required versus optional

Fail fast on a missing requirement instead of defaulting silently.

  • A required key with no value aborts startup with its name in the message.
  • Mark a key optional only when the code has a real path for its absence.
  • An empty string counts as present, so reject it in the schema if it is not valid.

Defaults

Supply a default only where one is genuinely safe.

  • A default hides a misconfiguration, so keep them to development conveniences.
  • Never default a credential, an endpoint or anything environment-specific.
  • A default port or log level is safe because being wrong is immediately visible.

Format validation

Constrain a URL, port or enum rather than accepting any string.

  • Parse a URL as a URL so a typo fails at boot rather than at first request.
  • Constrain a mode or a region to an enum of the values the code actually handles.
  • Bound a port or a timeout to a numeric range instead of accepting any integer.

Transformations

Coerce a string into a number or boolean at the boundary.

  • Every environment value arrives as a string and needs coercion before use.
  • Coerce once at the boundary so no call site parses the same value again.
  • Map the literal strings true and false rather than trusting a truthiness check.

Cross-field refinement

Require one variable only when another has a particular value.

  • A refinement can require a second key only when the first has a given value.
  • Express rules such as: if email sending is enabled, the API key is required.
  • Refinements run after each field parses, so a message can name both keys.

Error messages

Report which variable is wrong and what was expected.

  • Report every invalid key in one pass instead of stopping at the first.
  • Name the variable and the expected shape so the fix needs no source reading.
  • Keep the offending value out of the message, because it may be a secret.

Build & deployment

Skipping validation

Bypass checks for a container build that has no secrets, deliberately.

  • A skip flag lets a container image build without production secrets present.
  • Skipping belongs to the build step only; the running process still validates.
  • Leaving the flag on in a deploy turns a startup failure into a runtime one.

Framework presets

Use the preset matching Next.js, Nuxt, Astro or another target.

  • A preset supplies the public prefix and runtime mapping a framework expects.
  • The Next.js preset knows its public prefix and wires the runtime map for you.
  • Without a preset the prefix rule has to be restated by hand in every project.

Monorepo usage

Share one environment definition across packages.

  • Define the environment once in a package that every app imports.
  • Each app extends the shared definition with the keys only it needs.
  • One definition keeps two services from drifting on the meaning of a key name.

CI configuration

Provide the variables a build needs without leaking them to logs.

  • Inject values as masked secrets rather than as a committed file.
  • Printing the environment in a debug step leaks every secret into the log.
  • Give the build only the keys it compiles with; runtime keys can stay out.

Per-environment values

Keep development, preview and production configuration separate.

  • Development, preview and production each supply their own values for one schema.
  • Preview deployments should point at throwaway data, never at production stores.
  • Sharing the schema means a newly added key is remembered in every environment.

Secret rotation

Change a secret without a deploy that briefly has neither value.

  • Accept both the old and the new secret during the overlap window.
  • A public value is inlined at build time, so rotating one requires a rebuild.
  • Remove the retired value only after every instance has restarted on the new one.

Sources

  • T3 environment official documentation

Ask follow-up questions on any topic in your dashboard.

Start learning