Przejdź do treści

Plik llms.txt w Next.js i Astro: wdrożenie i format

Jak wdrożyć llms.txt w Next.js i Astro? Format pliku, przykłady route handlerów, llms-full.txt, robots.txt i filtrowanie szkiców i noindex.

Maciej Sala

Founder StriveLab

11 min czytaniaAktualizacja

Czym jest llms.txt i do czego służy?

Plik llms.txt to propozycja standardu opisana na llmstxt.org, która zakłada umieszczenie w głównej ścieżce witryny pliku /llms.txt. Jego zadaniem jest dostarczenie modelom językowym pomocnej informacji w momencie wnioskowania (). Twórcy propozycji wyszli z konkretnej obserwacji. Modele coraz częściej korzystają z treści internetowych, ale ich nie mieszczą całych, rozbudowanych serwisów. Konwersja HTML-a z nawigacją, reklamami i JavaScriptem na czysty tekst może być trudna i nieprecyzyjna. Zwięzły indeks pomaga narzędziu szybko znaleźć najważniejsze materiały, o ile dane narzędzie obsługuje tę konwencję.

Plik celowo używa Markdowna zamiast XML-a. Markdown to dzisiaj najszerzej i najłatwiej rozumiany format, a jednocześnie wystarczająco rygorystyczny, by parsowały go standardowe narzędzia programistyczne.

Warto też rozróżnić format bazowy od konwencji tworzonych przez integracje. llms.txt jest wyselekcjonowanym indeksem z linkami do najważniejszych materiałów. Część narzędzi generuje również llms-full.txt z pełną treścią oraz llms-small.txt z wersją skróconą. Te dwie nazwy nie należą do podstawowej propozycji i ich dokładna zawartość zależy od użytego generatora. Sama propozycja rekomenduje także udostępnianie czystych wersji Markdown poszczególnych stron.

llms.txt a robots.txt: czym się różnią?

robots.txt i llms.txt to dwa zupełnie różne rozwiązania, które mają odmienne cele. Automatyczne crawlery wyszukiwarek systematycznie skanują witryny, wracają w poszukiwaniu aktualizacji i zazwyczaj respektują reguły robots.txt, a pozyskane dane zasilają indeks wykorzystywany do prezentowania wyników. Systemy AI nie działają jednak według jednego schematu: mogą korzystać z wcześniej zbudowanego indeksu, danych treningowych albo pobierać stronę dynamicznie, dopiero po zadaniu pytania przez użytkownika. Tylko ten ostatni przypadek przypomina krótką wizytę agenta działającego w ograniczonym oknie kontekstowym, dlatego nie należy utożsamiać każdego bota AI z dostępem do sieci w czasie inferencji.

Zestawienie pokazuje to najlepiej:

Aspektrobots.txtllms.txt
AdresatCrawlery, które respektują Robots ExclusionNarzędzia obsługujące konwencję llms.txt
Moment użyciaPrzed automatycznym lub ręcznym pobraniemZależny od implementacji narzędzia
FormatDyrektywy User-agent i DisallowMarkdown
CelZarządzanie dostępem crawlerówWyselekcjonowany opis i lista zasobów
EgzekwowanieDobrowolne, zależne od crawleraBrak mechanizmu kontroli dostępu

Najważniejsze ograniczenie trzeba postawić wprost. Stan na październik 2026: główne systemy AI nie dają publicznej gwarancji powszechnej obsługi tego pliku, a Google Search nie wykorzystuje go jako specjalnego sygnału widoczności. Google może odkryć, pobrać i zaindeksować plik jak inny zasób, co nie oznacza obsługi konwencji llms.txt. Lighthouse sprawdza /llms.txt w eksperymentalnej kategorii Przeglądanie Agentowe. Audyt nie wymaga jednak utworzenia pliku. Odpowiedź 404 daje wynik N/A, a problem jest zgłaszany wtedy, gdy próba pobrania kończy się błędem serwera.

robots.txt pozwala deklarować reguły dla botów, które zdecydowały się je respektować. Trzeba jednak rozróżnić ich cele. OAI-SearchBot odpowiada za ChatGPT Search, a GPTBot za dane, które mogą zostać wykorzystane do treningu. Anthropic analogicznie rozdziela Claude-SearchBot, Claude-User i treningowy ClaudeBot. Google-Extended jest tokenem kontrolnym dotyczącym treningu Gemini i ugruntowania odpowiedzi w źródłach (ang. grounding), a nie osobnym crawlerem widocznym w logach. Pobrania inicjowane przez użytkownika mogą mieć inne zasady. OpenAI zaznacza na przykład, że w przypadku ChatGPT-User reguły robots.txt mogą nie mieć zastosowania.

Dlaczego mimo to warto rozważyć wdrożenie? W serwisie z uporządkowaną warstwą treści koszt może być niewielki, a plik może pełnić funkcję eksportu dla narzędzi, które świadomie go obsługują. Nie jest to jednak obowiązkowy element każdej witryny. Najpierw zadbaj o publiczny HTML, dostępność dla robotów, sitemapę, poprawne metadane i zasady dostępu. llms.txt traktuj jako eksperyment lub wygodny indeks, a nie jako substytut tych fundamentów.

llms.txt może wskazać narzędziu, co warto przeczytać. robots.txt deklaruje zasady dostępu dla crawlerów, które go respektują.

Format llms.txt: poprawna struktura pliku

Propozycja określa kolejność elementów, jeśli zdecydujesz się ich użyć. Jedynym wymaganym elementem jest H1 z nazwą projektu lub witryny. Najbardziej rozpoznawalna lokalizacja to /llms.txt w katalogu głównym domeny, chociaż propozycja dopuszcza także podścieżkę. Plik powinien być zapisany w UTF-8. Nazwa llm.txt nie odpowiada przyjętej konwencji.

Propozycja przewiduje następującą strukturę i kolejność:

  1. H1 z nazwą projektu lub witryny. To jedyny obowiązkowy element.
  2. Cytat blokowy (>) z krótkim podsumowaniem, zawierającym kluczowe informacje potrzebne do zrozumienia reszty pliku.
  3. Zero lub więcej sekcji Markdown zawierających dodatkowy kontekst, ale bez nagłówków.
  4. Sekcje z linkami oznaczone nagłówkami H2, gdzie każdy link ma format [Tytuł strony](URL): krótki opis.
  5. Opcjonalna sekcja ## Optional, zwyczajowo przeznaczona na materiały drugorzędne. W wersji v2 z sierpnia 2026 roku nagłówek ten nie narzuca narzędziom specjalnego sposobu pomijania treści.

Elementy od drugiego do piątego są opcjonalne. Dwukropek i opis po linku również nie są wymagane.

Minimalny, poprawny przykład wygląda tak:

Code
# Example Studio
 
> Example Studio to przykładowa firma specjalizująca się
> w aplikacjach React, Next.js i Astro oraz w doradztwie produktowym.
 
Kluczowe informacje o ofercie i realizacjach studia.
 
## Services
 
