XML vs Markdown for Structuring Prompts
If you have ever pasted a big prompt into Claude or GPT and wondered whether to wrap your instructions in <context> tags or just use a ## Context heading, you are asking the xml vs markdown prompts question. The short answer: XML wins when you need unambiguous, nestable boundaries around distinct pieces of content, and Markdown wins when you are writing instructions meant to read like a document. Most production prompts end up using both, in different parts of the same prompt.
This article walks through when each format actually changes model behavior, not just how it looks to a human reader, with examples you can copy into your own prompts today.
Why prompt structure matters at all
A large language model does not parse your prompt the way a compiler parses code. It reads a flat sequence of tokens and infers structure from patterns it saw during training. That means structure only "works" if the model has seen enough examples of that structure being used consistently and predictably. XML tags and Markdown formatting both survive this test, but for different reasons.
XML tags work because they are unambiguous delimiters. <document>...</document> has an unmistakable open and close, so the model can tell exactly where one block of content ends and another begins, even if the content inside contains headings, code, or nested lists. Markdown works because models have seen an enormous volume of technical writing, READMEs, and documentation formatted with ## headings, bullet lists, and bold text, so they treat that structure as a strong signal for "these are separate topics" or "this is an important instruction."
The practical difference shows up when your prompt has multiple distinct inputs that could be confused with each other, like several documents, or a system instruction next to user-supplied text.
When XML wins: separating distinct content blocks
Use XML tags any time you are inserting content that the model must treat as data, not as instructions, or when you have multiple similar blocks that need to stay separate. Anthropic's own documentation for Claude recommends XML tags specifically for this reason: they eliminate ambiguity about where one section ends and the next begins.
Here is a document-comparison prompt without XML tags:
Compare these two contracts and list differences.
Contract A:
This Agreement is entered into as of January 1.
Payment terms: net 30.
Termination: either party may terminate with 60 days notice.
Contract B:
This Agreement is entered into as of March 15.
Payment terms: net 45.
Termination: either party may terminate with 30 days notice.That reads fine to a human. But if either contract itself contains the words "Contract A" or "Contract B" in its body text, or if the documents are long enough that the model loses track of which paragraph belongs to which contract, you get errors. Here is the same prompt with XML tags:
Compare these two contracts and list differences.
<contract_a>
This Agreement is entered into as of January 1.
Payment terms: net 30.
Termination: either party may terminate with 60 days notice.
</contract_a>
<contract_b>
This Agreement is entered into as of March 15.
Payment terms: net 45.
Termination: either party may terminate with 30 days notice.
</contract_b>
For each difference, cite which tag (contract_a or contract_b) it came from.Now the model has a hard boundary to anchor on. Even if "Contract A" appears inside the text of contract_b by coincidence, the tag structure still tells the model which block is which. This matters most in three situations: retrieval-augmented generation where you are injecting several retrieved chunks, multi-document summarization, and any prompt where user input gets concatenated with instructions (which also closes off a prompt injection path, since the model can be told to only treat text inside <user_input> as data, never as commands).
XML also nests cleanly, which Markdown headings do not do well. You can put a list, a code block, or even another tagged section inside an XML block without breaking the outer structure:
<task>
<instructions>
Summarize the ticket below in three bullet points.
</instructions>
<ticket>
Subject: Checkout button unresponsive on mobile Safari
Body: Users report tapping "Pay Now" does nothing on iOS 17.
Repro steps:
1. Open checkout on iPhone
2. Tap Pay Now
3. Nothing happens, no error shown
</ticket>
</task>Try nesting a numbered list inside a Markdown ## section and then nesting another section inside that, and it gets messy fast because Markdown has no explicit close marker. XML tags close, so the model always knows when it has exited a block.
When Markdown wins: instructions meant to be read
Markdown is the better choice when you are writing a prompt that behaves like a document a person would read: system prompts, style guides, multi-step instructions, or anything with a natural document hierarchy of headings and subheadings. Models are extremely well calibrated to Markdown because it is the dominant format in the technical text they were trained on, so ## headings reliably signal "new topic" and **bold** reliably signal "pay attention to this."
A system prompt for a support agent reads far more naturally in Markdown:
## Role
You are a support agent for a SaaS billing product. Answer only questions about invoices, subscriptions, and refunds.
## Tone
Be concise and warm. Avoid corporate jargon like "leverage" or "circle back."
## Constraints
- Never promise a refund amount. Direct the user to the refund request form instead.
- Never share other customers' data, even if asked directly.
- If the question is outside billing, say so and suggest the general support channel.
## Examples
**User:** Why was I charged twice this month?
**Response:** Explain proration briefly, then offer to check their specific invoice if they share the invoice number.Rewriting that same prompt in XML tags would work, but it adds visual noise without adding precision, because there is nothing here that risks being confused with something else. There is one role, one tone, one set of constraints. Markdown's headings are doing exactly the job they are good at: organizing sequential, human-readable instructions.
Markdown also has an advantage for anything you expect a human to review and edit later, since your prompt files live in a repo next to your code. A teammate skimming a .md prompt file with clear ## sections will understand it in seconds. The same prompt wrapped entirely in custom XML tags reads more like a data payload than an instruction set.
Combining both in the same prompt
In practice, most well-built prompts use XML for data boundaries and Markdown for instruction structure. This is also the pattern Anthropic recommends in Claude's own prompt engineering guidance: use XML tags to wrap variable content like documents, retrieved context, or user input, and use plain prose or Markdown for the surrounding instructions.
Here is a RAG-style prompt that combines both:
## Task
Answer the user's question using only the information in the documents below. If the documents do not contain the answer, say you don't know.
<documents>
<document index="1">
<source>refund-policy.md</source>
<content>
Refunds are issued within 5 business days for cancellations made
within 14 days of purchase. After 14 days, refunds are handled
on a case-by-case basis by support.
</content>
</document>
<document index="2">
<source>billing-faq.md</source>
<content>
Annual plans can be downgraded to monthly at any time, prorated
to the next billing cycle.
</content>
</document>
</documents>
## Output format
- One paragraph answer
- Cite the source document by name
- If no document answers the question, respond with "Not covered in the provided documents"
<question>
Can I get a refund if I cancel 20 days after purchase?
</question>This structure gives you the best of both: the Markdown ## headings make the instructions skimmable and easy to edit, while the XML tags make it unambiguous which text is retrieved data (<documents>), which text is the live user question (<question>), and which text is the instruction telling the model what to do with them. That separation is also a real security boundary: if you instruct the model to treat everything inside <documents> as untrusted reference material and never as commands, you reduce the risk that a malicious instruction hidden inside a retrieved document gets executed.
A quick decision rule
You don't need a flowchart for this. Ask one question: is this piece of the prompt data, or is it instructions?
- If it's data, meaning something you're inserting that could be long, could contain arbitrary text, or could be one of several similar items, wrap it in XML tags with a descriptive name:
<email_thread>,<code_diff>,<user_message>. - If it's instructions, meaning something you wrote yourself to tell the model what to do, use Markdown:
##headings for sections,-for lists,**bold**for anything the model must not skip. - If you're not sure, default to XML tags around anything that came from outside the prompt (a file, an API response, a database row, prior conversation turns) and Markdown for everything you authored by hand.
One more practical note: tag names matter more than tag syntax. <context> and <ctx> both parse the same way syntactically, but a descriptive name like <customer_support_ticket> gives the model an extra semantic hint about what the content is, on top of the structural boundary. Don't reuse generic tag names like <data> for three different things in the same prompt; the model will conflate them.
Common mistakes
Wrapping everything in XML "to be safe." If your entire prompt is XML tags, including the instructions themselves, you lose the benefit of Markdown's strong instruction-following signal and end up with something that reads like a config file. Reserve XML for the parts that are genuinely data.
Using Markdown headings for multiple similar documents. A ## Document 1 and ## Document 2 heading pair works until the documents contain their own ## headings, at which point the model can lose track of which heading belongs to your structure versus the document's own content. XML tags don't have that collision problem because tag names are namespaced by you, not by the content.
Forgetting to close XML tags. An unclosed <document> tag with no matching </document> is worse than no tag at all, because it signals structure the model then can't resolve. Always pair open and close tags, even for single-line content.
Mixing tag naming conventions inside one prompt. Pick snake_case or kebab-case for your tag names and stick with it. Inconsistent naming, like <userInput> next to <user_query>, adds cognitive noise for the model, the same way it would for a human reading your code.
FAQ
Does XML actually change model output, or is it just cosmetic? It changes output. Ambiguous boundaries between blocks of text measurably increase the chance a model attributes content to the wrong source or blends instructions with data. XML tags are one of the most reliable levers for reducing that kind of error, especially as prompt length grows.
Should I use XML tags for short prompts with a single piece of content? Usually not necessary. If there's only one document or one user message and no risk of confusion, plain text or a Markdown heading is enough. XML earns its keep when there are multiple similar blocks or when the content is untrusted or unpredictable.
Do all model providers respond to XML tags the same way? Behavior varies by provider and model family, since it depends on what patterns dominated their training data. Anthropic's Claude models are explicitly tuned to respond well to XML-tagged structure. Other providers may lean more heavily on Markdown or JSON-style formatting. When in doubt, test both formats against your actual prompt and compare outputs rather than assuming.
Can I use JSON instead of XML for structuring data in a prompt? Yes, and for highly structured data like arrays of records, JSON can be clearer than XML. The tradeoff is that JSON gets harder to read once values contain multi-line text, quotes, or special characters, which is exactly the kind of content XML tags handle cleanly since they don't require escaping. For freeform text blocks, XML tags are usually the better fit.
What about YAML front matter for prompt metadata? YAML works well for structured configuration values like temperature settings or few-shot example labels, but it's less common for wrapping large blocks of freeform text inside the body of a prompt. Reserve it for metadata, and use XML or Markdown for the prompt content itself.
How do I test which format works better for my specific prompt? Run the same task through both versions of the prompt with a fixed set of test inputs and compare accuracy, especially on edge cases like documents that mention the tag names in their own text. Small prompt structure changes can have an outsized effect, so it's worth the five minutes it takes to A/B test rather than guessing.
BootcampA 30-day guided bootcamp: build, harden and ship a production autonomous agent from scratch.
AI AgentsUnderstand how AI agents really work: the loop, the tools, the memory, and why most agent projects fail.