Advanced Code Editing
Master complex code manipulation, refactoring, and editing techniques using Gemini CLI's advanced features.
What Makes Editing 'Advanced'?
Basic editing is asking Gemini CLI to fix a single function or rename a variable. Advanced editing is coordinating changes across multiple files, migrating an entire codebase from one technology to another, or applying a systematic refactoring that would take hours to do manually.
Three capabilities make these large-scale edits practical with Gemini CLI:
- Multi-file context — Pass several files as arguments and Gemini CLI reasons across all of them simultaneously, keeping cross-file references, imports, and interfaces consistent.
- Plan Mode — Ask Gemini CLI to describe every change it will make before it makes any of them. Review the plan, modify it if needed, then execute.
- Shell scripting integration — Combine Gemini CLI with standard Unix tools to apply changes to hundreds of files in parallel, with automatic rollback on failure.
Multi-File Editing
Many edits cannot be made file by file because the changes are interdependent. Renaming an interface, changing a function signature, or restructuring a module all require updating callers, importers, and type definitions simultaneously. Gemini CLI handles this when you pass all affected files as arguments.
Rename a type across multiple files
Before: UserProfile interface defined in types.ts and used in three components.
# Pass all files that reference the type
gemini 'Rename the UserProfile interface to Profile across all these files. Update all import statements and type annotations.' \
src/types.ts src/components/Header.tsx src/components/Sidebar.tsx src/pages/profile.tsx
Before (types.ts)
- export interface UserProfile {
id: string
name: string
- }
After (types.ts)
+ export interface Profile {
id: string
name: string
+ }
Update a function signature and all call sites
Changing a function to accept an options object instead of positional parameters requires updating the definition and every call site simultaneously.
# Refactor to options-object pattern
gemini 'Refactor createUser(name, email, role) to accept a single options object: createUser({ name, email, role }). Update the definition in userService.ts and all call sites.' \
src/services/userService.ts src/controllers/authController.ts src/tests/user.test.ts
Before (call site)
- createUser('Alice', 'a@x.com', 'admin')
After (call site)
+ createUser({
+ name: 'Alice',
+ email: 'a@x.com',
+ role: 'admin'
+ })
Refactoring Operations
Refactoring improves code structure without changing behavior. These examples show before-and-after patterns for the most common refactoring operations.
Extract a function from a long method
Before
function processOrder(order) {
// 20 lines of validation
if (!order.items?.length) throw new Error(...)
if (order.total < 0) throw new Error(...)
// ... more validation
// 30 lines of processing
const tax = order.total * 0.1
// ...
}
After
function validateOrder(order) {
if (!order.items?.length) throw new Error(...)
if (order.total < 0) throw new Error(...)
}
function calculateTax(total) {
return total * 0.1
}
function processOrder(order) {
validateOrder(order)
const tax = calculateTax(order.total)
}
gemini 'Extract the validation logic into a validateOrder() function and the tax calculation into calculateTax(). Keep the processOrder function as the entry point.' < orderService.ts
Convert class components to React hooks
Before (class component)
class Counter extends React.Component {
state = { count: 0 }
increment = () => {
this.setState({ count: this.state.count + 1 })
}
render() {
return <button onClick={this.increment}>
{this.state.count}
</button>
}
}
After (hooks)
function Counter() {
const [count, setCount] = useState(0)
const increment = () => setCount(c => c + 1)
return (
<button onClick={increment}>
{count}
</button>
)
}
# Convert all class components in a directory
gemini 'Convert class components to hooks' components/*.jsx
Apply consistent changes across multiple files and directories.
Code Migration: JavaScript to TypeScript
Migrating a JavaScript codebase to TypeScript is one of the most impactful refactors you can make for long-term maintainability. It is also one of the most tedious to do by hand. Gemini CLI can automate the mechanical parts — adding type annotations, defining interfaces, converting .js to.ts files — so you can focus on the genuinely difficult type decisions.
Step 1: Migrate a single file
Start with a leaf file (one that has no imports from your own codebase) to validate the approach.
Before (utils.js)
function formatCurrency(amount, currency) {
return new Intl.NumberFormat('en-US', {
style: 'currency',
currency,
}).format(amount)
}
module.exports = { formatCurrency }
After (utils.ts)
export function formatCurrency(
amount: number,
currency: string
): string {
return new Intl.NumberFormat('en-US', {
style: 'currency',
currency,
}).format(amount)
}
gemini 'Convert to TypeScript. Use explicit types for all parameters and return values. Replace CommonJS exports with ES modules.' < src/utils.js > src/utils.ts
Step 2: Bulk-migrate the entire project
#!/bin/bash
# migrate-to-ts.sh
find src -name '*.js' | while read jsfile; do
tsfile="${jsfile%.js}.ts"
echo "Migrating $jsfile → $tsfile"
gemini "Convert to TypeScript. Use ES module syntax." < "$jsfile" > "$tsfile"
done
# Verify the build
npx tsc --noEmit
Step 3: Fix remaining type errors
After the bulk migration, tsc will likely report some remaining type errors. Use Gemini CLI to fix them in batches:
# Pipe tsc errors to gemini for analysis
npx tsc --noEmit 2>&1 | gemini 'These are TypeScript compilation errors. Group them by file and suggest fixes for each.'
Using Plan Mode for Complex Edits
Plan Mode is Gemini CLI's most powerful safety feature for large-scale edits. When you add--plan to a command, Gemini CLI describes every change it intends to make in a numbered list — but makes no modifications to any file. You review the plan, request adjustments, and only run without--plan when you are satisfied.
Example: Plan a database migration refactor
# Step 1: Generate the plan (no files are changed)
gemini --plan 'Migrate all Mongoose model definitions to Prisma schema format. Update all service files to use Prisma client instead of Mongoose.' src/models/ src/services/
Gemini CLI outputs a plan like:
Plan (24 changes across 11 files):
1. Create prisma/schema.prisma with User, Post, Comment models
2. Delete src/models/user.model.ts (replaced by Prisma)
3. Delete src/models/post.model.ts
4. Update src/services/userService.ts: replace mongoose.model() with prisma.user
5. Update src/services/postService.ts: replace populate() with Prisma include
... 19 more changes
# Step 2: Execute after review
gemini 'Migrate all Mongoose model definitions to Prisma schema format. Update all service files to use Prisma client instead of Mongoose.' src/models/ src/services/
When to use Plan Mode
- • Any edit that touches more than 5 files simultaneously
- • Database or ORM migrations where wrong changes corrupt data
- • API contract changes that affect multiple services
- • Dependency upgrades with breaking changes
- • Security-critical refactors (authentication, authorization flows)
Advanced Techniques
Large-scale Refactoring
gemini 'Refactor this codebase to use TypeScript' --recursive src/
gemini 'Convert class components to hooks' components/*.jsx
Apply consistent changes across multiple files and directories.
Context-aware Editing
gemini 'Update this function to match the new API schema' --context api-schema.json function.js
Use external context files to inform editing decisions.
Performance Optimization
gemini 'Optimize this code for memory usage and speed' --profile performance algorithm.py
Focus editing on specific performance aspects.
Working with Code Patterns
Pattern-based Refactoring
#!/bin/bash
# Apply design patterns across codebase
find src -name '*.js' | while read file; do
gemini 'Apply observer pattern where appropriate' < '$file' > '$file.tmp'
mv '$file.tmp' '$file'
done
Frequently Asked Questions
How do I migrate a JavaScript project to TypeScript using Gemini CLI?
Use a two-pass approach. First run:find src -name '*.js' | xargs gemini 'Convert to TypeScript. Add explicit types to all function signatures, variables, and React props. Do not use 'any'.'This generates .ts files. Then run a second pass to fix type errors reported bytsc --noEmit.
Can Gemini CLI edit multiple files that depend on each other?
Yes. Pass all related files as arguments:gemini 'Rename the UserProfile interface to Profile across all these files. Update all imports.' src/types.ts src/components/Header.tsx src/pages/profile.tsxGemini CLI processes all files together and keeps cross-file references consistent.
What is Plan Mode and when should I use it?
Plan Mode separates the planning step from the execution step. Use it for large refactors where you want to review and approve the full list of changes before any files are modified. Run: gemini --plan 'Migrate all API calls from axios to fetch.'Gemini CLI will output a numbered list of every change it intends to make. Review the plan, then run without --plan to execute.
How do I refactor class components to React hooks without breaking the app?
Convert one component at a time and run tests after each. Use:gemini 'Convert this class component to a functional component with hooks. Preserve all existing behavior including error boundaries if present.' < UserList.jsx > UserList.tsxThen run npm test to confirm nothing broke before moving to the next component.