- [Tworzenie stron w Astro](https://example.com/uslugi/astro/): Szybkie, statyczne witryny zorientowane na treść.
- [Aplikacje Next.js](https://example.com/uslugi/next-js/): Aplikacje React renderowane po stronie serwera.
- [Konsultacje product management](https://example.com/uslugi/konsultacje/): Wsparcie w planowaniu i rozwoju produktu cyfrowego.
 
## Blog
 
- [Przewodnik po llms.txt](https://example.com/blog/plik-llms-txt/): Jak wdrożyć standard w Next.js i Astro.
 
## Optional
 
- [Polityka prywatności](https://example.com/privacy-policy/): Dokument prawny.
  • Tylko treści przeznaczone do publicznego eksportu. Zawsze odfiltruj szkice i materiały prywatne. Jeśli indeks ma odpowiadać sitemapie, pomiń także noindex i duplikaty.

  • Tylko adresy kanoniczne. Każdy link powinien prowadzić do głównej wersji strony, bez duplikatów.

  • Świadomy dobór zamiast pełnego eksportu. Bardzo długa lista utrudnia wykorzystanie pliku w ograniczonym oknie kontekstowym i osłabia jego funkcję wyselekcjonowanego indeksu. Lepsza jest mapa najważniejszych stron zbiorczych niż kompletna inwentaryzacja serwisu.

Jak wdrożyć llms.txt w Astro?

Astro daje tu dwie ścieżki, a wybór między nimi zależy od tego, czy chcesz plik statyczny, czy generowany dynamicznie z kolekcji treści.

Astro: statyczny llms.txt w katalogu public/

Zawartość katalogu public/ jest kopiowana do katalogu wynikowego bez przetwarzania. Dla małego serwisu bez automatyzacji wystarczy ręcznie utworzyć public/llms.txt i takie rozwiązanie jest proste, choć wymaga ręcznej aktualizacji.

Astro: endpoint llms.txt generowany z Content Collections

Dla bloga czy dokumentacji generuj plik dynamicznie z Content Collections. Tworzysz plik src/pages/llms.txt.ts:

Code
import { getCollection } from 'astro:content'
import type { APIRoute } from 'astro'
 
export const prerender = true
 
function markdownInline(value: string) {
  return value
    .replace(/\s+/g, ' ')
    .replace(/([\\[\]])/g, '\\$1')
    .trim()
}
 
export const GET: APIRoute = async ({ site }) => {
  if (!site) {
    throw new Error('Ustaw site w astro.config.mjs')
  }
 
  const posts = await getCollection(
    'blog',
    ({ data }) => !data.draft && !data.noindex,
  )
 
  const body = `# Example Blog
 
> Artykuły o frontendzie: React, Next.js, Astro, TypeScript oraz SEO/GEO.
 
## Articles
 
${posts
  .map((post) => {
    const url = new URL(`/blog/${post.id}/`, site).href
    return `- [${markdownInline(post.data.title)}](${url}): ${markdownInline(post.data.description)}`
  })
  .join('\n')}
`
 
  return new Response(body, {
    headers: { 'Content-Type': 'text/markdown; charset=utf-8' },
  })
}

export const prerender = true gwarantuje utworzenie pliku podczas budowania także wtedy, gdy projekt używa adaptera i trybu server. Dzięki temu endpoint nie wykonuje zapytań przy każdym żądaniu. Obiekt site z konfiguracji służy do budowy bezwzględnych URL-i. Funkcja markdownInline() usuwa nowe linie i zabezpiecza znaki, które mogłyby uszkodzić generowaną listę.

Nie dodawaj /llms.txt ręcznie do customPages w @astrojs/sitemap. Google Search ignoruje ten format jako specjalny sygnał, a sitemapę warto ograniczyć do kanonicznych treści przeznaczonych do indeksowania.

Astro: gotowa integracja do llms.txt

Jeśli nie chcesz pisać generatora od zera, możesz sprawdzić integracje astro-llms-generate albo @4hse/astro-llms-txt. Ich zakres i nazwy generowanych plików różnią się między wersjami, dlatego przed wdrożeniem sprawdź dokumentację oraz aktywność projektu. Dla witryn opartych na Starlight dostępny jest aktywnie rozwijany starlight-llms-txt. Pliki llms-small.txt i llms-full.txt są konwencjami tych narzędzi, a nie obowiązkowymi elementami bazowej propozycji.

Generowanie llms-full.txt w Astro

Jeśli wybrane narzędzie oczekuje jednego pliku z pełną treścią, można udostępnić opcjonalny endpoint llms-full.txt. Ten wariant nie należy do podstawowego formatu, więc nie ma gwarancji jego automatycznego wykrycia. W Astro wystarczy utworzyć endpoint src/pages/llms-full.txt.ts, który osadza pełne body każdego wpisu:

Code
import { getCollection } from 'astro:content'
import type { APIRoute } from 'astro'
 
export const prerender = true
 
export const GET: APIRoute = async ({ site }) => {
  if (!site) {
    throw new Error('Ustaw site w astro.config.mjs')
  }
 
  const posts = await getCollection(
    'blog',
    ({ data }) => !data.draft && !data.noindex,
  )
 
  // Kopiujemy tablicę, aby nie mutować wyniku getCollection().
  const sorted = [...posts].sort(
    (a, b) =>
      new Date(b.data.datePublished).valueOf() -
      new Date(a.data.datePublished).valueOf(),
  )
 
  const sections = sorted.map((post) => {
    const url = new URL(`/blog/${post.id}/`, site).href
    if (typeof post.body !== 'string') {
      throw new Error(`Brak treści wpisu ${post.id}; sprawdź loader i retainBody`)
    }
    const content = post.body.trim()
    return `## ${post.data.title}
 
Źródło: ${url}
 
${content}`
  })
 
  const body = `# StriveLab Blog, pełna treść
 
> Kompletny eksport artykułów dla modeli AI: React, Next.js, Astro, TypeScript, SEO/GEO.
 
${sections.join('\n\n')}
`
 
  return new Response(body, {
    headers: { 'Content-Type': 'text/markdown; charset=utf-8' },
  })
}

W Astro 5 i 6 wpis zwracany przez getCollection() ma pole body typu string | undefined. Dla wbudowanego glob loadera zawiera ono surowy Markdown lub MDX, chyba że ustawisz retainBody: false (opcja dostępna od Astro 5.17). Przykład przerywa budowanie przy braku body, żeby pełny eksport nie zastępował artykułów ich opisami. W takim przypadku zachowaj treść w loaderze lub pobierz ją ze źródła. Funkcja render(post) nie zwraca czystego tekstu. Zwraca komponent Astro, nagłówki i frontmatter zmodyfikowany przez wtyczki. Jeśli wpisy MDX zawierają importy, JSX albo niestandardowe komponenty, surowe body nadal wymaga transformacji przed udostępnieniem jako zwykły Markdown. Przy dużych blogach kontroluj rozmiar odpowiedzi i rozważ podział eksportu według sekcji.

Astro: filtrowanie noindex i szkiców w llms.txt

Propozycja llms.txt nie wymaga filtrowania noindex. Jest to jednak rozsądna polityka, jeśli plik ma odzwierciedlać publiczną i indeksowalną część serwisu. Szkice i treści prywatne należy odfiltrować zawsze. W Astro możesz wykorzystać pola draft, noindex i unlisted ze schematu kolekcji:

Code
import { getCollection } from 'astro:content'
import type { APIRoute } from 'astro'
 
export const prerender = true
 
function hasOwnCanonical(pageUrl: URL, canonicalURL?: string) {
  if (canonicalURL === undefined) return true
  try {
    if (!canonicalURL.trim()) return false
    const canonical = new URL(canonicalURL, pageUrl)
    canonical.hash = ''
    return canonical.href === pageUrl.href
  } catch {
    return false
  }
}
 
export const GET: APIRoute = async ({ site }) => {
  if (!site) {
    throw new Error('Ustaw site w astro.config.mjs')
  }
 
  const posts = await getCollection('blog', ({ id, data }) => {
    if (data.draft) return false
    if (data.noindex) return false
    if (data.unlisted) return false
    const pageUrl = new URL(`/blog/${id}/`, site)
    if (!hasOwnCanonical(pageUrl, data.canonicalURL)) return false
    return true
  })
 
  const body = `# Example Blog
 
> Artykuły o frontendzie: React, Next.js, Astro, TypeScript oraz SEO/GEO.
 
## Articles
 
${posts
  .map(
    (post) =>
      `- [${post.data.title}](${new URL(`/blog/${post.id}/`, site)}): ${post.data.description}`,
  )
  .join('\n')}
`
 
  return new Response(body, {
    headers: { 'Content-Type': 'text/markdown; charset=utf-8' },
  })
}

Filtr porównuje pełny adres wpisu z adresem kanonicznym, więc pomija także kopie wskazujące inną stronę w tej samej domenie. Względny adres kanoniczny rozwiązuje względem adresu wpisu, a fragment po # pomija. Ścieżka i końcowy ukośnik muszą odpowiadać faktycznej konfiguracji routingu; przykład zakłada adresy /blog/{id}/. Brak pola canonicalURL oznacza tu domyślnie własny adres wpisu.

Najlepiej przenieść ten predykat do wspólnego modułu używanego przez listę wpisów, sitemapę i generator llms.txt. Pamiętaj jednak, że noindex i reguły robots.txt nie chronią poufnych danych. Plik dostępny publicznie może zostać pobrany przez użytkownika lub bota, który nie respektuje tych deklaracji.

Jak wdrożyć llms.txt w Next.js App Router?

W Next.js (App Router) najczystszym podejściem jest . Tworzysz plik app/llms.txt/route.ts:

Code
import { getAllPosts } from '@/lib/posts'
 
export const dynamic = 'force-static'
 
function markdownInline(value: string) {
  return value
    .replace(/\s+/g, ' ')
    .replace(/([\\[\]])/g, '\\$1')
    .trim()
}
 
export async function GET() {
  const posts = (await getAllPosts()).filter(
    (post) => !post.draft && !post.noindex,
  )
  const baseUrl = 'https://example.com'
 
  const body = `# Example Studio
 
> Przykładowe studio frontendowe: React, Next.js, Astro i doradztwo produktowe.
 
## Blog
 
${posts
  .map((post) => {
    const url = new URL(`/blog/${post.slug}`, baseUrl).href
    return `- [${markdownInline(post.title)}](${url}): ${markdownInline(post.description)}`
  })
  .join('\n')}
`
 
  return new Response(body, {
    headers: { 'Content-Type': 'text/markdown; charset=utf-8' },
  })
}

W klasycznym modelu cache Next.js opcja włącza prerenderowanie i cache dla Route Handlera GET, który od Next.js 15 domyślnie nie jest cache’owany. Przykłady z tą opcją zakładają wyłączone cacheComponents. Jeśli projekt Next.js 16 ma włączone cacheComponents, usuń konfigurację dynamic i zastosuj model cache odpowiedni dla pobieranych danych. Dyrektywy use cache nie można umieścić bezpośrednio w ciele GET(); cache’owaną operację trzeba wydzielić do funkcji pomocniczej, w której można też ustawić czas ważności przez cacheLife. Sprawdź ustawienia projektu przed skopiowaniem przykładu.

Jeśli wolisz statyczny plik bez logiki, w Next.js wystarczy umieścić llms.txt w katalogu public/. Tak jak w Astro będzie serwowany z katalogu głównego domeny.

Generowanie llms-full.txt w Next.js

Analogicznie do głównego indeksu można utworzyć endpoint app/llms-full.txt/route.ts, który zamiast samych odnośników zwraca pełną treść artykułów. Poniższy przykład zakłada, że warstwa danych @/lib/posts dostarcza czysty Markdown w polu content. W przypadku źródeł MDX zawierających importy, elementy JSX lub wyrażenia JavaScript wymagana będzie ich wcześniejsza transformacja do zwykłego tekstu.

Code
import { getAllPosts } from '@/lib/posts'
 
export const dynamic = 'force-static'
 
export async function GET() {
  const posts = (await getAllPosts()).filter(
    (post) => !post.draft && !post.noindex,
  )
  const baseUrl = 'https://example.com'
 
  // Kopiujemy tablicę, aby nie mutować wyniku getAllPosts().
  const sorted = [...posts].sort(
    (a, b) => new Date(b.date).getTime() - new Date(a.date).getTime(),
  )
 
  const sections = sorted.map(
    (p) => `## ${p.title}
 
Źródło: ${baseUrl}/blog/${p.slug}
 
${p.content}`,
  )
 
  const body = `# Example Blog, pełna treść
 
> Kompletny eksport artykułów dla modeli AI: React, Next.js, Astro, TypeScript, SEO/GEO.
 
${sections.join('\n\n')}
`
 
  return new Response(body, {
    headers: { 'Content-Type': 'text/markdown; charset=utf-8' },
  })
}

Jeśli treść trzymasz w MDX i nie masz jej jeszcze jako surowego tekstu, pomocnik do odczytu wygląda tak:

Code
import { readFile } from 'node:fs/promises'
import path from 'node:path'
import matter from 'gray-matter'
 
export async function getPostRawContent(slug: string): Promise<string> {
  if (!/^[a-z0-9-]+$/i.test(slug)) {
    throw new Error('Nieprawidłowy slug')
  }
 
  const filePath = path.join(process.cwd(), 'content', 'blog', `${slug}.mdx`)
  const raw = await readFile(filePath, 'utf-8')
  // Odcinamy frontmatter; importy, JSX i wyrażenia MDX pozostają.
  const { content } = matter(raw)
  return content
}

Ten pomocnik zwraca surowy kod MDX bez nagłówka frontmatter. Należy pamiętać, że biblioteka gray-matter jedynie wyciąga metadane i nie przekształca komponentów ani wyrażeń w tekst widoczny na stronie. Przed przypisaniem wyniku do pola content w powyższym eksporcie należy zatem przetworzyć MDX na czysty Markdown, uwzględniając treść generowaną przez same komponenty – zwykłe usunięcie znaczników HTML/JSX mogłoby bowiem doprowadzić do utraty części artykułu.

Next.js: filtrowanie noindex i szkiców w llms.txt

W Next.js flagi sterujące indeksacją żyją zwykle we frontmatterze MDX (draft, noindex) i są mapowane na metadata.robots w funkcji generateMetadata poszczególnych stron. Żeby llms.txt nie rozjechał się z tym, co faktycznie pozwalasz indeksować, zastosuj ten sam filtr na liście wpisów:

Code
import { getAllPosts } from '@/lib/posts'
 
export const dynamic = 'force-static'
 
export async function GET() {
  const posts = await getAllPosts()
  const baseUrl = 'https://example.com'
 
  const indexable = posts.filter((p) => {
    if (p.draft) return false
    if (p.noindex) return false
 
    if (p.canonicalUrl !== undefined) {
      try {
        if (!p.canonicalUrl.trim()) return false
        const pageUrl = new URL(`/blog/${p.slug}`, baseUrl)
        const canonical = new URL(p.canonicalUrl, pageUrl)
        canonical.hash = ''
        if (canonical.href !== pageUrl.href) return false
      } catch {
        return false
      }
    }
 
    return true
  })
 
  const body = `# Example Studio
 
> Przykładowe studio frontendowe: React, Next.js, Astro i doradztwo produktowe.
 
## Blog
 
${indexable
  .map((p) => `- [${p.title}](${baseUrl}/blog/${p.slug}): ${p.description}`)
  .join('\n')}
`
 
  return new Response(body, {
    headers: { 'Content-Type': 'text/markdown; charset=utf-8' },
  })
}

Porównanie obejmuje pełny URL, więc adres kanoniczny wskazujący inną podstronę tej samej domeny również wyklucza wpis. Przykład zakłada adresy bez końcowego ukośnika; dostosuj ich budowę do routingu i używaj jej konsekwentnie w eksporcie oraz metadanych.

llms.txt i robots.txt w Next.js

Filtrowanie eksportu i reguły dostępu to dwa osobne tematy. W Next.js generujesz robots.txt przez app/robots.ts:

Code
import type { MetadataRoute } from 'next'
 
export default function robots(): MetadataRoute.Robots {
  return {
    rules: [{ userAgent: '*', allow: '/' }],
    sitemap: 'https://example.com/sitemap.xml',
  }
}

Reguły powinny odpowiadać celowi. Dla widoczności w ChatGPT Search znaczenie ma OAI-SearchBot, natomiast GPTBot dotyczy potencjalnego wykorzystania treści do treningu. Anthropic rozdziela Claude-SearchBot, Claude-User i treningowy ClaudeBot. Google-Extended jest tokenem kontrolnym dotyczącym treningu Gemini i ugruntowania odpowiedzi w źródłach. Nie jest osobnym crawlerem i nie wpływa na Google Search. Pamiętaj też, że robots.txt jest deklaracją respektowaną dobrowolnie przez boty, a nie techniczną blokadą dostępu.

Warto odróżnić dwie rozmowy, które często są wrzucane do jednego worka. Google Search nie wykorzystuje llms.txt jako specjalnego sygnału, także w AI Overviews i AI Mode. Lighthouse ma natomiast opcjonalny, eksperymentalny test dostępności tego pliku. Brak pliku nie jest błędem. Jeśli chcesz zrozumieć tę różnicę bez marketingowego szumu, omawiam ją osobno w tekście o Przeglądaniu Agentowym w PageSpeed Insights. Miejsce llms.txt w szerszej strategii widoczności w AI pokazuję w przewodniku po GEO.

Dlaczego Next.js i Astro dobrze nadają się do llms.txt?

Oba frameworki pozwalają wykorzystać istniejącą warstwę treści. Astro ma Content Collections i endpointy, a Next.js oferuje Route Handlers oraz prostą obsługę plików w public/. Dzięki temu generator może korzystać z tych samych danych i filtrów co lista wpisów oraz sitemapa.

  • Spójność. Generator uruchamiany podczas budowania odzwierciedla dane odczytane w tym momencie, jeśli używa tych samych filtrów co strony. Zmiany w CMS po zbudowaniu strony wymagają ponownego generowania i wdrożenia pliku albo skoordynowanej rewalidacji, jeśli korzystasz z cache Next.js.

  • Higiena architektury. Sam proces tworzenia llms.txt zmusza do przemyślenia, które treści naprawdę się liczą. Ta wartość istnieje, nawet gdyby żaden model nigdy pliku nie przeczytał.

  • Gotowość operacyjna. Plik możesz od razu wykorzystać wewnętrznie, wgrać do projektu w Claude albo umieścić w katalogu Cursora jako kontekst, gdy pracujesz z asystentem AI nad audytem czy strategią treści.

Audyt techniczny i optymalizacja pod kątem SEO i GEO.
Audyt techniczny SEO

Często zadawane pytania

Czy llms.txt zastępuje robots.txt?

Nie. robots.txt określa reguły dostępu dla crawlerów, ale nie jest mechanizmem blokowania indeksacji. llms.txt to opcjonalny, wyselekcjonowany indeks treści dla narzędzi, które zdecydowały się obsługiwać tę konwencję. Pliki mogą współistnieć, lecz żaden z nich nie zastępuje noindex, uwierzytelniania ani kontroli dostępu.

Czy główne modele AI już czytają llms.txt?

Stan na październik 2026: nie ma publicznej gwarancji powszechnej obsługi llms.txt przez najważniejsze wyszukiwarki i asystentów AI. Google Search nie używa go jako specjalnego sygnału, także w AI Overviews i AI Mode. Może jednak pobrać i zaindeksować plik jak zwykły zasób. Lighthouse ma eksperymentalny audyt llms.txt, ale brak pliku daje wynik N/A, a nie błąd.

Czy llms.txt poprawi moje pozycje w wynikach AI?

Nie ma dowodu, że sam llms.txt podnosi cytowalność albo pozycje w Google. Google Search nie traktuje go jako specjalnego sygnału. Plik może porządkować najważniejsze linki dla narzędzi, które świadomie obsługują tę konwencję, i może być przydatnym eksportem wewnętrznym. Wdrażaj go jako opcjonalny eksperyment, nie jako technikę rankingową.

Jaka jest różnica między llms.txt a llms-full.txt?

llms.txt jest opisanym w propozycji, wyselekcjonowanym indeksem treści. llms-full.txt to konwencja stosowana przez część integracji do eksportu pełnej treści w jednym pliku. Nie należy do podstawowego formatu llms.txt. Większości witryn, które chcą przetestować tę konwencję, wystarczy indeks.

Gdzie umieścić plik llms.txt?

Najbardziej rozpoznawalna lokalizacja to /llms.txt w katalogu głównym domeny, zapisany w UTF-8. Propozycja dopuszcza plik w podścieżce, ale nie należy zakładać jego automatycznego odkrycia. Nazwa llm.txt nie odpowiada przyjętej konwencji.

Jak nie dopuścić, by szkice i strony noindex trafiły do llms.txt?

Traktuj llms.txt jak publiczny zasób i zawsze odfiltruj szkice i treści prywatne. W sytuacji, kiedy plik ma odzwierciedlać publiczną część serwisu, możesz użyć tego samego predykatu co w sitemapie i metadanych, obejmującego draft, noindex oraz kanoniczność.

Czy llms.txt powinien być w sitemap.xml?

Nie. Sitemap powinna zawierać kanoniczne adresy treści przeznaczonych do indeksowania. Google Search nie używa llms.txt w specjalny sposób, dlatego ręczne dodawanie pliku do customPages nie daje korzyści dla widoczności.

O autorze

Maciej Sala

Maciej Sala — konsultant technologiczny produktów cyfrowych i web developer z bogatym doświadczeniem w marketingu internetowym oraz SEO. Na co dzień pracuje z Reactem, Next.js i TypeScriptem, a ostatnio także z Astro i narzędziami do automatyzacji procesów AI. Sprawnie łączy perspektywę produktową z praktycznym podejściem do kodu. Przez kilka lat był związany z branżą gier wideo jako project manager i game designer. Absolwent historii na Uniwersytecie Jagiellońskim oraz studiów podyplomowych z marketingu internetowego na AGH w Krakowie. Po godzinach trenuje na siłowni, maluje figurki i rozwija własne projekty.

Pomagam przekładać takie tematy na konkretne wdrożenia w frontendzie, SEO, analityce i procesie produktowym.

Skontaktuj się ze mną
LH.pl – Hosting Mango

Biblioteka wiedzy na temat Next.js

Czytaj dalej

Zobacz więcej wpisów
Techniczne SEO dla AI: robots.txt, boty i RAG

Zaplanowanie jednej, ogólnej reguły w robots.txt może niechcący odciąć Cię od wyszukiwarek AI, mimo że Twoim celem było jedynie zablokowanie treningu modeli na autorskich treściach. Z kolei otwarty dostęp na nic się nie przyda, jeśli robot zderzy się z pustym kodem HTML lub zaporą Cloudflare. W związku z powyższym techniczne SEO pod kątem AI zaczyna się od precyzyjnego rozpoznania roli danego bota, a kończy na weryfikacji faktycznej odpowiedzi serwera. Poniżej pokażę Ci, jak rozdzielić te kwestie i poprawnie skonfigurować reguły w Next.js.

Maciej Sala

Maciej Sala

Founder StriveLab

Audyt techniczny SEO: co obejmuje w 2026 roku?

To, że strona otwiera się w przeglądarce, nie oznacza jeszcze, że robot wyszukiwarki jest w stanie bez przeszkód pobrać jej treść, poprawnie ją zinterpretować i ostatecznie włączyć do indeksu. Audyt techniczny SEO służy właśnie do weryfikacji tych krytycznych warunków. Pozwala on zidentyfikować fundamenty wymagające naprawy i wyznaczyć właściwe priorytety, zanim przejdziemy do rozbudowy treści oraz pozyskiwania linków.

Maciej Sala

Maciej Sala

Founder StriveLab

Astro vs Next.js w 2026: porównanie frameworków

Astro czy Next.js? Wybór frameworka musi być dokładnie przemyślany, zanim pojawi się pierwszy commit. Jeśli stoisz przed takim właśnie wyborem, w tym artykule staram się wykazać, w jakich obszarach najlepiej sprawdza się Astro , a w jakich będzie dominował Next.js .

Maciej Sala

Maciej Sala

Founder StriveLab

LH.pl – Cloud Server 1C4G