StackPanel
Secrets

Variables

Define secrets, literals, and dynamic values as environment variables

Variables are the primary way to define configuration values that get exported as environment variables in your dev shell. They support plaintext values, direct secret references, and computed values.

Variable Types

TypeDescriptionResolved At
LITERALPlain text value (stored in value field)Nix eval time
ref+sops://...#/KEYDirect reference to a SOPS file and YAML keyRuntime
EXEC / computedShell or Nix produced valueRuntime / eval time

The variable scope is determined by the ID prefix. Secrets are best modeled as direct refs in value:

ID PrefixTypeStorage
/var/*Config (literal or direct secret ref)value field in Nix config
/secret/*Legacy placeholder secretTransitional only
/computed/*ComputedDerived at eval time

Defining Variables

Variables are defined under stackpanel.variables with a path-style key:

stackpanel.variables = {
  "/var/postgres-url" = {
    value = "ref+sops://.stack/secrets/dev/web.sops.yaml#/postgres_url";
  };

  "/var/log-level" = {
    value = "info";
  };

  "/computed/apps/web/port" = {
    value = "3000";
  };
};

The path prefix is metadata for the variable itself. Secret location and encryption are determined by the ref+sops://...#/KEY target and .stack/secrets/.sops.yaml rules.

Managing Variables via CLI

# Set a literal value
stackpanel vars set DATABASE_URL --value "postgresql://localhost:5432/dev"

# Set an encrypted secret
stackpanel vars set API_KEY --value "sk-abc123" --secret --keys dev,prod

# Get a value (decrypts if needed)
stackpanel vars get API_KEY

# List all variables
stackpanel vars list

# Delete a variable
stackpanel vars delete API_KEY

LITERAL Variables

The simplest type. The value is set directly in Nix config and baked into the shell at eval time:

"/dev/app-name" = {
  key = "APP_NAME";
  type = "LITERAL";
  value = "myapp";
};

Use LITERAL for values that are not sensitive and do not change between machines, such as app names, feature flags, and default URLs.

Direct SOPS References

Preferred secret usage is a direct SOPS ref. The value points at an encrypted file and YAML key.

"/var/stripe-secret-key" = {
  value = "ref+sops://.stack/secrets/prod/payments.sops.yaml#/STRIPE_SECRET_KEY";
};

At runtime, the value is resolved by decrypting the referenced SOPS file using the recipients configured in .stack/secrets/.sops.yaml.

EXEC Variables

Run a shell command to produce the value dynamically:

"/dev/git-commit" = {
  key = "GIT_COMMIT";
  type = "EXEC";
  value = "git rev-parse --short HEAD";
};

"/dev/timestamp" = {
  key = "BUILD_TIMESTAMP";
  type = "EXEC";
  value = "date -u +%Y-%m-%dT%H:%M:%SZ";
};

The command runs at shell entry time, and the output becomes the variable value.

EXEC variables run on every shell entry. Keep the commands fast and side-effect-free. Avoid commands that make network calls or modify state.

Variable Resolution Order

When you enter the dev shell, variables are resolved in this order:

  1. LITERAL values are set immediately during Nix evaluation
  2. EXEC commands run and their output is captured
  3. ref+sops://...#/KEY values are decrypted at runtime
  4. Other vals references are resolved by the agent

If a variable cannot be resolved (for example, SOPS keys are unavailable or a vals reference fails), the agent logs a warning but continues. Your shell still starts with whatever variables could be resolved.

Per-User Overrides

Variables defined in config.local.nix (gitignored) override shared variables:

# .stack/config.local.nix
{
  stackpanel.variables."/var/postgres-url".value = "ref+sops://.stack/secrets/local/web.sops.yaml#/postgres_url";
}

This lets individual developers customize connection strings and other values without affecting the team.

Reference

On this page