# The smallest working setup

One URL. Two representations. One correct `Vary` header. Every recipe on this site is a variation of the three steps below.

## 1. Detect the Accept header

When a request comes in, read `Accept`. If it asks for `text/markdown` before `text/html`, you'll serve Markdown. Otherwise, you'll serve HTML.

Don't substring-match. Parse the header, sort by q-value, break ties by specificity. Or use a library — every stack has one. See the [Accept parsing guide](https://acceptmarkdown.com/guides/accept-parsing) for the gotchas.

## 2. Respond with the matching representation

You need two things in the response:

- `Content-Type` matching what you served (`text/markdown; charset=utf-8` or `text/html; charset=utf-8`)
- `Vary: Accept` so caches key on the request header

If you can't satisfy the request at all (the client specifically asked for something you don't do), return [406 Not Acceptable](https://acceptmarkdown.com/guides/returning-406) instead of silently falling back.

## 3. Verify with curl

```
curl -sI -H "Accept: text/markdown" https://yoursite.com/article
```

You should see `Content-Type: text/markdown` and `Vary: Accept`. Swap the Accept header to `text/html` and you should get HTML back from the same URL.

Or use the [probe on the home page](https://acceptmarkdown.com/#tester) to check any URL.

---

## What's next

Pick your stack: [Nginx, Caddy, WordPress, Laravel, Rails, Cloudflare Workers, Next.js, Astro, Apache, SvelteKit, Nuxt/Nitro, Express, Django](https://acceptmarkdown.com/recipes). Each recipe is the three steps above translated into that stack's idioms, usually in under 20 lines of config or code.

If your site sits behind Cloudflare, you may not need to do any of this yourself — see [Markdown for Agents](https://acceptmarkdown.com/guides/cloudflare-markdown-for-agents).