Why You Should Commit Your Lock File

One small file that is often ignored in a JavaScript project is the lock file.

package-lock.json for npm.
pnpm-lock.yaml for pnpm.
yarn.lock for Yarn.

Commit it.

Why?

Your package.json usually doesn’t define the exact version of every dependency.

For example:

"react": "^19.0.0"

The ^ means npm can install a newer compatible version.

Today you might get:

react 19.0.0

Next month, another developer might get:

react 19.1.0

And one day, your CI/CD pipeline could install yet another version.

That’s where the lock file helps.

It records the exact dependency versions that were resolved, including transitive dependencies.

So instead of:

package.json - "Give me a compatible version"

you get:

package.json - lock file ↓ "Install exactly what we tested"

This is especially important in teams and production systems.

A developer’s machine, CI server and production environment should ideally be using the same dependency tree.

With npm, that’s one reason npm ci exists.

With pnpm:

pnpm install --frozen-lockfile

can ensure the lock file isn’t silently changed during installation.

The lock file also makes debugging easier.

If an application suddenly breaks after a dependency update, you can see exactly which versions changed.

Without a lock file, dependency resolution can become unpredictable.

So my simple rule is:

package.json says what you want.
The lock file says exactly what you installed.

If you’re building a serious application, commit the lock file.

Don’t add it to `.gitignore.

Your future self – and your CI/CD pipeline – will thank you.

Ask, Plan, Agent — pick the right mode every time

AI Coding Tools · Quick Guide

Ask, Plan, Agent — pick the right mode, every time

Three modes, three different jobs. Here’s the mental model that stops you from reaching for the sledgehammer when you need a scalpel.


💬 Ask

You want understanding, not changes.

  • Explain what this function does or why it was written this way
  • Review code for bugs, smells, or security issues
  • Compare two approaches before committing to one
  • Generate a snippet you’ll paste and review yourself
  • Onboard to an unfamiliar codebase — “walk me through this flow”

🗺️ Plan

You want a blueprint before the AI touches anything.

  • Non-trivial features that span multiple files or systems
  • Risky refactors where a wrong assumption is expensive to undo
  • Situations where you need to approve the approach first
  • Architecture decisions — let AI surface tradeoffs, you decide
  • Starting a new module: “plan how to add auth to this app”

🤖 Agent

You want it done — and you trust the scope.

  • Well-scoped tasks with a clear finish line: “add dark mode to this component”
  • Mechanical work you’d find tedious: writing tests, adding JSDoc, migrations
  • Iterating on a plan you already approved in Plan mode
  • Chained edits across many files that follow an obvious pattern

The Quick Rule of Thumb

Unclear? Start in Ask. Clarify before acting. Risky? Go to Plan. Review before executing. Scoped? Use Agent. Let it run.

TL;DR

Most people jump to Agent by default. The real power move is using Plan for anything non-trivial — it forces alignment before the AI writes a single line, and saves you a painful revert 20 minutes later.