diff --git a/docs/app/blog/_components/blog-list.tsx b/docs/app/blog/_components/blog-list.tsx
index 26685accc2..1b1ef48aa3 100644
--- a/docs/app/blog/_components/blog-list.tsx
+++ b/docs/app/blog/_components/blog-list.tsx
@@ -1,4 +1,5 @@
import { DiscordLogoIcon } from "@radix-ui/react-icons";
+import { RssIcon } from "lucide-react";
import Image from "next/image";
import Link from "next/link";
import { formatBlogDate } from "@/lib/blog";
@@ -18,7 +19,7 @@ export async function BlogPage() {
-
+
Blogs
@@ -55,6 +56,11 @@ export async function BlogPage() {
BETTER-AUTH.
+
+
+ RSS
+
+
diff --git a/docs/app/blog/rss.xml/route.ts b/docs/app/blog/rss.xml/route.ts
new file mode 100644
index 0000000000..2c7245cdf9
--- /dev/null
+++ b/docs/app/blog/rss.xml/route.ts
@@ -0,0 +1,11 @@
+import { getRSS } from "@/lib/rss";
+
+export const revalidate = false;
+
+export function GET() {
+ return new Response(getRSS(), {
+ headers: {
+ "Content-Type": "application/rss+xml; charset=utf-8",
+ },
+ });
+}
diff --git a/docs/lib/metadata.ts b/docs/lib/metadata.ts
index 35fa58cb3a..771bb6ccc6 100644
--- a/docs/lib/metadata.ts
+++ b/docs/lib/metadata.ts
@@ -19,6 +19,17 @@ export function createMetadata(override: Metadata): Metadata {
images: "https://better-auth.com/og.png",
...override.twitter,
},
+ alternates: {
+ types: {
+ "application/rss+xml": [
+ {
+ title: "Better Auth Blog",
+ url: "https://better-auth.com/blog/rss.xml",
+ },
+ ],
+ },
+ ...override.alternates,
+ },
};
}
diff --git a/docs/lib/rss.ts b/docs/lib/rss.ts
new file mode 100644
index 0000000000..b757f48ae1
--- /dev/null
+++ b/docs/lib/rss.ts
@@ -0,0 +1,43 @@
+import { Feed } from "feed";
+import { blogs } from "./source";
+import { baseUrl } from "./utils";
+
+export function getRSS() {
+ const feed = new Feed({
+ title: "Better Auth Blog",
+ description: "Latest updates, articles, and insights about Better Auth",
+ generator: "better-auth",
+ id: `${baseUrl}blog`,
+ link: `${baseUrl}blog`,
+ language: "en",
+ image: `${baseUrl}release-og/blogs.png`,
+ favicon: `${baseUrl}favicon/favicon-32x32.png`,
+ copyright: `All rights reserved ${new Date().getFullYear()}, Better Auth Inc.`,
+ });
+
+ for (const page of blogs.getPages()) {
+ const url = page.url.replace("blogs/", "blog/");
+
+ feed.addItem({
+ id: url,
+ title: page.data.title,
+ description: page.data.description,
+ image: page.data.image
+ ? `${baseUrl}${page.data.image.startsWith("/") ? page.data.image.slice(1) : page.data.image}`
+ : undefined,
+ link: `${baseUrl}${url.startsWith("/") ? url.slice(1) : url}`,
+ date: new Date(page.data.lastModified || page.data.date),
+ author: page.data.author
+ ? [
+ {
+ name: page.data.author.name,
+ avatar: page.data.author.avatar,
+ link: page.data.author.twitter,
+ },
+ ]
+ : [],
+ });
+ }
+
+ return feed.rss2();
+}
diff --git a/docs/package.json b/docs/package.json
index 86ce7f8acb..99c76f8682 100644
--- a/docs/package.json
+++ b/docs/package.json
@@ -56,6 +56,7 @@
"date-fns": "^4.1.0",
"dotenv": "^17.2.2",
"embla-carousel-react": "^8.6.0",
+ "feed": "^5.1.0",
"foxact": "^0.2.49",
"framer-motion": "^12.23.12",
"fumadocs-core": "15.8.3",
@@ -88,11 +89,11 @@
"recharts": "^3.1.2",
"rehype-highlight": "^7.0.2",
"remark": "^15.0.1",
- "resend": "^4.0.1",
"remark-gfm": "^4.0.1",
"remark-mdx": "^3.1.1",
"remark-rehype": "^11.1.2",
"remark-stringify": "^11.0.0",
+ "resend": "^4.0.1",
"shiki": "^3.13.0",
"sonner": "^2.0.7",
"tailwind-merge": "^3.3.1",
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index b689827cec..e3f54cdcf7 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -373,7 +373,7 @@ importers:
version: 12.23.12(react-dom@19.2.3(react@19.2.3))(react@19.2.3)
geist:
specifier: ^1.4.2
- version: 1.4.2(next@16.0.10(@babel/core@7.28.4)(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(sass@1.90.0))
+ version: 1.4.2(next@16.0.10(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(sass@1.90.0))
input-otp:
specifier: ^1.4.2
version: 1.4.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3)
@@ -485,7 +485,7 @@ importers:
version: 2.1.1
geist:
specifier: ^1.4.2
- version: 1.4.2(next@16.0.10(@babel/core@7.28.4)(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(sass@1.90.0))
+ version: 1.4.2(next@16.0.10(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(sass@1.90.0))
lucide-react:
specifier: ^0.542.0
version: 0.542.0(react@19.2.3)
@@ -701,6 +701,9 @@ importers:
embla-carousel-react:
specifier: ^8.6.0
version: 8.6.0(react@19.2.3)
+ feed:
+ specifier: ^5.1.0
+ version: 5.1.0
foxact:
specifier: ^0.2.49
version: 0.2.49(react@19.2.3)
@@ -724,7 +727,7 @@ importers:
version: 15.8.3(@oramacloud/client@2.1.4)(@tanstack/react-router@1.139.7(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(@types/react-dom@19.2.2(@types/react@19.2.2))(@types/react@19.2.2)(algoliasearch@5.36.0)(lucide-react@0.542.0(react@19.2.3))(next@16.0.10(@babel/core@7.28.4)(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(sass@1.90.0))(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(tailwindcss@4.1.17)
geist:
specifier: ^1.4.2
- version: 1.4.2(next@16.0.10(@babel/core@7.28.4)(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(sass@1.90.0))
+ version: 1.4.2(next@16.0.10(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(sass@1.90.0))
gray-matter:
specifier: ^4.0.3
version: 4.0.3
@@ -9129,6 +9132,10 @@ packages:
fecha@4.2.3:
resolution: {integrity: sha512-OP2IUU6HeYKJi3i0z4A19kHMQoLVs4Hc+DPqqxI2h/DPZHTm/vjsfC6P0b4jCMy14XizLBqvndQ+UilD7707Jw==}
+ feed@5.1.0:
+ resolution: {integrity: sha512-qGNhgYygnefSkAHHrNHqC7p3R8J0/xQDS/cYUud8er/qD9EFGWyCdUDfULHTJQN1d3H3WprzVwMc9MfB4J50Wg==}
+ engines: {node: '>=20', pnpm: '>=10'}
+
fetch-blob@3.2.0:
resolution: {integrity: sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ==}
engines: {node: ^12.20 || >= 14.13}
@@ -14218,6 +14225,10 @@ packages:
xml-escape@1.1.0:
resolution: {integrity: sha512-B/T4sDK8Z6aUh/qNr7mjKAwwncIljFuUP+DO/D5hloYFj+90O88z8Wf7oSucZTHxBAsC1/CTP4rtx/x1Uf72Mg==}
+ xml-js@1.6.11:
+ resolution: {integrity: sha512-7rVi2KMfwfWFl+GpPg6m80IVMWXLRjO+PxTq7V2CDhoGak0wzYzFgUY2m4XJ47OGdXd8eLE8EmwfAmdjw7lC1g==}
+ hasBin: true
+
xml2js@0.6.0:
resolution: {integrity: sha512-eLTh0kA8uHceqesPqSE+VvO1CDDJWMwlQfB6LuN6T8w6MaDJ8Txm8P7s5cHD0miF0V+GGTZrDQfxPZQVsur33w==}
engines: {node: '>=4.0.0'}
@@ -16580,7 +16591,7 @@ snapshots:
postcss: 8.4.49
resolve-from: 5.0.0
optionalDependencies:
- expo: 54.0.21(@babel/core@7.28.4)(@expo/metro-runtime@6.1.2)(expo-router@6.0.14)(graphql@16.12.0)(react-native@0.81.5(@babel/core@7.28.4)(@react-native-community/cli@20.0.1(typescript@5.9.3))(@react-native/metro-config@0.81.0(@babel/core@7.28.4))(@types/react@19.2.2)(react@19.2.3))(react@19.2.3)
+ expo: 54.0.21(@babel/core@7.28.4)(@expo/metro-runtime@6.1.2)(expo-router@6.0.14)(graphql@16.12.0)(react-native@0.80.2(@babel/core@7.28.4)(@react-native-community/cli@20.0.1(typescript@5.9.3))(@types/react@19.2.2)(react@19.2.3))(react@19.2.3)
transitivePeerDependencies:
- bufferutil
- supports-color
@@ -16665,7 +16676,7 @@ snapshots:
'@expo/json-file': 10.0.7
'@react-native/normalize-colors': 0.81.5
debug: 4.4.3
- expo: 54.0.21(@babel/core@7.28.4)(@expo/metro-runtime@6.1.2)(expo-router@6.0.14)(graphql@16.12.0)(react-native@0.81.5(@babel/core@7.28.4)(@react-native-community/cli@20.0.1(typescript@5.9.3))(@react-native/metro-config@0.81.0(@babel/core@7.28.4))(@types/react@19.2.2)(react@19.2.3))(react@19.2.3)
+ expo: 54.0.21(@babel/core@7.28.4)(@expo/metro-runtime@6.1.2)(expo-router@6.0.14)(graphql@16.12.0)(react-native@0.80.2(@babel/core@7.28.4)(@react-native-community/cli@20.0.1(typescript@5.9.3))(@types/react@19.2.2)(react@19.2.3))(react@19.2.3)
resolve-from: 5.0.0
semver: 7.7.3
xml2js: 0.6.0
@@ -18978,7 +18989,9 @@ snapshots:
metro-runtime: 0.83.3
transitivePeerDependencies:
- '@babel/core'
+ - bufferutil
- supports-color
+ - utf-8-validate
optional: true
'@react-native/normalize-colors@0.74.89': {}
@@ -20959,7 +20972,7 @@ snapshots:
resolve-from: 5.0.0
optionalDependencies:
'@babel/runtime': 7.28.4
- expo: 54.0.21(@babel/core@7.28.4)(@expo/metro-runtime@6.1.2)(expo-router@6.0.14)(graphql@16.12.0)(react-native@0.81.5(@babel/core@7.28.4)(@react-native-community/cli@20.0.1(typescript@5.9.3))(@react-native/metro-config@0.81.0(@babel/core@7.28.4))(@types/react@19.2.2)(react@19.2.3))(react@19.2.3)
+ expo: 54.0.21(@babel/core@7.28.4)(@expo/metro-runtime@6.1.2)(expo-router@6.0.14)(graphql@16.12.0)(react-native@0.80.2(@babel/core@7.28.4)(@react-native-community/cli@20.0.1(typescript@5.9.3))(@types/react@19.2.2)(react@19.2.3))(react@19.2.3)
transitivePeerDependencies:
- '@babel/core'
- supports-color
@@ -22589,7 +22602,7 @@ snapshots:
expo-keep-awake@15.0.7(expo@54.0.21)(react@19.2.3):
dependencies:
- expo: 54.0.21(@babel/core@7.28.4)(@expo/metro-runtime@6.1.2)(expo-router@6.0.14)(graphql@16.12.0)(react-native@0.81.5(@babel/core@7.28.4)(@react-native-community/cli@20.0.1(typescript@5.9.3))(@react-native/metro-config@0.81.0(@babel/core@7.28.4))(@types/react@19.2.2)(react@19.2.3))(react@19.2.3)
+ expo: 54.0.21(@babel/core@7.28.4)(@expo/metro-runtime@6.1.2)(expo-router@6.0.14)(graphql@16.12.0)(react-native@0.80.2(@babel/core@7.28.4)(@react-native-community/cli@20.0.1(typescript@5.9.3))(@types/react@19.2.2)(react@19.2.3))(react@19.2.3)
react: 19.2.3
expo-linking@7.1.7(expo@54.0.21)(react-native@0.80.2(@babel/core@7.28.4)(@react-native-community/cli@20.0.1(typescript@5.9.3))(@types/react@19.2.2)(react@19.2.3))(react@19.2.3):
@@ -22988,6 +23001,10 @@ snapshots:
fecha@4.2.3: {}
+ feed@5.1.0:
+ dependencies:
+ xml-js: 1.6.11
+
fetch-blob@3.2.0:
dependencies:
node-domexception: 1.0.0
@@ -23271,7 +23288,7 @@ snapshots:
function-bind@1.1.2: {}
- geist@1.4.2(next@16.0.10(@babel/core@7.28.4)(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(sass@1.90.0)):
+ geist@1.4.2(next@16.0.10(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(sass@1.90.0)):
dependencies:
next: 16.0.10(@babel/core@7.28.4)(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(sass@1.90.0)
@@ -29272,6 +29289,10 @@ snapshots:
xml-escape@1.1.0: {}
+ xml-js@1.6.11:
+ dependencies:
+ sax: 1.4.3
+
xml2js@0.6.0:
dependencies:
sax: 1.4.3