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 draftów/noindex.

Maciej Sala

Founder StriveLab

9 min czytaniaOpublikowano 28 maja 2026 (Aktualizacja 24 lipca 2026)

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

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 kuratorowanym 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 nie są wersjami tego samego rozwiązania. Mają inne cele i inną dojrzałość.

Automatyczne crawlery wyszukiwarek systematycznie skanują witryny, wracają w poszukiwaniu zmian i zwykle respektują reguły robots.txt. Pozyskane informacje mogą zasilać indeks używany później do prezentowania wyników.

Systemy AI nie działają według jednego modelu. Mogą korzystać z wcześniej zbudowanego indeksu, danych treningowych albo pobrać stronę po pytaniu użytkownika. Dopiero ostatni wariant przypomina krótką wizytę agenta pracującego w ograniczonym oknie kontekstowym. Z tego powodu nie należy utożsamiać wszystkich botów AI z dostępem 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 konkretnego toola
FormatDyrektywy User-agent i DisallowMarkdown
CelZarządzanie dostępem crawlerówKuratorowany opis i lista zasobów
EgzekwowanieDobrowolne, zależne od crawleraBrak mechanizmu kontroli dostępu

Najważniejsze ograniczenie trzeba postawić wprost. Stan na lipiec 2026: główne systemy AI nie dają publicznej gwarancji powszechnej obsługi tego pliku, a Google Search wyraźnie informuje, że go ignoruje. 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 groundingu, 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, crawlability, 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. Blockquote (>) 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 dla treści drugorzędnych, które model może pominąć przy ograniczonym kontekście.

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ę kuratorowanego indeksu. Lepsza jest mapa najważniejszych hubów niż kompletna inwentaryzacja serwisu.

Jak wdrożyć llms.txt w Astro?

Astro daje tu dwie ścieżki, a jej wybór 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 outputu builda bez przetwarzania. Dla małego serwisu bez automatyzacji wystarczy ręcznie utworzyć public/llms.txt. Rozwiązanie jest proste, ale wymaga ręcznej aktualizacji i z czasem może rozjechać się z treścią.

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 buildu 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żesz udostępnić umowny llms-full.txt. Nie jest to część podstawowego formatu i nie ma gwarancji automatycznego wykrycia. W Astro utwórz endpoint src/pages/llms-full.txt.ts, który wstawia 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
    const content = post.body?.trim() || post.data.description
    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. Funkcja render(post) nie zwraca czystego tekstu. Zwraca komponent Astro, nagłówki i frontmatter zmodyfikowany przez pluginy. 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 draftó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
 
const SITE_ORIGIN = new URL('https://example.com').origin
 
function hasOwnCanonical(canonicalURL?: string) {
  if (!canonicalURL) return true
 
  try {
    return new URL(canonicalURL, SITE_ORIGIN).origin === SITE_ORIGIN
  } 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', ({ data }) => {
    if (data.draft) return false
    if (data.noindex) return false
    if (data.unlisted) return false
    if (!hasOwnCanonical(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' },
  })
}

Najlepiej przenieść ten predykat do wspólnego modułu używanego przez listing, 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 domyślnie nie jest cache’owany. Jeśli projekt Next.js 16 ma włączone cacheComponents, konfiguracje segmentu takie jak dynamic są zastępowane przez dyrektywę use cache i powiązane API. 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 roota.

Generowanie llms-full.txt w Next.js

Analogicznie do indeksu możesz utworzyć umowny endpoint app/llms-full.txt/route.ts. Zamiast samego linku wstawia pełną treść wpisu. Poniższy przykład zakłada, że warstwa danych @/lib/posts zwraca surowy Markdown w polu content. Jeśli trzymasz treść w plikach MDX, możesz odczytać ją funkcją pomocniczą:

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 stringa, 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, zostawiamy samą treść Markdown.
  const { content } = matter(raw)
  return content
}

Next.js: filtrowanie noindex i draftó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) {
      try {
        const canonical = new URL(p.canonicalUrl, baseUrl)
        if (canonical.origin !== new URL(baseUrl).origin) 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' },
  })
}

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 groundingu. 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 ignoruje llms.txt 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.

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 listing oraz sitemap.

  • Spójność. Plik aktualizuje się automatycznie przy każdym buildzie, więc nigdy nie rozjedzie się z faktyczną treścią.

  • 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, kuratorowany 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 lipiec 2026: nie ma publicznego potwierdzenia powszechnej obsługi llms.txt przez najważniejsze wyszukiwarki i asystentów AI. Google Search wprost informuje, że ignoruje ten plik także w AI Overviews i AI Mode. 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 go ignoruje. 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, kuratorowanym 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. Zawsze odfiltruj szkice i treści prywatne. Jeśli plik ma odzwierciedlać publiczną część serwisu, możesz użyć tego samego predykatu co w sitemapie i metadanych, obejmującego draft, noindex oraz kanoniczność. Jest to polityka publikacyjna, a nie wymaganie specyfikacji.

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ą

Biblioteka wiedzy na temat Next.js

Czytaj dalej

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

Przez dwadzieścia lat techniczne SEO oznaczało jedno: ułatwić życie Googlebotowi . W 2026 roku po Twojej stronie chodzi cała menażeria botów AI: GPTBot, ClaudeBot, PerplexityBot, Google-Extended i kilkanaście innych. Każdy z nich ma inny cel, od trenowania modelu, po indeksację pod wyszukiwanie AI czy pobranie strony na żądanie użytkownika. W związku z powyższym, wpółczesne techniczne SEO ewoluowało w kontrolę nad tym, kto i po co sięga po Twoją treść oraz dostępność tej treści dla systemów, które realnie kierują do Ciebie ruch i cytowania.

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

Next.js Sitemap i robots.txt — automatyczna generacja z App Routera

Next.js App Router oferuje natywne API bez zewnętrznych bibliotek do generowania obu plików. W tym artykule pokazuję, jak zrobić to konwencjami app/sitemap.ts i app/robots.ts , kiedy wystarczy natywne rozwiązanie, a kiedy warto sięgnąć po next-sitemap .

Maciej Sala

Maciej Sala

Founder StriveLab