Persisting Environment Variables Across Sessions with Claude Code Hooks: A Complete Guide

Use the CLAUDE_ENV_FILE environment variable in your Claude Code hooks to append export statements, making environment variables available for the entire session duration.

Claude Code hooks enable custom automation that runs on specific lifecycle events, and persisting environment variables across these events is a common requirement for maintaining consistent tool configurations. According to the luongnv89/claude-howto repository, you can achieve persistent session variables by writing to a special temporary file path provided via the CLAUDE_ENV_FILE environment variable. This approach works across SessionStart, CwdChanged, and FileChanged hook events, ensuring your variables remain available to all subsequent hooks and tool invocations.

How CLAUDE_ENV_FILE Works

Claude Code injects the CLAUDE_ENV_FILE variable during specific hook events, containing the absolute path to a temporary session file. When your hook scripts append export VAR=value lines to this file, Claude automatically sources it before executing any subsequent hooks, effectively injecting those variables into the session environment.

This mechanism is available during three distinct lifecycle events:

Hook Event When It Fires Variable Availability
SessionStart Initial session creation or resume CLAUDE_ENV_FILE contains path to session temp file
CwdChanged User changes working directory (cd) Same temp file persists across directory changes
FileChanged Watched file modification detected Temp file remains available for updates

The source documentation in 06-hooks/README.md (lines 314-319) demonstrates this pattern with a minimal example appending export statements, while the environment variable table (line 488) confirms availability across these three event types.

Creating a SessionStart Hook to Persist Variables

To persist an environment variable when Claude Code initializes, create a command hook that writes to CLAUDE_ENV_FILE during the SessionStart event.

  1. Create the hook script (e.g., .claude/hooks/session-init.sh):
#!/usr/bin/env bash

# Persist NODE_ENV for the entire Claude Code session

if [ -n "$CLAUDE_ENV_FILE" ]; then
  echo 'export NODE_ENV=development' >> "$CLAUDE_ENV_FILE"
fi
exit 0
  1. Set execution permissions:
chmod +x .claude/hooks/session-init.sh
  1. Register the hook in your settings configuration (~/.claude/settings.json or project-level .claude/settings.json):
{
  "hooks": {
    "SessionStart": [
      {
        "matcher": "startup",
        "hooks": [
          {
            "type": "command",
            "command": "/full/path/to/.claude/hooks/session-init.sh"
          }
        ]
      }
    ]
  }
}

When the session starts or resumes, Claude executes your script, appends the export statement to the temporary file, and sources it globally. All subsequent hooks, tools, and subprocesses then see NODE_ENV=development in their environment.

Handling Directory and File Changes

The CLAUDE_ENV_FILE mechanism extends beyond session initialization to support dynamic variable updates based on workflow context.

CwdChanged Hooks for Directory-Specific Variables

When navigating between projects, automatically export variables based on the current directory:

#!/usr/bin/env bash
if [ -n "$CLAUDE_ENV_FILE" ]; then
  PROJECT=$(basename "$PWD")
  echo "export PROJECT_NAME=$PROJECT" >> "$CLAUDE_ENV_FILE"
  
  # Export project-specific API endpoints

  if [ "$PROJECT" = "backend-api" ]; then
    echo 'export API_URL=http://localhost:3000' >> "$CLAUDE_ENV_FILE"
  fi
fi
exit 0

Configure this in the CwdChanged hook array within your settings.json using the same JSON structure as SessionStart hooks.

FileChanged Hooks for Dynamic Configuration

Monitor configuration files (such as .env files) and refresh environment variables when changes occur. Since CLAUDE_ENV_FILE persists across the session, your FileChanged hook can overwrite or append new values as the underlying configuration evolves.

Best Practices for Persistent Environment Variables

Follow these guidelines to ensure secure and reliable environment variable persistence:

Practice Implementation Details
Scope variables minimally Only export variables required for the current session to reduce accidental leakage
Avoid secret persistence Never write raw API keys or passwords to CLAUDE_ENV_FILE; the temporary file resides on disk for the session duration
Ensure idempotency Use conditional checks to prevent duplicate export lines when sessions resume or hooks rerun
Optimize execution speed Keep hook scripts small and fast; they run synchronously and block the user workflow
Version control your hooks Store scripts in .claude/hooks/ within your repository so teammates share identical environment setups

For idempotent appends, consider checking existing values before writing:

#!/usr/bin/env bash
if [ -n "$CLAUDE_ENV_FILE" ] && ! grep -q "NODE_ENV=" "$CLAUDE_ENV_FILE"; then
  echo 'export NODE_ENV=development' >> "$CLAUDE_ENV_FILE"
fi
exit 0

Summary

  • CLAUDE_ENV_FILE provides a temporary file path for persisting environment variables across Claude Code sessions
  • Append export VAR=value lines to this file in SessionStart, CwdChanged, or FileChanged hooks
  • Claude automatically sources the file before subsequent hook execution, making variables globally available
  • Store hook scripts in version-controlled directories like .claude/hooks/ for team consistency
  • Never persist sensitive secrets to this file, as it remains on disk for the session duration

Frequently Asked Questions

What is the CLAUDE_ENV_FILE variable in Claude Code?

CLAUDE_ENV_FILE is an environment variable containing the absolute path to a temporary file created by Claude Code during specific hook events. When your hook scripts write export statements to this file, Claude sources it automatically before running subsequent hooks, making those variables available to the entire session. This file persists for the duration of the Claude Code session, including across directory changes and file watches.

Can I use CLAUDE_ENV_FILE in PreTool or PostTool hooks?

No, CLAUDE_ENV_FILE is only available during SessionStart, CwdChanged, and FileChanged events according to the source documentation in 06-hooks/README.md. PreTool and PostTool hooks execute in a different context and do not have access to this persistence mechanism. For tool-specific environment variables, consider using SessionStart to set variables that tools will inherit.

How do I prevent duplicate environment variables when resuming a session?

Make your hook scripts idempotent by checking if the variable already exists in CLAUDE_ENV_FILE before appending. Use grep to test for existing export lines, or clear the file at the start of your SessionStart hook if you want to reset the environment completely. Since SessionStart fires on both initial creation and session resume, idempotent guards prevent duplicate entries that could cause shell parsing issues.

Where should I store my Claude Code hook scripts?

Store hook scripts in a .claude/hooks/ directory within your project repository or in ~/.claude/hooks/ for user-global configuration. The luongnv89/claude-howto repository examples show scripts stored in the dedicated hooks directory with executable permissions set via chmod +x. Reference the absolute path in your settings.json hook configuration to ensure Claude can locate and execute them reliably across different working directories.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →