skip to content

In Langfuse, how do prompt versions and labels decide what get_prompt() returns?

level: juniorimportance: must knowfreq 72%

answer

  1. Two concepts: numbers and pointers
  2. Saves append, never overwrite
  3. One pointer is the default fetch
  4. production label resolved by get_prompt
  5. label= or version= overrides the default

basics

~20 s

Every save of a Langfuse prompt creates a new immutable numbered version. Labels such as production and latest are movable pointers to one of those versions. langfuse.get_prompt("name") resolves the version labelled production; pass label= or version= to target a different one.

solid answer

~40 s

Langfuse stores prompts server-side under a name, and each save appends a new integer version that is never edited in place. On top of the version list sit **labels** — named pointers you move onto a version. `production` is the one the SDK resolves by default, and `latest` is maintained by Langfuse to follow the highest version number. So `langfuse.get_prompt("support-reply")` returns whichever version currently carries the `production` label, `get_prompt("support-reply", label="staging")` follows your own label, and `get_prompt("support-reply", version=3)` pins a specific version and ignores labels entirely. Promoting a prompt is a label move, not a new deploy; rolling back is moving the label onto the older version, which is safe precisely because versions are immutable. The call returns a prompt client object exposing `.prompt`, `.name`, `.version`, `.labels` and `.config`.

code

python · 17 lines
python
from langfuse import Langfuse

langfuse = Langfuse()

# Creating a version and promoting it in one call
langfuse.create_prompt(
    name="support-reply",
    prompt="Answer the customer question politely: {{question}}",
    labels=["production"],
    config={"model": "gpt-4o-mini", "temperature": 0.2},
)

prod = langfuse.get_prompt("support-reply")                  # production label
staging = langfuse.get_prompt("support-reply", label="staging")
pinned = langfuse.get_prompt("support-reply", version=3)

print(prod.version, prod.labels)

go deeper

for a junior

Know that prompts are stored by name, each save adds a numbered version, and labels point at one version. Say plainly that a bare get_prompt call returns the version labelled production.

for a middle

Explain the mechanics: versions are immutable and append-only, labels are movable pointers, and get_prompt resolves label, then version, then defaults to production. Mention that the call returns a prompt client with .version and .config, not a plain string.

for a senior

Show the operational judgment: which call sites follow a moving label and which pin a version, that a label move is the release event, and that rollback is a relabel. Note that propagation across replicas is bounded by the client cache, not instant.

for a principal

Own the policy question — who may move the production label, what must pass before promotion, and where the organisation deliberately gives up deploy-free iteration in exchange for a pinned, auditable version on high-risk surfaces.

## Why prompts live on the server at all When a prompt is a string literal in application code, changing a single word costs a code review, a build and a deploy — and the people who most want to change it (product owners, support leads, domain experts) cannot touch it. Langfuse prompt management moves the string into the Langfuse backend, where the application fetches it at runtime **by name**. The service ships once; the prompt then changes on its own cadence. That convenience is only safe because of two mechanisms working together: immutable versions and movable labels. ## Versions are immutable and append-only Each save of a prompt under a given name produces the next integer version: 1, 2, 3, and so on. Versions are never rewritten. You create one from the Langfuse UI, or from the SDK: `langfuse.create_prompt(name="support-reply", prompt="...", labels=["production"], config={...})` Calling `create_prompt` again with the same `name` **adds** a version rather than replacing the existing one. Immutability is what makes rollback trustworthy: version 7 is exactly the bytes it always was, so directing traffic back to it reproduces the previous behaviour precisely, with no "did someone also tweak it while we were rolling back?" ambiguity. ## Labels are movable pointers A label is a named pointer to one version of one prompt. Two conventions matter: - **production** — the label the SDK resolves when you ask for nothing else. Promoting a prompt means moving this label onto a newer version. - **latest** — maintained by Langfuse to point at the highest version number, so it advances automatically every time you create a version. You can also define your own labels — `staging`, `canary`, a per-region label — and one version may carry several labels at once. Moving a label onto a different version is a single write, and that write **is** the release. ## What get_prompt actually resolves - `langfuse.get_prompt("support-reply")` → the version labelled `production`. - `langfuse.get_prompt("support-reply", label="staging")` → the version that label points at. - `langfuse.get_prompt("support-reply", version=3)` → version 3, labels ignored. - `langfuse.get_prompt("support-chat", type="chat")` → a chat prompt, whose template is a list of role/content messages rather than a single string. The return value is a prompt client object, not a bare string. It carries the raw template on `.prompt`, plus `.name`, `.version`, `.labels` and `.config` (an arbitrary JSON blob versioned alongside the text). You still have to substitute variables into it before sending it to a model. ## Choosing between a label and a pinned version This is the real design decision, and it is per call site: - **Label** — the prompt can change without redeploying the service. Right for surfaces where iteration speed is the point and a bad prompt is recoverable. - **Pinned `version=`** — the prompt is effectively part of the build. Right for a high-risk surface, for a reproducible offline experiment, or for anything you must be able to replay exactly. A common house style is: labels everywhere by default, pinned versions in the one or two places where a silent text change would be a compliance or safety event. ## Consequences and pitfalls - **A prompt with no production label breaks the default fetch.** Creating a prompt in the UI and forgetting to promote it is the classic first-day failure: the code calls `get_prompt("name")` and finds nothing to resolve. - **`label=` and `version=` are alternatives, not a filter pair.** Decide whether the call site follows a moving pointer or pins a number. - **A label move is instant server-side but not instant in your fleet**, because the SDK caches prompts client-side; each process picks the change up when its cache entry expires. - **"What was in production last Tuesday?" is only answerable if you recorded it.** Labels move, so the label alone is not an audit trail — you get the answer by linking the fetched prompt to the generations it produced, so every trace carries the version number it actually used. - **Names are the coupling point.** A typo'd or renamed prompt name is a runtime failure, not a compile-time one; keep names in one constants module rather than scattered literals.

  • How would you roll back a bad prompt change in Langfuse, and why is that safe?
    Move the `production` label back onto the last known-good version — a single write, no deploy. It is safe because versions are immutable: the older version is byte-for-byte what it was when it worked, so nothing else can have drifted underneath it. In a fleet the rollback lands as each process's prompt cache entry expires, so it is fast but not atomic.
  • What does the latest label point at, and why would you not use it in production?
    `latest` is maintained by Langfuse to follow the highest version number, so it advances the instant anyone saves a new version. That makes it useful for a playground or a scratch environment, but in production it means any save — including an unreviewed experiment — goes live immediately. Production should follow a label you move deliberately.
  • When would you pin version= instead of following a label?
    When a silent text change is unacceptable or must be reproducible: a regulated surface, a safety-critical system prompt, or an offline experiment you need to replay exactly. Pinning makes the prompt part of the build again, so changing it costs a deploy — that is the tradeoff you are buying.

saying these in an interview costs you the question

  • Thinks saving a prompt overwrites the previous version
  • Believes get_prompt returns the newest version by default
  • Confuses the latest label with the production label
  • Assumes a label move reaches every replica instantly
  • Thinks version= and label= combine to filter one result

context