Claude API System Prompt vs User Prompt: Key Differences
When you call the Claude API, you're not sending Claude a single block of text — you're sending it a structured request made of two distinct components: a system prompt and one or more user/assistant messages. The system prompt sets persistent context, rules, and persona for the entire conversation. User prompts are the actual turns in the conversation — the questions, instructions, or data a human (or your application) sends at each step.
The short answer: use the system prompt for things that should apply to every response (tone, role, constraints, output format), and use user prompts for the specific task or question being asked right now. Mixing these up is one of the most common reasons developers get inconsistent or oddly-formatted responses from Claude.
How Claude's API Actually Separates Them
In the Messages API, a request looks like this:
{
"model": "claude-sonnet-4-5",
"system": "You are a technical support assistant for a SaaS billing platform. Always respond in under 150 words and never mention internal pricing.",
"messages": [
{ "role": "user", "content": "Why was I charged twice this month?" }
]
}
Notice that system is a top-level field, not a message with a role. It's not part of the messages array the way user and assistant turns are. This is a structural distinction, not just a style convention: Claude treats the system prompt as a standing instruction layer that applies across the whole conversation, while messages represent the back-and-forth exchange itself.
A curl example against the raw Anthropic-compatible format:
curl https://api.anthropic.com/v1/messages \
-H "x-api-key: $ANTHROPIC_API_KEY" \
-H "anthropic-version: 2023-06-01" \
-H "content-type: application/json" \
-d '{
"model": "claude-sonnet-4-5",
"max_tokens": 500,
"system": "You are a strict JSON-only API. Never include explanations.",
"messages": [
{ "role": "user", "content": "List 3 programming languages." }
]
}'
If you're routing requests through SubToAPI instead of managing raw Anthropic keys, the request shape is the same — see /docs/messages for the full reference:
curl https://api.subtoapi.app/v1/messages \
-H "Authorization: Bearer $SUBTOAPI_KEY" \
-H "content-type: application/json" \
-d '{
"model": "claude-sonnet-4-5",
"max_tokens": 500,
"system": "You are a strict JSON-only API. Never include explanations.",
"messages": [
{ "role": "user", "content": "List 3 programming languages." }
]
}'
What Belongs in the System Prompt
The system prompt is the right place for anything that should hold true no matter what the user asks next:
- Role and persona — "You are a senior backend engineer reviewing pull requests."
- Output constraints — format, length, language, tone.
- Behavioral rules — what to refuse, what to avoid, how to handle edge cases.
- Static context — company policies, product documentation, schema definitions that don't change between turns.
- Tool-use instructions — how and when to call available tools (see /docs/tools).
Because the system prompt persists for the life of the conversation, it's also the most efficient place to put large, reusable context. If you're sending the same instructions or reference material on every request, that's a strong signal it belongs in system rather than being repeated in every user message.
What Belongs in the User Prompt
User prompts carry the dynamic, turn-specific content:
- The actual question or task.
- Data that changes per request (a support ticket, a code snippet, a document to summarize).
- Follow-up clarifications in a multi-turn conversation.
- User-supplied parameters that affect just this one response.
A useful mental model: the system prompt answers "who are you and how should you behave?" The user prompt answers "what do you want right now?"
A Practical Example of Getting It Wrong
Here's a system prompt that's actually doing a user prompt's job:
{
"system": "Summarize the following article in 3 bullet points: [article text]",
"messages": [
{ "role": "user", "content": "Go." }
]
}
This works, but it's fragile. If you later want to summarize a different article, you have to rebuild the entire system prompt. It also wastes the system prompt's purpose — it should describe how to summarize, not contain the one-off content to summarize.
A cleaner split:
{
"system": "You are a summarization assistant. Always respond with exactly 3 bullet points, each under 20 words. No preamble.",
"messages": [
{ "role": "user", "content": "Summarize this article: [article text]" }
]
}
Now the behavior (format, length, style) lives in system and is reusable across every article you send, while the content lives in messages where it belongs.
Multi-Turn Conversations and the System Prompt
One detail that trips people up: the system prompt is sent once per API call, not once per conversation turn stored on Anthropic's side. Claude's API is stateless — there's no server-side conversation memory. Every request you send must include the full message history plus the system prompt, even if it hasn't changed since the last call.
const response = await fetch("https://api.subtoapi.app/v1/messages", {
method: "POST",
headers: {
"Authorization": `Bearer ${process.env.SUBTOAPI_KEY}`,
"content-type": "application/json"
},
body: JSON.stringify({
model: "claude-sonnet-4-5",
max_tokens: 1024,
system: "You are a concise code reviewer. Flag only correctness and security issues.",
messages: [
{ role: "user", content: "Review this function: ..." },
{ role: "assistant", content: "Found one SQL injection risk..." },
{ role: "user", content: "Can you suggest a fix?" }
]
})
});
The system prompt stays identical across all three calls in a growing conversation; only the messages array accumulates. If you're building an app that streams responses turn by turn, this pattern combines well with server-sent events — see /docs/streaming for details.
Should You Put Dynamic Data in the System Prompt?
Sometimes. If you're injecting per-request context like a user's account tier, retrieved documents, or current date, it's technically valid to template that into the system prompt. The distinction isn't strictly "static vs dynamic" — it's "instruction vs request." A retrieved document used as reference material to answer a question can live in system since it describes context the assistant should use for every answer in that session. A specific question about that document belongs in messages.
If you're new to the Messages API shape generally, /docs/quickstart walks through the full request/response cycle, and /docs/messages covers the field-level reference including system, messages, and max_tokens.
questions
Does the system prompt count toward token usage and billing? Yes. The system prompt is part of the input tokens for every request it's included in, so a long system prompt sent on every call adds up across a conversation.
Can I use multiple system prompts in one request? No — system is a single top-level string (or content block array) per request. If you need multiple instruction sources, concatenate them into one coherent system prompt rather than sending separate fields.
Does changing the system prompt reset the conversation? It doesn't reset anything server-side since Claude's API is stateless, but changing it mid-conversation does change how Claude interprets the existing message history, which can produce inconsistent behavior if the new instructions conflict with earlier assistant replies.