Skip to content

Batch Operations

Your team is migrating from moment.js to date-fns. There are 147 files importing moment, each using a different subset of the API. A find-and-replace will not work because moment().format('YYYY-MM-DD') becomes format(new Date(), 'yyyy-MM-dd') — the API surface is completely different. Doing this manually takes a week. With the right batch operation pattern, it takes an afternoon.

  • Subagent-based parallel processing for multi-file changes
  • The plan-then-execute pattern for safe large-scale modifications
  • Headless batch scripts for codemod-style operations
  • Verification strategies that catch errors before they hit production

Never let Claude make 50 file changes without reviewing the plan first.

  1. Scope the change

    Find all files that import from 'moment'. List each file, the specific moment functions used,
    and the equivalent date-fns function. Output as a table. Do not make any changes yet.
  2. Review the plan Claude shows you a table of every file, every import, and the planned replacement. Review for edge cases.

  3. Execute in batches

    Good. Now migrate the files in src/utils/ first (there are 8 of them).
    After each file, run the tests in that directory to verify.
  4. Verify and continue

    All tests pass. Continue with src/components/ (23 files). Same approach:
    migrate, test, report any failures.

For large codebases, delegate batch work to subagents so each file group gets its own context window:

Migrate the moment.js imports to date-fns across the entire project. Use subagents to
process each directory in parallel:
1. src/utils/ (8 files) -- delegate to a subagent
2. src/components/ (23 files) -- delegate to a subagent
3. src/api/ (12 files) -- delegate to a subagent
4. src/services/ (15 files) -- delegate to a subagent
Each subagent should: migrate the imports, update the function calls, and run the
tests in that directory. Report back with: files changed, tests passed/failed.

This works because subagents have independent context windows, so they do not crowd out the main session with 50 files worth of diffs.

For repeatable operations, use print mode to build automated scripts:

#!/bin/bash
# migrate-moment.sh -- Run headless migration across directories
DIRS=("src/utils" "src/components" "src/api" "src/services")
for dir in "${DIRS[@]}"; do
echo "Migrating $dir..."
claude -p "Migrate all moment.js imports in $dir/ to date-fns. \
Update function calls to match the date-fns API. \
After migration, run: npx jest $dir/ --no-coverage" \
--max-turns 20 \
--dangerously-skip-permissions \
--output-format json > "results/$dir.json" 2>&1
echo "Completed $dir"
done
echo "Migration complete. Review results in results/"
We are deprecating /api/v1/ and all clients have been migrated to /api/v2/.
Remove all v1 route handlers, their tests, and any middleware specific to v1.
Keep shared middleware that both versions use.
Process:
1. List all files in src/api/v1/
2. For each v1 route, verify a v2 equivalent exists
3. Remove v1 files and their tests
4. Remove v1 entries from the router configuration
5. Run the full test suite to verify nothing breaks
Rename the UserService class to AccountService across the entire codebase.
This includes:
- The class definition and file name
- All imports referencing UserService
- All variable names that use userService or UserService
- Test files and test descriptions
- CLAUDE.md and documentation references
Use git mv for file renames so git tracks the history.
Run the full test suite and TypeScript compiler after all changes.
Every API route in src/api/routes/ needs to have:
1. An OpenAPI JSDoc comment block above the handler
2. Input validation using the Zod schema pattern from src/api/routes/orders.ts
3. Error handling wrapped in the asyncHandler utility
Process: Read src/api/routes/orders.ts as the reference implementation.
Then apply the same patterns to all other route files that are missing them.
List each file and what you added before proceeding.

Run tests after each batch of changes, not at the end:

For each directory you migrate:
1. Make the changes
2. Run: npx jest [directory] --no-coverage
3. If tests fail, fix the failures before moving to the next directory
4. Report: directory name, files changed, tests passed, tests failed
After making all changes, run: npx tsc --noEmit
If there are type errors, fix them. The TypeScript compiler is the source of truth
for whether imports and function signatures are correct.
After completing the migration:
1. Run: git diff --stat to show all changed files
2. Run: git diff to show the actual changes
3. Verify there are no unintended modifications
4. Run the full test suite
5. If everything passes, create a commit with a descriptive message

Claude modifies files it should not touch: Use constraints at the top of your prompt: “Only modify files in src/api/. Do not touch src/core/ or any configuration files.” For extra safety, use --disallowedTools "Edit(src/core/**)" to block edits to specific paths.

Batch operation runs out of context: Long batch operations fill the context window. Use subagents for parallel work, or split the operation into multiple sessions with /clear between batches.

Tests pass but behavior changes: Batch operations can introduce subtle behavior changes that tests do not catch. Always do a manual review of the git diff before committing batch changes.

Claude gets stuck in a loop: If Claude keeps fixing one file’s errors only to break another, stop the operation. The changes need a different approach — likely a plan that accounts for the dependency order between files.