1import { themes as prismThemes } from 'prism-react-renderer'
2import type { Config } from '@docusaurus/types'
3import type * as Preset from '@docusaurus/preset-classic'
4
5import type * as OpenApiPlugin from 'docusaurus-plugin-openapi-docs'
6import type { Options as BlogOptions } from '@docusaurus/plugin-content-blog'
7import type { Options as PageOptions } from '@docusaurus/plugin-content-pages'
8
9import tailwindPlugin from './plugins/tailwind-config.cjs'
10import * as fs from 'fs'
11import * as path from 'path'
12
13// Load versions from versions.json if it exists (generated at build time)
14const versionsPath = path.join(__dirname, 'versions.json')
15const versions: string[] = fs.existsSync(versionsPath)
16 ? JSON.parse(fs.readFileSync(versionsPath, 'utf-8'))
17 : []
18
19// Build version configuration dynamically
20// Trunk docs (current) are "Next" at /docs/next
21// Highest version in versions.json (e.g., 1.11.x) is "Latest" at /docs (default)
22// Previous versions are at /docs/v1.10, etc.
23// Maintenance policy: latest + 1 previous minor versions are maintained
24const hasVersions = versions.length > 0
25
26// Extract major and minor version numbers from versions to determine ordering and maintenance status
27const getVersion = (v: string): { major: number; minor: number } => {
28 const match = v.match(/^(\d+)\.(\d+)/)
29 return match
30 ? { major: parseInt(match[1], 10), minor: parseInt(match[2], 10) }
31 : { major: 0, minor: 0 }
32}
33
34// Sort versions by semver (major desc, then minor desc)
35const sortedVersions = [...versions].sort((a, b) => {
36 const vA = getVersion(a)
37 const vB = getVersion(b)
38 if (vB.major !== vA.major) return vB.major - vA.major
39 return vB.minor - vA.minor
40})
41
42// Highest version is "latest", trunk (current) is "next"
43const latestVersion = sortedVersions[0] || null
44const latestVer = latestVersion ? getVersion(latestVersion) : { major: 0, minor: 0 }
45
46const docsVersionConfig = hasVersions
47 ? {
48 lastVersion: latestVersion!, // The stable release is the default
49 onlyIncludeVersions: [...versions, 'current'],
50 versions: {
51 current: {
52 label: 'Next',
53 path: 'next',
54 banner: 'unreleased' as const
55 },
56 ...Object.fromEntries(
57 versions.map((version) => {
58 const ver = getVersion(version)
59 const isLatest = version === latestVersion
60 // Versions within same major and latest minor - 1 are maintained (no banner)
61 const isMaintained =
62 ver.major > latestVer.major ||
63 (ver.major === latestVer.major && ver.minor >= latestVer.minor - 1)
64
65 return [
66 version,
67 {
68 label: isLatest
69 ? `Latest (v${version.replace('.x', '')})`
70 : `v${version.replace('.x', '')}`,
71 path: isLatest ? '' : `v${version.replace('.x', '')}`,
72 banner: isMaintained ? ('none' as const) : ('unmaintained' as const)
73 }
74 ]
75 })
76 )
77 }
78 }
79 : {
80 // No versions generated - use current docs only (for local dev)
81 lastVersion: 'current',
82 versions: {
83 current: {
84 label: 'Latest',
85 path: '',
86 banner: 'none' as const
87 }
88 },
89 onlyIncludeVersions: ['current']
90 }
91
92const config: Config = {
93 title: 'Spice.ai OSS',
94 tagline:
95 'A portable SQL query and AI compute engine, written in Rust, for data-grounded apps and agents.',
96 favicon: 'img/favicon.ico',
97
98 // Set the production url of your site here
99 url: 'https://spiceai.org',
100 // Set the /<baseUrl>/ pathname under which your site is served
101 // For GitHub pages deployment, it is often '/<projectName>/'
102 baseUrl: '/',
103
104 trailingSlash: false,
105
106 // GitHub pages deployment config.
107 // If you aren't using GitHub pages, you don't need these.
108 organizationName: 'spiceai', // Usually your GitHub org/user name.
109 projectName: 'docs', // Usually your repo name.
110
111 onBrokenAnchors: 'throw',
112 onBrokenLinks: 'throw',
113
114 markdown: {
115 mermaid: true,
116 hooks: {
117 onBrokenMarkdownLinks: 'throw'
118 }
119 },
120
121 // Even if you don't use internationalization, you can use this field to set
122 // useful metadata like html lang. For example, if your site is Chinese, you
123 // may want to replace "en" with "zh-Hans".
124 i18n: {
125 defaultLocale: 'en',
126 locales: ['en']
127 },
128
129 future: {
130 v4: {
131 removeLegacyPostBuildHeadAttribute: true // required
132 },
133 experimental_faster: true
134 },
135
136 presets: [
137 [
138 'classic',
139 {
140 docs: {
141 routeBasePath: '/docs',
142 path: 'docs',
143 sidebarPath: 'sidebars.ts',
144 onInlineTags: 'throw',
145 docItemComponent: '@theme/ApiItem',
146 editUrl: ({ versionDocsDirPath, docPath }) => {
147 return `https://github.com/spiceai/docs/edit/trunk/website/${versionDocsDirPath}/${docPath}`
148 },
149 ...docsVersionConfig
150 },
151 blog: {
152 path: 'blog',
153 showLastUpdateAuthor: true,
154 showLastUpdateTime: true,
155 onInlineTags: 'throw',
156 onUntruncatedBlogPosts: 'ignore',
157 editUrl: ({ locale, blogDirPath, blogPath }) => {
158 return `https://github.com/spiceai/docs/edit/trunk/website/${blogDirPath}/${blogPath}`
159 },
160 remarkPlugins: [],
161 postsPerPage: 5,
162 feedOptions: {
163 type: 'all',
164 description:
165 'Keep up to date with upcoming Spice.ai OSS releases and articles by following our feed!',
166 copyright: `Copyright © 2021-2026 Spice AI, Inc.`,
167 xslt: true
168 },
169 blogTitle: 'Spice.ai OSS blog',
170 blogDescription: 'Read blog posts about Spice.ai OSS from the team and community',
171 blogSidebarCount: 'ALL',
172 blogSidebarTitle: 'All Posts'
173 } satisfies BlogOptions,
174 pages: {
175 remarkPlugins: [],
176 showLastUpdateAuthor: true,
177 showLastUpdateTime: true
178 } satisfies PageOptions,
179 theme: {
180 customCss: ['./src/css/custom.css', './src/css/openapi.css', './src/css/preflight.css']
181 },
182 gtag: {
183 trackingID: 'G-SST0X6NS37',
184 anonymizeIP: true
185 },
186 sitemap: {
187 lastmod: 'date',
188 changefreq: 'weekly',
189 priority: 0.5,
190 ignorePatterns: ['/tags/**'],
191 filename: 'sitemap.xml'
192 }
193 } satisfies Preset.Options
194 ]
195 ],
196 themes: ['docusaurus-theme-openapi-docs', '@docusaurus/theme-mermaid'],
197 themeConfig: {
198 // SEO metadata configuration
199 metadata: [
200 {
201 name: 'keywords',
202 content:
203 'spice, spice.ai, sql query engine, ai compute engine, data federation, data acceleration, rag, retrieval augmented generation, arrow flight, datafusion, duckdb, rust, llm, openai compatible, mcp server'
204 },
205 { name: 'author', content: 'Spice AI, Inc.' },
206 { name: 'robots', content: 'index, follow' },
207 { property: 'og:type', content: 'website' },
208 { property: 'og:site_name', content: 'Spice.ai OSS' },
209 { property: 'og:image:width', content: '1200' },
210 { property: 'og:image:height', content: '630' },
211 { property: 'og:image:alt', content: 'Spice.ai - SQL Query and AI Compute Engine' },
212 { name: 'twitter:card', content: 'summary_large_image' },
213 { name: 'twitter:site', content: '@spice_ai' },
214 { name: 'twitter:creator', content: '@spice_ai' }
215 ],
216 announcementBar: {
217 content: '<a href="/releases/v2.0-rc.4">Spice.ai OSS v2.0-rc.4</a> is now available! 🚀',
218 backgroundColor: 'var(--announcement-bar-bg)',
219 textColor: 'var(--announcement-bar-text)',
220 isCloseable: true
221 },
222 navbar: {
223 title: 'Spice.ai OSS',
224 logo: {
225 alt: 'Spice.ai OSS logo',
226 src: 'img/logo.svg'
227 },
228 hideOnScroll: true,
229 items: [
230 {
231 type: 'doc',
232 position: 'left',
233 docId: 'index',
234 label: 'Docs'
235 },
236 {
237 type: 'docSidebar',
238 position: 'left',
239 sidebarId: 'api',
240 label: 'API'
241 },
242 { to: 'releases', label: 'Releases', position: 'left' },
243 {
244 label: 'Blog',
245 href: 'https://spice.ai/blog',
246 position: 'left'
247 },
248 { to: 'cookbook', label: 'Cookbook', position: 'left' },
249 { to: 'docs/reference/sql', label: 'SQL Reference', position: 'left' },
250 // Version dropdown is only shown when versions exist
251 ...(hasVersions
252 ? [
253 {
254 type: 'docsVersionDropdown' as const,
255 position: 'right' as const,
256 dropdownActiveClassDisabled: true
257 }
258 ]
259 : []),
260 {
261 label: 'Try Spice Cloud',
262 href: 'https://spice.ai/login',
263 position: 'right'
264 },
265 {
266 label: 'X',
267 href: 'https://x.com/spice_ai',
268 position: 'right'
269 },
270 {
271 label: 'Slack',
272 href: 'https://spice.ai/slack',
273 position: 'right'
274 },
275 {
276 label: 'YouTube',
277 href: 'https://www.youtube.com/@spiceai',
278 position: 'right'
279 },
280 {
281 href: 'https://github.com/spiceai/spiceai',
282 position: 'right',
283 className: 'header-github-link',
284 'aria-label': 'GitHub repository'
285 }
286 ]
287 },
288 footer: {
289 style: 'dark',
290 links: [
291 {
292 title: 'Docs',
293 items: [
294 {
295 label: 'Getting Started',
296 to: '/docs/getting-started'
297 },
298 {
299 label: 'API',
300 to: '/docs/api'
301 },
302 {
303 label: 'CLI',
304 to: '/docs/cli'
305 },
306 {
307 label: 'SDKs',
308 to: '/docs/sdks'
309 }
310 ]
311 },
312 {
313 title: 'Community',
314 items: [
315 {
316 label: 'Reddit',
317 href: 'https://reddit.com/r/spiceai'
318 },
319 {
320 label: 'Slack',
321 href: 'https://spice.ai/slack'
322 },
323 {
324 label: 'X',
325 href: 'https://x.com/spice_ai'
326 },
327 {
328 label: 'YouTube',
329 href: 'https://www.youtube.com/@spiceai'
330 }
331 ]
332 },
333 {
334 title: 'More',
335 items: [
336 {
337 label: 'Blog',
338 href: 'https://spice.ai/blog'
339 },
340 {
341 label: 'GitHub',
342 href: 'https://github.com/spiceai/spiceai'
343 }
344 ]
345 }
346 ],
347 copyright: `Copyright © 2025 Spice AI, Inc.`
348 },
349 languageTabs: [
350 {
351 highlight: 'bash',
352 language: 'curl',
353 logoClass: 'curl'
354 }
355 ],
356 prism: {
357 theme: prismThemes.oneLight,
358 darkTheme: prismThemes.gruvboxMaterialDark,
359 additionalLanguages: ['bash', 'json', 'csharp']
360 },
361 algolia: {
362 appId: '0SP8I8JTL8',
363 apiKey: '72f66fe334ccd3c7db696a123d68735c',
364 indexName: 'spiceai',
365 contextualSearch: true
366 }
367 } satisfies Preset.ThemeConfig,
368
369 headTags: [
370 // Structured data for SEO (JSON-LD)
371 {
372 tagName: 'script',
373 attributes: {
374 type: 'application/ld+json'
375 },
376 innerHTML: JSON.stringify({
377 '@context': 'https://schema.org',
378 '@type': 'SoftwareApplication',
379 name: 'Spice.ai OSS',
380 applicationCategory: 'DeveloperApplication',
381 operatingSystem: 'Linux, macOS, Windows',
382 description:
383 'A portable SQL query and AI compute engine, written in Rust, for data-grounded apps and agents.',
384 url: 'https://spiceai.org',
385 downloadUrl: 'https://github.com/spiceai/spiceai/releases',
386 softwareVersion: '1.10.0',
387 author: {
388 '@type': 'Organization',
389 name: 'Spice AI, Inc.',
390 url: 'https://spice.ai'
391 },
392 license: 'https://github.com/spiceai/spiceai/blob/trunk/LICENSE',
393 programmingLanguage: 'Rust',
394 offers: {
395 '@type': 'Offer',
396 price: '0',
397 priceCurrency: 'USD'
398 }
399 })
400 },
401 {
402 tagName: 'script',
403 attributes: {
404 type: 'application/ld+json'
405 },
406 innerHTML: JSON.stringify({
407 '@context': 'https://schema.org',
408 '@type': 'Organization',
409 name: 'Spice AI, Inc.',
410 url: 'https://spice.ai',
411 logo: 'https://spiceai.org/img/logo.svg',
412 sameAs: [
413 'https://github.com/spiceai',
414 'https://x.com/spice_ai',
415 'https://www.youtube.com/@spiceai',
416 'https://www.linkedin.com/company/spiceai'
417 ]
418 })
419 },
420 {
421 tagName: 'link',
422 attributes: {
423 rel: 'preconnect',
424 href: 'https://fonts.googleapis.com'
425 }
426 },
427 {
428 tagName: 'link',
429 attributes: {
430 rel: 'preconnect',
431 href: 'https://fonts.gstatic.com',
432 crossorigin: 'true'
433 }
434 },
435 {
436 tagName: 'link',
437 attributes: {
438 href: 'https://fonts.googleapis.com/css2?family=Open+Sans:wght@400;700&family=Roboto+Mono:ital,wght@0,100..700;1,100..700&display=swap',
439 rel: 'stylesheet'
440 }
441 },
442 {
443 tagName: 'link',
444 attributes: {
445 rel: 'icon',
446 type: 'image/png',
447 sizes: '32x32',
448 href: '/favicon-32x32.png'
449 }
450 },
451 {
452 tagName: 'link',
453 attributes: {
454 rel: 'icon',
455 type: 'image/png',
456 sizes: '16x16',
457 href: '/favicon-16x16.png'
458 }
459 },
460 {
461 tagName: 'script',
462 attributes: {
463 type: 'text/javascript',
464 id: 'hs-script-loader',
465 async: 'true',
466 defer: 'true',
467 src: '//js.hs-scripts.com/46107967.js'
468 }
469 },
470 // SEO: hreflang for language targeting
471 {
472 tagName: 'link',
473 attributes: {
474 rel: 'alternate',
475 hreflang: 'en',
476 href: 'https://spiceai.org'
477 }
478 },
479 {
480 tagName: 'link',
481 attributes: {
482 rel: 'alternate',
483 hreflang: 'x-default',
484 href: 'https://spiceai.org'
485 }
486 }
487 ],
488
489 plugins: [
490 tailwindPlugin,
491 [
492 '@docusaurus/plugin-content-blog',
493 {
494 id: 'releases',
495 path: 'releases',
496 routeBasePath: 'releases',
497 showLastUpdateAuthor: true,
498 showLastUpdateTime: true,
499 onInlineTags: 'throw',
500 onUntruncatedBlogPosts: 'ignore',
501 editUrl: ({ locale, blogDirPath, blogPath }) => {
502 return `https://github.com/spiceai/docs/edit/trunk/website/${blogDirPath}/${blogPath}`
503 },
504 remarkPlugins: [],
505 postsPerPage: 10,
506 feedOptions: {
507 type: 'all',
508 description: 'Keep up to date with Spice.ai OSS releases by following our feed!',
509 copyright: `Copyright © 2025-2026 Spice AI, Inc.`,
510 xslt: true
511 },
512 blogTitle: 'Spice.ai OSS Releases',
513 blogDescription: 'Spice.ai OSS release notes and announcements',
514 blogSidebarCount: 'ALL',
515 blogSidebarTitle: 'All Releases'
516 } satisfies BlogOptions
517 ],
518 [
519 'docusaurus-plugin-openapi-docs',
520 {
521 id: 'api',
522 docsPluginId: 'classic',
523 config: {
524 spice: {
525 proxy: 'http://localhost:8090',
526
527 specPath: 'public/openapi.json',
528 outputDir: 'docs/api/HTTP',
529 sidebarOptions: {
530 groupPathsBy: 'tag'
531 }
532 } satisfies OpenApiPlugin.Options
533 }
534 }
535 ],
536 [
537 '@docusaurus/plugin-client-redirects',
538 {
539 redirects: [
540 {
541 from: '/blog',
542 to: 'https://spice.ai/blog'
543 },
544 {
545 from: '/blog/announcing-1.0-stable',
546 to: 'https://spice.ai/blog/announcing-spice-ai-open-source-1-0-stable'
547 },
548 {
549 from: '/blog/amazon-s3-vectors-with-spice',
550 to: 'https://spice.ai/blog/getting-started-with-amazon-s3-vectors-and-spice'
551 },
552 {
553 from: '/blog/releases/v1.10-0',
554 to: '/releases/v1.10.0'
555 },
556 {
557 from: '/query-federation',
558 to: '/docs/features/query-federation'
559 },
560 // 2021 blog posts
561 {
562 from: '/blog/a-new-class-of-applications-that-learn-and-adapt',
563 to: 'https://spice.ai/blog/a-new-class-of-applications-that-learn-and-adapt'
564 },
565 {
566 from: '/blog/2021/a-new-class-of-applications-that-learn-and-adapt',
567 to: 'https://spice.ai/blog/a-new-class-of-applications-that-learn-and-adapt'
568 },
569 {
570 from: '/blog/ai-needs-ai-ready-data',
571 to: 'https://spice.ai/blog/ai-needs-ai-ready-data'
572 },
573 {
574 from: '/blog/2021/ai-needs-ai-ready-data',
575 to: 'https://spice.ai/blog/ai-needs-ai-ready-data'
576 },
577 {
578 from: '/blog/making-apps-that-learn-and-adapt',
579 to: 'https://spice.ai/blog/making-apps-that-learn-and-adapt'
580 },
581 {
582 from: '/blog/2021/making-apps-that-learn-and-adapt',
583 to: 'https://spice.ai/blog/making-apps-that-learn-and-adapt'
584 },
585 {
586 from: '/blog/q-learning-reward-is-all-you-need',
587 to: 'https://spice.ai/blog/q-learning-reward-is-all-you-need'
588 },
589 {
590 from: '/blog/spiceais-approach-to-time-series-ai',
591 to: 'https://spice.ai/blog/spiceais-approach-to-time-series-ai'
592 },
593 {
594 from: '/blog/2021/spiceais-approach-to-time-series-ai',
595 to: 'https://spice.ai/blog/spiceais-approach-to-time-series-ai'
596 },
597 {
598 from: '/blog/spicepods-from-zero-to-hero',
599 to: 'https://spice.ai/blog/spicepods-from-zero-to-hero'
600 },
601 {
602 from: '/blog/2021/spicepods-from-zero-to-hero',
603 to: 'https://spice.ai/blog/spicepods-from-zero-to-hero'
604 },
605 {
606 from: '/blog/teaching-apps-how-to-learn-with-spicepods',
607 to: 'https://spice.ai/blog/teaching-apps-how-to-learn-with-spicepods'
608 },
609 // 2022 blog posts
610 {
611 from: '/blog/adding-soft-actor-critic',
612 to: 'https://spice.ai/blog/adding-soft-actor-critic'
613 },
614 {
615 from: '/blog/building-on-apache-arrow-and-flight',
616 to: 'https://spice.ai/blog/building-on-apache-arrow-and-flight'
617 },
618 {
619 from: '/blog/what-data-informs-ai-driven-decision-making',
620 to: 'https://spice.ai/blog/what-data-informs-ai-driven-decision-making'
621 },
622 {
623 from: '/blog/2022/what-data-informs-ai-driven-decision-making',
624 to: 'https://spice.ai/blog/what-data-informs-ai-driven-decision-making'
625 },
626 // 2024 blog posts
627 {
628 from: '/blog/adding-spice',
629 to: 'https://spice.ai/blog/adding-spice-the-next-generation-of-spice-ai-oss'
630 },
631 {
632 from: '/blog/2024/adding-spice',
633 to: 'https://spice.ai/blog/adding-spice--the-next-generation-of-spice-ai-oss'
634 },
635 {
636 from: '/federated-queries',
637 to: '/docs/features/query-federation'
638 },
639 {
640 from: '/data-ingestion',
641 to: '/docs/features/data-ingestion'
642 },
643 {
644 from: '/data-acceleration',
645 to: '/docs/features/data-acceleration'
646 },
647 {
648 from: '/monitoring',
649 to: '/docs/features/observability'
650 }
651 ]
652 }
653 ],
654 [
655 '@signalwire/docusaurus-plugin-llms-txt',
656 {
657 siteTitle: 'Spice.ai OSS',
658 siteDescription:
659 'A portable SQL query and AI compute engine, written in Rust, for data-grounded apps and agents.',
660 depth: 2,
661 logLevel: 1,
662 content: {
663 includeBlog: false,
664 includePages: true,
665 includeDocs: true,
666 enableLlmsFullTxt: true,
667 enableMarkdownFiles: false,
668 excludeRoutes: ['/tags/**', '/search', '/api/HTTP/**']
669 },
670 optionalLinks: [
671 {
672 title: 'GitHub Repository',
673 url: 'https://github.com/spiceai/spiceai',
674 description: 'Spice.ai OSS source code and issue tracker'
675 },
676 {
677 title: 'Cookbook',
678 url: 'https://github.com/spiceai/cookbook',
679 description: 'Ready-to-use recipes and examples for Spice.ai'
680 },
681 {
682 title: 'Spice Cloud Platform',
683 url: 'https://spice.ai',
684 description: 'Managed cloud platform for Spice.ai'
685 }
686 ]
687 }
688 ]
689 ]
690}
691
692export default config
693
1import { themes as prismThemes } from 'prism-react-renderer'
2import type { Config } from '@docusaurus/types'
3import type * as Preset from '@docusaurus/preset-classic'
4
5import type * as OpenApiPlugin from 'docusaurus-plugin-openapi-docs'
6import type { Options as BlogOptions } from '@docusaurus/plugin-content-blog'
7import type { Options as PageOptions } from '@docusaurus/plugin-content-pages'
8
9import tailwindPlugin from './plugins/tailwind-config.cjs'
10import * as fs from 'fs'
11import * as path from 'path'
12
13// Load versions from versions.json if it exists (generated at build time)
14const versionsPath = path.join(__dirname, 'versions.json')
15const versions: string[] = fs.existsSync(versionsPath)
16 ? JSON.parse(fs.readFileSync(versionsPath, 'utf-8'))
17 : []
18
19// Build version configuration dynamically
20// Trunk docs (current) are "Next" at /docs/next
21// Highest version in versions.json (e.g., 1.11.x) is "Latest" at /docs (default)
22// Previous versions are at /docs/v1.10, etc.
23// Maintenance policy: latest + 1 previous minor versions are maintained
24const hasVersions = versions.length > 0
25
26// Extract major and minor version numbers from versions to determine ordering and maintenance status
27const getVersion = (v: string): { major: number; minor: number } => {
28 const match = v.match(/^(\d+)\.(\d+)/)
29 return match
30 ? { major: parseInt(match[1], 10), minor: parseInt(match[2], 10) }
31 : { major: 0, minor: 0 }
32}
33
34// Sort versions by semver (major desc, then minor desc)
35const sortedVersions = [...versions].sort((a, b) => {
36 const vA = getVersion(a)
37 const vB = getVersion(b)
38 if (vB.major !== vA.major) return vB.major - vA.major
39 return vB.minor - vA.minor
40})
41
42// Highest version is "latest", trunk (current) is "next"
43const latestVersion = sortedVersions[0] || null
44const latestVer = latestVersion ? getVersion(latestVersion) : { major: 0, minor: 0 }
45
46const docsVersionConfig = hasVersions
47 ? {
48 lastVersion: latestVersion!, // The stable release is the default
49 onlyIncludeVersions: [...versions, 'current'],
50 versions: {
51 current: {
52 label: 'Next',
53 path: 'next',
54 banner: 'unreleased' as const
55 },
56 ...Object.fromEntries(
57 versions.map((version) => {
58 const ver = getVersion(version)
59 const isLatest = version === latestVersion
60 // Versions within same major and latest minor - 1 are maintained (no banner)
61 const isMaintained =
62 ver.major > latestVer.major ||
63 (ver.major === latestVer.major && ver.minor >= latestVer.minor - 1)
64
65 return [
66 version,
67 {
68 label: isLatest
69 ? `Latest (v${version.replace('.x', '')})`
70 : `v${version.replace('.x', '')}`,
71 path: isLatest ? '' : `v${version.replace('.x', '')}`,
72 banner: isMaintained ? ('none' as const) : ('unmaintained' as const)
73 }
74 ]
75 })
76 )
77 }
78 }
79 : {
80 // No versions generated - use current docs only (for local dev)
81 lastVersion: 'current',
82 versions: {
83 current: {
84 label: 'Latest',
85 path: '',
86 banner: 'none' as const
87 }
88 },
89 onlyIncludeVersions: ['current']
90 }
91
92const config: Config = {
93 title: 'Spice.ai OSS',
94 tagline:
95 'A portable SQL query and AI compute engine, written in Rust, for data-grounded apps and agents.',
96 favicon: 'img/favicon.ico',
97
98 // Set the production url of your site here
99 url: 'https://spiceai.org',
100 // Set the /<baseUrl>/ pathname under which your site is served
101 // For GitHub pages deployment, it is often '/<projectName>/'
102 baseUrl: '/',
103
104 trailingSlash: false,
105
106 // GitHub pages deployment config.
107 // If you aren't using GitHub pages, you don't need these.
108 organizationName: 'spiceai', // Usually your GitHub org/user name.
109 projectName: 'docs', // Usually your repo name.
110
111 onBrokenAnchors: 'throw',
112 onBrokenLinks: 'throw',
113
114 markdown: {
115 mermaid: true,
116 hooks: {
117 onBrokenMarkdownLinks: 'throw'
118 }
119 },
120
121 // Even if you don't use internationalization, you can use this field to set
122 // useful metadata like html lang. For example, if your site is Chinese, you
123 // may want to replace "en" with "zh-Hans".
124 i18n: {
125 defaultLocale: 'en',
126 locales: ['en']
127 },
128
129 future: {
130 v4: {
131 removeLegacyPostBuildHeadAttribute: true // required
132 },
133 experimental_faster: true
134 },
135
136 presets: [
137 [
138 'classic',
139 {
140 docs: {
141 routeBasePath: '/docs',
142 path: 'docs',
143 sidebarPath: 'sidebars.ts',
144 onInlineTags: 'throw',
145 docItemComponent: '@theme/ApiItem',
146 editUrl: ({ versionDocsDirPath, docPath }) => {
147 return `https://github.com/spiceai/docs/edit/trunk/website/${versionDocsDirPath}/${docPath}`
148 },
149 ...docsVersionConfig
150 },
151 blog: {
152 path: 'blog',
153 showLastUpdateAuthor: true,
154 showLastUpdateTime: true,
155 onInlineTags: 'throw',
156 onUntruncatedBlogPosts: 'ignore',
157 editUrl: ({ locale, blogDirPath, blogPath }) => {
158 return `https://github.com/spiceai/docs/edit/trunk/website/${blogDirPath}/${blogPath}`
159 },
160 remarkPlugins: [],
161 postsPerPage: 5,
162 feedOptions: {
163 type: 'all',
164 description:
165 'Keep up to date with upcoming Spice.ai OSS releases and articles by following our feed!',
166 copyright: `Copyright © 2021-2026 Spice AI, Inc.`,
167 xslt: true
168 },
169 blogTitle: 'Spice.ai OSS blog',
170 blogDescription: 'Read blog posts about Spice.ai OSS from the team and community',
171 blogSidebarCount: 'ALL',
172 blogSidebarTitle: 'All Posts'
173 } satisfies BlogOptions,
174 pages: {
175 remarkPlugins: [],
176 showLastUpdateAuthor: true,
177 showLastUpdateTime: true
178 } satisfies PageOptions,
179 theme: {
180 customCss: ['./src/css/custom.css', './src/css/openapi.css', './src/css/preflight.css']
181 },
182 gtag: {
183 trackingID: 'G-SST0X6NS37',
184 anonymizeIP: true
185 },
186 sitemap: {
187 lastmod: 'date',
188 changefreq: 'weekly',
189 priority: 0.5,
190 ignorePatterns: ['/tags/**'],
191 filename: 'sitemap.xml'
192 }
193 } satisfies Preset.Options
194 ]
195 ],
196 themes: ['docusaurus-theme-openapi-docs', '@docusaurus/theme-mermaid'],
197 themeConfig: {
198 // SEO metadata configuration
199 metadata: [
200 {
201 name: 'keywords',
202 content:
203 'spice, spice.ai, sql query engine, ai compute engine, data federation, data acceleration, rag, retrieval augmented generation, arrow flight, datafusion, duckdb, rust, llm, openai compatible, mcp server'
204 },
205 { name: 'author', content: 'Spice AI, Inc.' },
206 { name: 'robots', content: 'index, follow' },
207 { property: 'og:type', content: 'website' },
208 { property: 'og:site_name', content: 'Spice.ai OSS' },
209 { property: 'og:image:width', content: '1200' },
210 { property: 'og:image:height', content: '630' },
211 { property: 'og:image:alt', content: 'Spice.ai - SQL Query and AI Compute Engine' },
212 { name: 'twitter:card', content: 'summary_large_image' },
213 { name: 'twitter:site', content: '@spice_ai' },
214 { name: 'twitter:creator', content: '@spice_ai' }
215 ],
216 announcementBar: {
217 content: '<a href="/releases/v2.0-rc.4">Spice.ai OSS v2.0-rc.4</a> is now available! 🚀',
218 backgroundColor: 'var(--announcement-bar-bg)',
219 textColor: 'var(--announcement-bar-text)',
220 isCloseable: true
221 },
222 navbar: {
223 title: 'Spice.ai OSS',
224 logo: {
225 alt: 'Spice.ai OSS logo',
226 src: 'img/logo.svg'
227 },
228 hideOnScroll: true,
229 items: [
230 {
231 type: 'doc',
232 position: 'left',
233 docId: 'index',
234 label: 'Docs'
235 },
236 {
237 type: 'docSidebar',
238 position: 'left',
239 sidebarId: 'api',
240 label: 'API'
241 },
242 { to: 'releases', label: 'Releases', position: 'left' },
243 {
244 label: 'Blog',
245 href: 'https://spice.ai/blog',
246 position: 'left'
247 },
248 { to: 'cookbook', label: 'Cookbook', position: 'left' },
249 { to: 'docs/reference/sql', label: 'SQL Reference', position: 'left' },
250 // Version dropdown is only shown when versions exist
251 ...(hasVersions
252 ? [
253 {
254 type: 'docsVersionDropdown' as const,
255 position: 'right' as const,
256 dropdownActiveClassDisabled: true
257 }
258 ]
259 : []),
260 {
261 label: 'Try Spice Cloud',
262 href: 'https://spice.ai/login',
263 position: 'right'
264 },
265 {
266 label: 'X',
267 href: 'https://x.com/spice_ai',
268 position: 'right'
269 },
270 {
271 label: 'Slack',
272 href: 'https://spice.ai/slack',
273 position: 'right'
274 },
275 {
276 label: 'YouTube',
277 href: 'https://www.youtube.com/@spiceai',
278 position: 'right'
279 },
280 {
281 href: 'https://github.com/spiceai/spiceai',
282 position: 'right',
283 className: 'header-github-link',
284 'aria-label': 'GitHub repository'
285 }
286 ]
287 },
288 footer: {
289 style: 'dark',
290 links: [
291 {
292 title: 'Docs',
293 items: [
294 {
295 label: 'Getting Started',
296 to: '/docs/getting-started'
297 },
298 {
299 label: 'API',
300 to: '/docs/api'
301 },
302 {
303 label: 'CLI',
304 to: '/docs/cli'
305 },
306 {
307 label: 'SDKs',
308 to: '/docs/sdks'
309 }
310 ]
311 },
312 {
313 title: 'Community',
314 items: [
315 {
316 label: 'Reddit',
317 href: 'https://reddit.com/r/spiceai'
318 },
319 {
320 label: 'Slack',
321 href: 'https://spice.ai/slack'
322 },
323 {
324 label: 'X',
325 href: 'https://x.com/spice_ai'
326 },
327 {
328 label: 'YouTube',
329 href: 'https://www.youtube.com/@spiceai'
330 }
331 ]
332 },
333 {
334 title: 'More',
335 items: [
336 {
337 label: 'Blog',
338 href: 'https://spice.ai/blog'
339 },
340 {
341 label: 'GitHub',
342 href: 'https://github.com/spiceai/spiceai'
343 }
344 ]
345 }
346 ],
347 copyright: `Copyright © 2025 Spice AI, Inc.`
348 },
349 languageTabs: [
350 {
351 highlight: 'bash',
352 language: 'curl',
353 logoClass: 'curl'
354 }
355 ],
356 prism: {
357 theme: prismThemes.oneLight,
358 darkTheme: prismThemes.gruvboxMaterialDark,
359 additionalLanguages: ['bash', 'json', 'csharp']
360 },
361 algolia: {
362 appId: '0SP8I8JTL8',
363 apiKey: '72f66fe334ccd3c7db696a123d68735c',
364 indexName: 'spiceai',
365 contextualSearch: true
366 }
367 } satisfies Preset.ThemeConfig,
368
369 headTags: [
370 // Structured data for SEO (JSON-LD)
371 {
372 tagName: 'script',
373 attributes: {
374 type: 'application/ld+json'
375 },
376 innerHTML: JSON.stringify({
377 '@context': 'https://schema.org',
378 '@type': 'SoftwareApplication',
379 name: 'Spice.ai OSS',
380 applicationCategory: 'DeveloperApplication',
381 operatingSystem: 'Linux, macOS, Windows',
382 description:
383 'A portable SQL query and AI compute engine, written in Rust, for data-grounded apps and agents.',
384 url: 'https://spiceai.org',
385 downloadUrl: 'https://github.com/spiceai/spiceai/releases',
386 softwareVersion: '1.10.0',
387 author: {
388 '@type': 'Organization',
389 name: 'Spice AI, Inc.',
390 url: 'https://spice.ai'
391 },
392 license: 'https://github.com/spiceai/spiceai/blob/trunk/LICENSE',
393 programmingLanguage: 'Rust',
394 offers: {
395 '@type': 'Offer',
396 price: '0',
397 priceCurrency: 'USD'
398 }
399 })
400 },
401 {
402 tagName: 'script',
403 attributes: {
404 type: 'application/ld+json'
405 },
406 innerHTML: JSON.stringify({
407 '@context': 'https://schema.org',
408 '@type': 'Organization',
409 name: 'Spice AI, Inc.',
410 url: 'https://spice.ai',
411 logo: 'https://spiceai.org/img/logo.svg',
412 sameAs: [
413 'https://github.com/spiceai',
414 'https://x.com/spice_ai',
415 'https://www.youtube.com/@spiceai',
416 'https://www.linkedin.com/company/spiceai'
417 ]
418 })
419 },
420 {
421 tagName: 'link',
422 attributes: {
423 rel: 'preconnect',
424 href: 'https://fonts.googleapis.com'
425 }
426 },
427 {
428 tagName: 'link',
429 attributes: {
430 rel: 'preconnect',
431 href: 'https://fonts.gstatic.com',
432 crossorigin: 'true'
433 }
434 },
435 {
436 tagName: 'link',
437 attributes: {
438 href: 'https://fonts.googleapis.com/css2?family=Open+Sans:wght@400;700&family=Roboto+Mono:ital,wght@0,100..700;1,100..700&display=swap',
439 rel: 'stylesheet'
440 }
441 },
442 {
443 tagName: 'link',
444 attributes: {
445 rel: 'icon',
446 type: 'image/png',
447 sizes: '32x32',
448 href: '/favicon-32x32.png'
449 }
450 },
451 {
452 tagName: 'link',
453 attributes: {
454 rel: 'icon',
455 type: 'image/png',
456 sizes: '16x16',
457 href: '/favicon-16x16.png'
458 }
459 },
460 {
461 tagName: 'script',
462 attributes: {
463 type: 'text/javascript',
464 id: 'hs-script-loader',
465 async: 'true',
466 defer: 'true',
467 src: '//js.hs-scripts.com/46107967.js'
468 }
469 },
470 // SEO: hreflang for language targeting
471 {
472 tagName: 'link',
473 attributes: {
474 rel: 'alternate',
475 hreflang: 'en',
476 href: 'https://spiceai.org'
477 }
478 },
479 {
480 tagName: 'link',
481 attributes: {
482 rel: 'alternate',
483 hreflang: 'x-default',
484 href: 'https://spiceai.org'
485 }
486 }
487 ],
488
489 plugins: [
490 tailwindPlugin,
491 [
492 '@docusaurus/plugin-content-blog',
493 {
494 id: 'releases',
495 path: 'releases',
496 routeBasePath: 'releases',
497 showLastUpdateAuthor: true,
498 showLastUpdateTime: true,
499 onInlineTags: 'throw',
500 onUntruncatedBlogPosts: 'ignore',
501 editUrl: ({ locale, blogDirPath, blogPath }) => {
502 return `https://github.com/spiceai/docs/edit/trunk/website/${blogDirPath}/${blogPath}`
503 },
504 remarkPlugins: [],
505 postsPerPage: 10,
506 feedOptions: {
507 type: 'all',
508 description: 'Keep up to date with Spice.ai OSS releases by following our feed!',
509 copyright: `Copyright © 2025-2026 Spice AI, Inc.`,
510 xslt: true
511 },
512 blogTitle: 'Spice.ai OSS Releases',
513 blogDescription: 'Spice.ai OSS release notes and announcements',
514 blogSidebarCount: 'ALL',
515 blogSidebarTitle: 'All Releases'
516 } satisfies BlogOptions
517 ],
518 [
519 'docusaurus-plugin-openapi-docs',
520 {
521 id: 'api',
522 docsPluginId: 'classic',
523 config: {
524 spice: {
525 proxy: 'http://localhost:8090',
526
527 specPath: 'public/openapi.json',
528 outputDir: 'docs/api/HTTP',
529 sidebarOptions: {
530 groupPathsBy: 'tag'
531 }
532 } satisfies OpenApiPlugin.Options
533 }
534 }
535 ],
536 [
537 '@docusaurus/plugin-client-redirects',
538 {
539 redirects: [
540 {
541 from: '/blog',
542 to: 'https://spice.ai/blog'
543 },
544 {
545 from: '/blog/announcing-1.0-stable',
546 to: 'https://spice.ai/blog/announcing-spice-ai-open-source-1-0-stable'
547 },
548 {
549 from: '/blog/amazon-s3-vectors-with-spice',
550 to: 'https://spice.ai/blog/getting-started-with-amazon-s3-vectors-and-spice'
551 },
552 {
553 from: '/blog/releases/v1.10-0',
554 to: '/releases/v1.10.0'
555 },
556 {
557 from: '/query-federation',
558 to: '/docs/features/query-federation'
559 },
560 // 2021 blog posts
561 {
562 from: '/blog/a-new-class-of-applications-that-learn-and-adapt',
563 to: 'https://spice.ai/blog/a-new-class-of-applications-that-learn-and-adapt'
564 },
565 {
566 from: '/blog/2021/a-new-class-of-applications-that-learn-and-adapt',
567 to: 'https://spice.ai/blog/a-new-class-of-applications-that-learn-and-adapt'
568 },
569 {
570 from: '/blog/ai-needs-ai-ready-data',
571 to: 'https://spice.ai/blog/ai-needs-ai-ready-data'
572 },
573 {
574 from: '/blog/2021/ai-needs-ai-ready-data',
575 to: 'https://spice.ai/blog/ai-needs-ai-ready-data'
576 },
577 {
578 from: '/blog/making-apps-that-learn-and-adapt',
579 to: 'https://spice.ai/blog/making-apps-that-learn-and-adapt'
580 },
581 {
582 from: '/blog/2021/making-apps-that-learn-and-adapt',
583 to: 'https://spice.ai/blog/making-apps-that-learn-and-adapt'
584 },
585 {
586 from: '/blog/q-learning-reward-is-all-you-need',
587 to: 'https://spice.ai/blog/q-learning-reward-is-all-you-need'
588 },
589 {
590 from: '/blog/spiceais-approach-to-time-series-ai',
591 to: 'https://spice.ai/blog/spiceais-approach-to-time-series-ai'
592 },
593 {
594 from: '/blog/2021/spiceais-approach-to-time-series-ai',
595 to: 'https://spice.ai/blog/spiceais-approach-to-time-series-ai'
596 },
597 {
598 from: '/blog/spicepods-from-zero-to-hero',
599 to: 'https://spice.ai/blog/spicepods-from-zero-to-hero'
600 },
601 {
602 from: '/blog/2021/spicepods-from-zero-to-hero',
603 to: 'https://spice.ai/blog/spicepods-from-zero-to-hero'
604 },
605 {
606 from: '/blog/teaching-apps-how-to-learn-with-spicepods',
607 to: 'https://spice.ai/blog/teaching-apps-how-to-learn-with-spicepods'
608 },
609 // 2022 blog posts
610 {
611 from: '/blog/adding-soft-actor-critic',
612 to: 'https://spice.ai/blog/adding-soft-actor-critic'
613 },
614 {
615 from: '/blog/building-on-apache-arrow-and-flight',
616 to: 'https://spice.ai/blog/building-on-apache-arrow-and-flight'
617 },
618 {
619 from: '/blog/what-data-informs-ai-driven-decision-making',
620 to: 'https://spice.ai/blog/what-data-informs-ai-driven-decision-making'
621 },
622 {
623 from: '/blog/2022/what-data-informs-ai-driven-decision-making',
624 to: 'https://spice.ai/blog/what-data-informs-ai-driven-decision-making'
625 },
626 // 2024 blog posts
627 {
628 from: '/blog/adding-spice',
629 to: 'https://spice.ai/blog/adding-spice-the-next-generation-of-spice-ai-oss'
630 },
631 {
632 from: '/blog/2024/adding-spice',
633 to: 'https://spice.ai/blog/adding-spice--the-next-generation-of-spice-ai-oss'
634 },
635 {
636 from: '/federated-queries',
637 to: '/docs/features/query-federation'
638 },
639 {
640 from: '/data-ingestion',
641 to: '/docs/features/data-ingestion'
642 },
643 {
644 from: '/data-acceleration',
645 to: '/docs/features/data-acceleration'
646 },
647 {
648 from: '/monitoring',
649 to: '/docs/features/observability'
650 }
651 ]
652 }
653 ],
654 [
655 '@signalwire/docusaurus-plugin-llms-txt',
656 {
657 siteTitle: 'Spice.ai OSS',
658 siteDescription:
659 'A portable SQL query and AI compute engine, written in Rust, for data-grounded apps and agents.',
660 depth: 2,
661 logLevel: 1,
662 content: {
663 includeBlog: false,
664 includePages: true,
665 includeDocs: true,
666 enableLlmsFullTxt: true,
667 enableMarkdownFiles: false,
668 excludeRoutes: ['/tags/**', '/search', '/api/HTTP/**']
669 },
670 optionalLinks: [
671 {
672 title: 'GitHub Repository',
673 url: 'https://github.com/spiceai/spiceai',
674 description: 'Spice.ai OSS source code and issue tracker'
675 },
676 {
677 title: 'Cookbook',
678 url: 'https://github.com/spiceai/cookbook',
679 description: 'Ready-to-use recipes and examples for Spice.ai'
680 },
681 {
682 title: 'Spice Cloud Platform',
683 url: 'https://spice.ai',
684 description: 'Managed cloud platform for Spice.ai'
685 }
686 ]
687 }
688 ]
689 ]
690}
691
692export default config
693
