How to stop Claude Code from editing .env files and lockfiles

Claude Code is eager to make an error go away. In a Next.js project, that eagerness sometimes aims at files nobody should be hand-editing. A hook that runs before every edit can refuse those writes and tell Claude what to do instead.

The files worth protecting

Five groups cause the most avoidable damage when an assistant edits them directly:

Why a hook and not a CLAUDE.md rule

A line in CLAUDE.md saying "never edit .env" is advice. A PreToolUse hook is enforcement: Claude Code passes the pending tool call to your script as JSON, and a script that exits with code 2 blocks the call and feeds its message back to Claude.

The useful part is the message. A bare refusal leaves Claude to improvise. A good block message names the rule and the alternative:

A minimal shape for the hook

The hook only needs built-in Node modules. It reads the tool input, checks the target path, and exits 2 with a message on a match:

// .claude/hooks/protect-files.mjs (sketch)
import { readFileSync } from "node:fs";

const input = JSON.parse(readFileSync(0, "utf8"));
const file = input.tool_input?.file_path ?? "";

if (/(^|\/)\.env(\..+)?$/.test(file) && !file.endsWith(".env.example")) {
  console.error("protect-files: .env files hold secrets. Add the name to .env.example and ask the user for the value.");
  process.exit(2);
}

Register it in .claude/settings.json under PreToolUse, matched to the edit and write tools, and point the command at $CLAUDE_PROJECT_DIR so it resolves from any working directory inside the project.

Check that it works

Hooks are read when a session starts, so restart Claude Code after adding one. Then run /hooks to confirm it is listed, and do a live test: ask Claude to "add API_KEY=test to .env.local". You should see a block message from the hook rather than an edit.

If the hook does not appear or never fires, the cause is usually the settings location or a stale session, not the script.

Tune it to your project

Block lists are project-specific. If you keep generated code in a folder such as out/ that you do want Claude to edit, remove it from the list. Every time you change a rule, re-run whatever test covers the hook so you know what else changed.

What this does not do

A path check is a guardrail for common mistakes, not a security boundary. It will not stop a Bash command that writes to a protected file (cover that separately with a command guard), and it does not replace code review, tests, or CI. Keep Claude Code's permission prompts on.

Going further

If you would rather start from a tested set than write and maintain these scripts yourself, the Next.js Claude Code workflow pack bundles this protection with four other hooks, a CLAUDE.md template and self-tests.

This article was written with AI assistance.