Live Vanta integration is live
Tutorials
ENV validation

Validate your .env files with Ghostable

Step-by-step tutorial for setting up Ghostable schema validation, adding framework-specific rules, and wiring checks into deploys.

Ghostable's validation keeps bad environment variables out of your deployments without ever uploading plaintext values or schema details. In this tutorial you'll define validation rules, run them locally, wire them into CI, and learn patterns that keep Laravel, Node/Next.js, Rails, and Django apps from shipping broken config.

What you'll build

  • A project-level schema in .ghostable/schema.yaml with sensible defaults.
  • Environment overrides (e.g., production-only rules) in .ghostable/schemas/<env>.yaml.
  • A repeatable command: ghostable env validate --env <env> that fails fast when config drifts.
  • A CI job that blocks merges/deploys when validation fails.

Prerequisites

  • Ghostable CLI installed and authenticated (ghostable login --token $GHOSTABLE_TOKEN).
  • A project initialized with .ghostable/ghostable.yaml so the CLI knows which project/environment to target.
  • Local .env files for the environments you want to validate.
  • Node.js available if you're running the CLI in CI (see GitHub Actions example below).

1. Define your validation schema

All validation lives locally inside .ghostable (see the validation docs). Start with a global schema file and add per-environment overrides only when needed.

.ghostable/
  ghostable.yaml
  schema.yaml           # global rules
  schemas/
    production.yaml     # env-specific overrides
    staging.yaml

Create .ghostable/schema.yaml with baseline rules that apply everywhere:

APP_NAME:
  - required
  - string
  - max:64

APP_ENV:
  - required
  - in:local,staging,production

APP_DEBUG:
  - required
  - boolean

APP_URL:
  - required
  - url

LOG_CHANNEL:
  - required
  - in:stack,stdout

Add overrides for stricter environments (e.g., production):

# .ghostable/schemas/production.yaml
APP_DEBUG:
  - required
  - boolean
  - in:false

APP_KEY:
  - required
  - starts_with:base64:
  - min:44

QUEUE_CONNECTION:
  - required
  - in:redis,sqs

Ghostable merges the global schema with the matching override file before validating your .env.

2. Add rules for your framework

Here are practical rule sets you can drop into schema.yaml. Tweak names and allowed values to match your stack.

Laravel

APP_KEY:
  - required
  - starts_with:base64:
  - min:44

SESSION_DRIVER:
  - required
  - in:file,database,redis

CACHE_DRIVER:
  - required
  - in:file,redis,memcached,dynamodb

MAIL_MAILER:
  - required
  - in:smtp,log,mailgun,postmark,sendmail

DB_CONNECTION:
  - required
  - in:mysql,pgsql,sqlsrv,sqlite

Next.js / Node

NODE_ENV:
  - required
  - in:development,staging,production

NEXT_PUBLIC_API_URL:
  - required
  - url

DATABASE_URL:
  - required
  - regex:^postgres://

JWT_SECRET:
  - required
  - min:32
  - starts_with:sk_

Django / Rails

SECRET_KEY:
  - required
  - min:50

DJANGO_SETTINGS_MODULE:
  - required
  - ends_with:.settings

RAILS_ENV:
  - required
  - in:development,test,production

DATABASE_URL:
  - required
  - regex:^postgres://

ALLOWED_HOSTS:
  - required
  - string

Prefer in: for controlled enums, starts_with/regex for keys and URLs, and required everywhere you expect the app to boot.

3. Validate locally before merging

Run validation against any environment. The CLI loads schema.yaml, merges the matching override, and compares against your resolved .env (you can pass --file for non-standard names).

ghostable env validate --env production
# or validate a custom file:
ghostable env validate --env staging --file .env.staging

Failures are human-readable and the command exits non-zero:

X APP_KEY must start with "base64:"
X APP_DEBUG must be "false"
! QUEUE_CONNECTION is set to sync (recommended: redis)

Fix values locally, rerun, and only push or deploy once validation passes.

4. Gate deploys in CI/CD

Because validation happens locally (zero-knowledge), it fits neatly into your pipeline. Here is a GitHub Actions job that blocks merges when validation fails:

name: Validate env

on:
  pull_request:
  workflow_dispatch:

jobs:
  validate-env:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: 20
      - run: npm install @ghostable/cli@latest
      - name: Validate production schema
        env:
          GHOSTABLE_TOKEN: ${{ secrets.GHOSTABLE_TOKEN }}
        run: |
          ghostable login --token "$GHOSTABLE_TOKEN"
          ghostable env validate --env production

Apply the same pattern to deploy jobs so release pipelines fail fast when config drifts.

What not to do

  • Don't copy real secrets into schema files or checked-in .env examples - keep schemas as contracts, not storage.
  • Don't treat warnings as optional in production. Tighten in: lists or add overrides so prod rules are explicit.
  • Don't skip validation for "small" changes. A single mistyped queue driver or URL can break deploys.
  • Don't maintain divergent schemas per developer. Keep one shared .ghostable folder in version control.

Why validation protects deploys

  • Prevents broken releases: schema violations fail pipelines before code hits servers.
  • Codifies expectations: rules document required keys and safe values across every environment.
  • Stops config drift: pairing validation with ghostable env push|pull keeps remote and local envs aligned.
  • Safer rotations: regex and starts_with checks catch half-rotated keys or wrong providers.

Next steps

  • Expand schemas with optional keys marked nullable to reduce noise while staying explicit.
  • Add staging/preview overrides that mirror production (minus the strictest checks) to surface drift earlier.
  • Continue with the validation deep-dive for full rule syntax and tips.

Want product news and updates?

Sign up for our newsletter.

Email Address

We care about your data. Read our privacy policy.