← Library

intermediate9 min read4 November 2026

This is a sample: a placeholder until Shyam’s own write-up replaces it.

Codemods are just ASTs with manners

tl;dr A codemod reads your code as a tree, changes the tree, and prints it back without touching anything you didn't ask it to.

you'll learn

  • What an AST is, and why tools edit trees instead of text
  • The four steps every codemod follows
  • How to rename an API across a codebase without wrecking the formatting
How deep?

Renaming a function in one file is easy. Renaming it in 4,000 files, without breaking the ones where the name means something else, is where find-and-replace gives up and a CodemodA script that rewrites source code automatically, usually across a whole codebase at once. takes over.

Why not find-and-replace?

Say a library renames fetchUser(id) to getUser({ id }). A regex can find the text fetchUser(, but it can’t tell a call from a comment, a string, or a local variable that happens to share the name. And it definitely can’t move the argument into an object.

A codemod doesn’t look at text at all. It parses the file into an AST (abstract syntax tree)Your code parsed into a tree of nodes: a function call, its arguments, an identifier. Tools change the tree, not the text., a tree where every node knows exactly what it is.

The four steps

Every codemod, from a one-line rename to a framework migration, follows the same loop.

1Parse2Find3Change4Print
What a codemod does to each file
  1. Read the source file and turn it into a tree of nodes. jscodeshift uses recast for this, which also remembers the original formatting of every node.

  2. Search the tree for the nodes you care about. Here: every CallExpression whose callee is the identifier fetchUser.

  3. Replace or edit those nodes. Rename the callee to getUser and wrap the first argument in an object: { id }.

  4. Turn the tree back into source. Untouched nodes are printed exactly as they were, so the diff only shows real changes.

The code

Here’s the whole transform with jscodeshiftA toolkit from Meta for running codemods on JavaScript and TypeScript, built on recast.:

export default function transformer(file, api) {
  const j = api.jscodeshift;

  return j(file.source)
    .find(j.CallExpression, { callee: { name: 'fetchUser' } })
    .forEach((path) => {
      const [id] = path.node.arguments;
      path.node.callee.name = 'getUser';
      path.node.arguments = [j.objectExpression([j.objectProperty(j.identifier('id'), id)])];
    })
    .toSource();
}

quick check Which call would this codemod change?

deep dive Why the formatting survives

recastA parser and printer that remembers the original formatting, so only the parts you changed get reprinted. keeps a copy of the original source for every node it parses. When you call toSource(), it walks the tree and reuses the original text for any node you didn’t modify. Only modified nodes are pretty-printed from scratch. That’s why a codemod across thousands of files produces a diff a human can actually review.

The trade-off: if you replace a big node (say, a whole function), recast has to reprint all of it, and its formatting may differ from your Prettier config. Run Prettier after the codemod to settle it.

Running it safely

Treat a codemod like a migration: dry-run it, test it against real examples, then run it everywhere.

  • Write fixtures: an input file and the output you expect, for the common case and the weird ones.
  • Run with --dry --print first and read a sample of the output.
  • Commit before running, so git diff shows exactly what changed and git checkout . undoes it.

so, in short

  1. Find-and-replace edits text; a codemod edits meaning.
  2. Every codemod is parse → find → change → print.
  3. recast reprints only the nodes you touched, so diffs stay small and reviewable.
  4. Start with a dry run and a handful of test fixtures before running it everywhere.

still curious?

Ask the librarian

Soon you'll be able to ask questions about this post and get answers that point back to the exact paragraph. Until then, ask me directly.

Ask Shyam →

Swipe, or tap the time before or after