In the Messages API, user and assistant turns live in the messages array, but instructions about the conversation live in a separate top-level field: system. Think of it as the contract between your application and the model — it applies to every turn, it is written by you rather than your end users, and it is where enterprise apps encode who Claude is supposed to be and what it must never do. The field works identically on all four third-party platforms because it is part of the core Messages API.
What belongs in the system prompt
Anthropic's prompting guidance is consistent on the fundamentals. Give Claude a role — even a single sentence in the system prompt focuses behavior and tone. Be clear and direct: the golden rule is that if a colleague with minimal context would be confused by your instructions, Claude will be too. Explain why an instruction matters ("responses are read aloud by a text-to-speech engine, so never use ellipses") — the model generalizes from the reason, not just the rule. And structure longer prompts with XML tags, wrapping instructions, context, and inputs in their own consistently named tags so the sections cannot bleed into each other.
What does not belong there: per-request data (that goes in messages), secrets, and anything that changes on every call — for reasons that come down to caching.
Where system sits in the token budget
The system prompt is billed as ordinary input tokens on every request, and it counts toward the context window like everything else. Two overheads are easy to forget. First, when you pass a tools array, the API adds a tool-use system prompt behind the scenes — for example about 290 extra input tokens on Claude Opus 4.8 and 354 on Sonnet 5 with the default tool_choice. Second, individual built-in tools carry their own definition costs on top of that. None of this is large per request, but on high-volume workloads it is real money, which is why the next section matters most.
Caching: why stability pays
Prompt caching treats a request as a hierarchy: tools, then system, then messages. A change at any level invalidates the cache at that level and everything after it — so editing the system prompt wipes the cached system and message prefix, while tool definition changes wipe all three. Caching is also a strict prefix match on exact bytes: one changed character invalidates everything from that point on.
response = client.messages.create(
model="claude-opus-4-8",
max_tokens=1024,
system=[{"type": "text", "text": STABLE_POLICY_TEXT,
"cache_control": {"type": "ephemeral"}}],
messages=[{"role": "user", "content": user_question}],
)
With a cache_control breakpoint on the system block, repeat requests within the TTL read the system prompt from cache at roughly a tenth of the normal input price. The mechanics — TTLs, breakpoints, minimum lengths — are covered in the prompt caching article.
Durable system prompts for enterprise apps
Patterns that hold up in production: keep one canonical system prompt per application version and treat edits like code changes (reviewed, versioned, tested against your evals); state boundaries positively where possible; include 3–5 diverse examples wrapped in <example> tags when output format matters; and resist the urge to branch the prompt per user — per-user variants defeat caching and multiply the surface you have to test. Remember that a system prompt is guidance, not a security boundary: server-side authorization checks still belong in your application, not in prose.
A newer wrinkle: mid-conversation system messages
Classically, system is a top-level field and "role": "system" inside the messages array is rejected. Claude Opus 4.8 introduces an exception: mid-conversation system messages after a user turn, which let an operator inject new instructions late in a long conversation without invalidating the cached prefix. This is currently supported only on the first-party API and Claude Platform on AWS — not on Bedrock, Vertex AI, or Foundry — and other models return a 400, so treat it as an optimization, not a portability assumption.
Where to go next
Pair this with the Messages API anatomy and multi-turn conversation management, or check the feature matrix for platform-by-platform capability differences.