Claude Code Best Practices
These best practices are specifically for production codebases and team environments. Solo developer on a weekend project? Check the tips page instead — this page is about the harder problems that emerge at scale.
CLAUDE.md Architecture
A well-structured CLAUDE.md is the foundation. Every team member and every Claude session gets the same context automatically.
Production CLAUDE.md Template
# <Project Name> <One paragraph: what it is, who uses it, what problem it solves> ## Architecture - Frontend: Next.js 14, TypeScript, Tailwind - API: FastAPI (Python 3.12) - DB: PostgreSQL 16 via Alembic migrations - Auth: JWT + refresh tokens (see src/auth/) - Queue: Redis + Celery for async jobs - Infra: AWS ECS + RDS, managed by Terraform in /infra ## Services Map - `src/api/` — HTTP handlers, one file per resource - `src/services/` — business logic (no DB calls here) - `src/models/` — SQLAlchemy models + Pydantic schemas - `src/workers/` — Celery task definitions ## Dev Commands ```bash make dev # Start all services (docker-compose) make test # pytest + vitest make migrate # Run pending Alembic migrations make lint # ruff + eslint make typecheck # mypy + tsc ``` ## Critical Invariants - Service layer NEVER imports from api/ layer - All DB access goes through repositories (src/repositories/) - Celery tasks must be idempotent (they may retry) - Never store PII in Redis (only IDs) ## Code Conventions - Commit style: conventional commits (feat/fix/chore/docs) - Branch naming: <type>/<ticket>-slug (e.g. feat/PROJ-123-add-webhooks) - No comments explaining WHAT code does — only WHY - Test file co-location: src/api/users.test.ts next to users.ts ## Do Not - Never use `git push --force` without asking - Never mock the database in tests (integration tests hit real DB) - Never commit .env files - Never add console.log/print to production code - Never bypass security middleware in tests ## Danger Zones (ask before touching) - src/auth/ — any change here needs security review - infra/ — Terraform changes need team approval - Database migrations — must be backward compatible
Permission Model
Claude Code has three permission levels. Choose based on the context.
✓ Auto-approve
Read (any file), Edit (non-critical files), Glob, Grep — these are non-destructive and safe to batch.
✗ Always confirm
Bash commands, git push, database writes, file deletes, any API calls with side effects.
# In .claude/settings.json
{
"permissions": {
"autoApprove": ["Read", "Edit", "Glob", "Grep"],
"requireConfirm": ["Bash", "Write", "WebFetch"],
"deny": ["git push --force", "DROP TABLE", "rm -rf"]
}
}
CLAUDE_NO_CONFIRM=1 and narrow what Claude can do via permissions. Never give CI Claude write access to production systems.Security Guidelines
Never put in CLAUDE.md or prompts
- API keys, passwords, or secrets of any kind
- Production database connection strings
- PII (customer names, emails, IDs)
- Internal URLs or IP addresses
Secrets Management
Claude Code reads environment variables. Use a secrets manager and inject them at runtime rather than storing in any file Claude can read.
# Safe: Claude sees the variable name, not the value export STRIPE_SECRET_KEY=$(aws secretsmanager get-secret-value ...) # Unsafe: Claude can read this file echo "STRIPE_SECRET_KEY=sk_live_..." >> .env
Run /security on Every Auth Change
Make it a hard rule: any PR touching src/auth/, session handling, or data-access layer gets a /security review before merge. Add it as a CI check.
CI/CD Integration
GitHub Actions Example
name: Claude Code Review
on:
pull_request:
types: [opened, synchronize]
jobs:
ai-review:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Install Claude Code
run: npm install -g @anthropic-ai/claude-code
- name: Run AI Review
env:
ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
CLAUDE_NO_CONFIRM: "1"
run: |
git diff origin/main...HEAD | claude review --format json \
| jq -e '.findings | map(select(.severity == "critical")) | length == 0' \
|| (echo "Critical issues found" && exit 1)
- name: Post Review Comment
env:
ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
REVIEW=$(claude review --format markdown)
gh pr comment ${{ github.event.pull_request.number }} --body "$REVIEW"
Team Conventions
What to standardize in CLAUDE.md
- Commit message format (conventional commits, etc.)
- Test coverage expectations (happy path + error cases minimum)
- Which things must NEVER be done (force push, mock the DB)
- Architecture invariants (which layer can import which)
- Danger zones that need extra review
Prompt Library Pattern
Store shared prompts in .claude/prompts/ at the repo root. Document them in CLAUDE.md so the team knows they exist.
.claude/
prompts/
migration-review.md # Review DB migrations for safety
incident-runbook.md # Diagnose production incidents
release-notes.md # Generate release notes from git log
security-review.md # Security-focused review checklist
Do's and Don'ts at Scale
✓ Do
Commit before each Claude session. Review every diff. Use /dry-run for large changes. Keep CLAUDE.md updated as the codebase evolves.
✗ Don't
Approve diffs you don't understand. Let Claude push to main directly. Give Claude access to production secrets. Use Claude to bypass code review.
Frequently Asked Questions
Should every developer on the team have their own API key?
Yes. Each developer should use their own Anthropic API key set as ANTHROPIC_API_KEY in their shell environment. This keeps costs attributable, lets individuals set usage limits, and prevents a single key rotation from breaking everyone's workflow. For CI/CD, use a separate team API key stored as a secret.
How do I prevent Claude Code from making unwanted changes?
Three layers of protection: (1) Claude Code asks for permission before file writes and shell commands by default — just say no. (2) Set permissions.requireConfirm: ["Bash", "Write"] in settings to always prompt for destructive operations. (3) Review every diff before accepting. Claude Code never pushes to git automatically unless you run claude /commit yourself.
What should go in CLAUDE.md vs a system prompt?
Put stable, project-wide conventions in CLAUDE.md (tech stack, commands, naming rules, architecture decisions). CLAUDE.md is committed to git and applies to everyone. Use claude --system "..." or inline prompts for session-specific instructions that don't belong in the shared project context.
How do I use Claude Code in GitHub Actions for automated reviews?
Add a workflow step that runs claude /review on the changed files. Store your API key as a GitHub Actions secret (ANTHROPIC_API_KEY). Claude Code runs headless in CI with CLAUDE_NO_CONFIRM=1 to skip interactive prompts. See our GitHub integration guide for complete workflow examples.
Is Claude Code safe to use on a production codebase?
Yes, with the right setup. Never give Claude direct access to production secrets or databases. Use it for code editing, review, and commit message generation — not for running migrations or deploying. The permission model (confirm before Bash, confirm before writes) keeps it safe as long as you review each action before approving.