Most teams start prompt management with a prompts folder in the repository. Files have names like summarize_v3.txt or extract_entities_final_final.txt. You know the folder, and may have made it.
The issue is not versioning prompt text. That part is right. The issue is putting history in filenames, where tools cannot see it, eval results cannot connect to it, and run comparisons require manual work.
Here is the mental model that works, including the important ways prompts differ from source code.
What the code analogy gets right
Calling prompts code means source-control primitives remain useful: history, diff, branch, and rollback.
History lets you retrieve every prior prompt version and know when and why it changed. Not merely "the summarization prompt changed sometime in March," but a commit with a timestamp, author, and intent.
Diff compares two versions and shows their changes. Character-level diff often beats line-level diff for prompts, since one changed word can shift model behavior. Seeing "always include" become "try to include" in a 200-word prompt can explain a score change.
A branch lets you test a prompt variant without touching production. Run it against your eval suite before promotion. This prevents an untested "let me just try something" change from going straight to production.
Rollback quickly restores an earlier prompt version. If quality falls after a production change, restoration should take minutes, not hours.
These four primitives fit prompt management. The analogy breaks when you ask whether a version is better.
How prompts differ from code
For source code, correctness is mostly binary. A function returns the right value or not. A test asserts the expected output and passes or fails. If all tests pass after a function change, that strongly suggests safety.
Prompt quality is a distribution. A change that raises average score by 8% can also raise variance. Some formerly acceptable inputs may become poor, despite the higher average. A passing eval means this eval set did better on average, not that no input worsened.
This changes prompt review. A text diff shows changed words, not their output effects. Pair it with the eval delta: which inputs improved, which degraded, and by how much. Together, they make prompt changes reviewable like code changes.
The second difference is external dependency. Source code is deterministic in that identical function inputs produce identical outputs. Prompts run against a model, a black box with its own versioning. A prompt scoring 0.88 on Monday may score 0.83 on Wednesday after the provider updates the model. Your prompt depends on something outside your control.
Prompt versions matter only alongside the model version used for evaluation. A history containing only prompt text is incomplete. Record prompt text, model identifier, and eval scores together to get the needed context.
Deployable unit: prompt plus configuration
We initially made the mistake of versioning prompts apart from configuration. A prompt runs with a temperature, max token limit, model identifier, and sometimes a system prompt stored elsewhere.
Each can change behavior. Moving temperature from 0.7 to 0.2 for a creative writing prompt matters as much as rewriting a paragraph. Versioning text without temperature leaves history incomplete.
Version the execution bundle: prompt text plus every output-affecting configuration parameter. Record eval scores against that bundle version, not text alone.
This adds overhead but blocks a common bug. Someone changes temperature "just to test something," sees better results, then loses the uncommitted config change. Bundle versioning prevents configuration from silently separating from the prompt.
A branching plan for prompt development
Git branching fits prompt development fairly well. Main is production. Branch from main for an experimental variant, run the eval suite, then open a review with the eval delta and merge if key metrics improve.
Parallel experiments are harder. When two people vary one prompt, prompt variants cannot be meaningfully diff-merged like code branches. One variant wins; the other is discarded.
Treat variants as competing options, not mergeable branches. Run both on the same eval set, choose the stronger result, and archive the other with its scores and rejection rationale.
Version numbers or content addresses
Sequential numbers, v1, v2, v3, are easy for people to read. Everyone understands "we rolled back to v4." But v4 is opaque and says nothing about its contents.
Content-addressed identifiers, hashes of prompt text and configuration, are unambiguous. Matching hashes mean identical prompts; different hashes mean differences, even invisible ones. This supports cache invalidation and ties eval results to the exact bundle tested.
Use both in practice. A readable label, such as "summarizer-v4," works in conversation and deployment manifests. Eval infrastructure uses the content hash for reproducibility. The label points; the hash identifies.
Sequential versions are not wrong. They belong as metadata over a content-addressed store, not as the primary key of prompt history.
Turning history into action
History matters only when you can use it. When production quality drops, can you find the causing prompt change and restore the prior working version within minutes?
If you must search Git commits, locate the file, inspect the deployment log, and manually send the old version to the API, history exists but is not actionable. Connect it to deployment so rollback is one confirmed operation.
That connection separates versioned prompt files from first-class pipeline artifacts. Files provide history. An actionable setup lets you use it quickly under pressure, when a production regression appears at 2pm on a Thursday.