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