This content originally appeared on Ariel Salminen and was authored by Ariel Salminen
Large Language Models are increasingly relying on information found on the web, but often struggle to handle most websites in their entirety because the context windows are too small. In an attempt to solve this, there is a new emerging standard called llms.txt.
This proposal aims to standardize on using an /llms.txt
file to provide information to help LLMs use a website at inference time. The proposal is based on Markdown format as it’s the most widely and easily understood format for language models right now.
Since my website uses Eleventy and the content is already written in Markdown format, I wanted to spend a few hours implementing this feature. Mainly to see how it could be utilized with different AI tools and if it (already today) improves the visibility of my website’s content in various contexts.
Side note: I’ve previously had conflicting thoughts when it comes to the content on this website and whether I want that to be re-purposed by LLMs. I’ve since changed my mind on this though. Mainly because I realized that I want the information I provide here to be accessible to the widest possible range of users in the future. The method used to access or re-purpose the content isn’t something I want to try to control.
What goes into LLMs.txt?
In its simplest form, an /llms.txt
looks like this. Note that the Optional
section holds a special meaning — if it’s included, the URLs provided there can be skipped if a shorter context is needed:
# Title
> Optional description goes here
Optional details go here
## Docs
- [Link title](https://link_url.md): Optional link details
## Optional
- [Link title](https://link_url.md)
Looks fairly straightforward? Ok, let’s try to implement this using Eleventy!
Preparing Robots.txt
To get started, I first ended up removing the previously defined AI Data Scrapers block list from my website’s /robots.txt
and simplified it to allow crawling for all user agents. The updated version looks like this:
# Robots.txt of arielsalminen.com
# www.robotstxt.org
# Allow crawling of all content
User-agent: *
Sitemap: https://arielsalminen.com/sitemap.xml
Creating Template for LLMS.txt
The next step was to create an llms.njk
template in the root of my website’s src
directory. This template basically takes care of generating the /llms.txt
file:
---
permalink: llms.txt
eleventyExcludeFromCollections: true
---
# Ariel Salminen
> Ariel Salminen is a Design Systems Architect from Helsinki,
Finland with 20 years of experience helping companies build
tools for the web platform.
In the above example, I’m setting the permalink
option to define the output file name and use eleventyExcludeFromCollections
to make sure that this template isn’t included in any of the Eleventy collections I’m using elsewhere on the website.
Adding Posts to LLMS.txt
Once I had a template to utilize, I created a simple Nunjucks for
loop to get the posts from my blog onto this template. They are all tagged with post
, so I used that collection directly:
## Docs
{%- for page in collections.post | reverse %}
- [{{ page.data.title | safe }}](https://arielsalminen.com{{ page.url | replace(r/.$/, ".md") }}){% if page.data.llms %}: {{ page.data.llms | safe }}{% endif %}
{%- endfor %}
I’m keeping the URL the same as the original content, but replacing the ending with .md
instead. Additionally, if the post contains llms
meta data, that is also being added as a description to provide more context for the language models.
Serving Content in Markdown Format
While my website’s content is written in Markdown format already, Eleventy converts that into an HTML format in the build phase. The original .md
files also include some unnecessary meta data that I don’t really want to expose to the language models.
To solve these problems, I ended up creating another template called markdown.njk
into the root of my src
directory with the following contents in it:
---
pagination:
data: collections.post
size: 1
alias: article
permalink: "{{ article.data.date | year }}/{{ article.data.title | slug }}.md"
eleventyExcludeFromCollections: true
---
# {{ article.data.title | safe }}
{{ article.rawInput | safe }}
This template makes sure that each post on my blog gets generated and served in Markdown format in addition to the HTML format, but with .md
appended at the end of the URL.
Adjusting Netlify Headers for .MD and .TXT
By default, Netlify seems to serve .md
and .txt
files with a charset that doesn’t support some common characters in UTF-8. To improve this, I modified the Content-Type
and Cache-Control
headers for these file types for a better experience:
[[headers]]
for = "*.md"
[headers.values]
Cache-Control = "max-age=3600,public,must-revalidate"
Content-Type = "text/x-markdown; charset=utf-8"
[[headers]]
for = "*.txt"
[headers.values]
Cache-Control = "max-age=3600,public,must-revalidate"
Content-Type = "text/plain; charset=utf-8"
Custom Descriptions for Context
To provide more context about each page linked in the /llms.txt
file, I first tried to utilize the page’s description, and if that didn’t exist, utilize an excerpt from the beginning of the page instead.
I quickly realized though that this doesn’t often provide the best possible context for the language models. After some tweaking, I ended up creating a custom Front Matter variable called llms
:
---
llms: "This article explains what CSS View Transitions are
and how you can enable them for any website today."
---
For each page on the website, this variable gets populated with more specific information about the content. Eventually, it gets injected into the /llms.txt
file after each Markdown link that is listed, like this:
## Docs
- [Figma MCP Server](https://arielsalminen.com/2025/figma-mcp-server.md): This article explains what the Figma MCP Server is and how it helps LLMs with design-informed code generation.
- [Introducing Brands for Nord Design System](https://arielsalminen.com/2025/introducing-brands-for-nord-design-system.md): This article introduces Nord Design System’s latest 4.0 version which ships with a completely reimagined theming architecture.
- [Modern Way to Center Elements with CSS](https://arielsalminen.com/2025/modern-way-to-center-elements-with-css.md): This article explains how to center elements with CSS using only two lines, display: grid; and place-self: center;.
Complete LLMS Template
This is what the complete llms.njk
template looks like at the time of writing this article:
---
permalink: llms.txt
eleventyExcludeFromCollections: true
---
# Ariel Salminen
> Ariel Salminen is a Design Systems Architect from Helsinki, Finland with 20 years of experience helping companies build tools for the web platform.
Important notes:
- Ariel Salminen has an extensive experience working on the web platform both as a designer and a developer. She often likes to describe that her job, in a design systems team, is about bridging the gap between designers, developers, and other disciplines in the company and that’s also where her greatest strengths lie.
- Instead of working in silos, Ariel Salminen believes in a more collaborative process where we sketch our ideas in code or work closely together with the developers to achieve that.
- Ariel Salminen is a systems thinker; designing for the whole rather than the individual parts. As an architect, she collaborates with design, product and engineering teams on the tactical and strategic direction of a design system and helps her clients set up the right tooling, processes and teams — all the way down to designing and developing complete design system platforms for them.
- Ariel Salminen is based in Helsinki, Finland but is available for both local and remote design systems work around the world.
## Main content{{"\n"}}
{%- for page in collections.content %}
- [{{ page.data.title | safe }}]{% if page.data.llmLink %}({{ page.data.llmLink }}){% else %}(https://arielsalminen.com{{ page.url }}){% endif %}{% if page.data.llms %}: {{ page.data.llms | safe }}{% endif %}
{%- endfor %}
## Supporting content{{"\n"}}
{%- for page in collections.addons %}
- [{{ page.data.title | safe }}]{% if page.data.llmLink %}({{ page.data.llmLink }}){% else %}(https://arielsalminen.com{{ page.url }}){% endif %}{% if page.data.llms %}: {{ page.data.llms | safe }}{% endif %}
{%- endfor %}
## Docs{{"\n"}}
{%- for page in collections.post | reverse %}
- [{{ page.data.title | safe }}](https://arielsalminen.com{{ page.url | replace(r/.$/, ".md") }}){% if page.data.llms %}: {{ page.data.llms | safe }}{% endif %}
{%- endfor %}
## Optional
- [Testimonials](https://arielsalminen.com/#testimonials): Ariel Salminen’s clients and past colleagues share their experiences working with her.
- [Trusted by](https://arielsalminen.com/#clients): Companies that trust Ariel Salminen’s work.
- [Recent work](https://arielsalminen.com/#work): Ariel Salminen’s recent projects and achievements.
- [Resume](https://arielsalminen.com/resume.pdf): Ariel Salminen’s résumé that contains a summary of relevant job experience and education.
…And here’s the final output: https://arielsalminen.com/llms.txt
Conclusion
I’m quite happy how simple Eleventy makes generating the llms.txt. I also tested setting up an MCP Server to directly interact with the data using tools such as Cursor and Claude. llms.txt
seemed to significantly improve the accuracy of the replies and contextual suggestions.
I also noticed that two weeks after adding this feature, the rankings and displayed meta data in the Google Search improved significantly for my website. Could be a coincidence, but the timing makes me suspicious.
Ultimately, I can see how the llms.txt
standard can be beneficial in the context of a large documentation website such as the one we’ve built for Nord Design System (especially if the proposed standard gets more widely adopted).
Further Reading
- How we think about writing for robots with llms.txt
- LLMs.txt to help LLMs grok your content
- MCP LLMS-TXT Documentation Server
- llmstxt.org
- llmstxt.site
This content originally appeared on Ariel Salminen and was authored by Ariel Salminen