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.
- 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
- Set execution permissions:
chmod +x .claude/hooks/session-init.sh
- Register the hook in your settings configuration (
~/.claude/settings.jsonor 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=valuelines 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:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →