# Fumadocs Core (the core library of Fumadocs): Orama Cloud
URL: /ja/docs/headless/search/orama-cloud
Source: https://raw.githubusercontent.com/fuma-nama/fumadocs/refs/heads/main/apps/docs/content/docs/headless/search/orama-cloud.ja.mdx

Orama Cloud との連携

まず、Orama Cloud でアカウントを作成してください。

## REST API [#rest-api]

REST API 連携では、ドキュメント側からインデックスをアップロードする必要があります。

1. Orama Cloud のダッシュボードで、**REST API** データソースを使用する新しいプロジェクトを作成します。

   認証情報は `.env.local` などに保存します (`NEXT_PUBLIC_` は、Vite 系フレームワークでは `VITE_`、Astro では `PUBLIC_` になります) 。

   ```dotenv
   NEXT_PUBLIC_ORAMA_DATASOURCE_ID="Rest API data source ID"
   NEXT_PUBLIC_ORAMA_PROJECT_ID="project ID"
   NEXT_PUBLIC_ORAMA_API_KEY="public API key"

   ORAMA_PRIVATE_API_KEY="private API key"
   ```

2. `static.json` ルートを事前レンダリングしてビルド時に検索インデックスをエクスポートし、ビルドのたびにスクリプトで Orama Cloud に同期します。

   ```ts tab="Next.js" title="app/static.json/route.ts"
   import { source } from '@/lib/source';
   import { toDocuments } from 'fumadocs-core/search/orama-cloud';

   export const revalidate = false;

   export async function GET() {
     return Response.json(await toDocuments(source));
   }

   ```

   ```ts tab="Next.js" title="scripts/sync-content.ts"
   import * as fs from 'node:fs/promises';
   import { type OramaDocument as DocumentRecord, sync } from 'fumadocs-core/search/orama-cloud';
   import { OramaCloud } from '@orama/core';

   // Next.js writes it under `route-cache` when built with an adapter, like on Vercel
   const [file] = await Array.fromAsync(fs.glob('.next/server/{app,route-cache/*/*/$}/static.json.body'));
   const records = JSON.parse(await fs.readFile(file, 'utf-8')) as DocumentRecord[];

   const orama = new OramaCloud({
     projectId: process.env.NEXT_PUBLIC_ORAMA_PROJECT_ID!,
     apiKey: process.env.ORAMA_PRIVATE_API_KEY!,
   });

   await sync(orama, {
     index: process.env.NEXT_PUBLIC_ORAMA_DATASOURCE_ID!,
     documents: records,
   });

   console.log(`search updated: ${records.length} records`);

   ```

   ```json tab="Next.js" title="package.json"
   {
     "scripts": {
       "build": "next build && node --env-file-if-exists=.env.local scripts/sync-content.ts"
     }
   }
   ```

   ```ts tab="React Router" title="app/routes/static.json.ts"
   import { source } from '@/lib/source';
   import { toDocuments } from 'fumadocs-core/search/orama-cloud';

   export async function loader() {
     return Response.json(await toDocuments(source));
   }

   ```

   ```ts tab="React Router" title="app/routes.ts"
   import { index, route, type RouteConfig } from '@react-router/dev/routes';

   export default [
     index('routes/home.tsx'),
     route('static.json', 'routes/static.json.ts'), // [!code ++:1]
   ] satisfies RouteConfig;

   ```

   ```ts tab="React Router" title="scripts/sync-content.ts"
   import * as fs from 'node:fs/promises';
   import { type OramaDocument as DocumentRecord, sync } from 'fumadocs-core/search/orama-cloud';
   import { OramaCloud } from '@orama/core';

   const records = JSON.parse(await fs.readFile('build/client/static.json', 'utf-8')) as DocumentRecord[];

   const orama = new OramaCloud({
     projectId: process.env.VITE_ORAMA_PROJECT_ID!,
     apiKey: process.env.ORAMA_PRIVATE_API_KEY!,
   });

   await sync(orama, {
     index: process.env.VITE_ORAMA_DATASOURCE_ID!,
     documents: records,
   });

   console.log(`search updated: ${records.length} records`);

   ```

   ```json tab="React Router" title="package.json"
   {
     "scripts": {
       "build": "react-router build && node --env-file-if-exists=.env.local scripts/sync-content.ts"
     }
   }
   ```

   ```ts tab="TanStack Start" title="src/routes/static[.]json.ts"
   import { createFileRoute } from '@tanstack/react-router';
   import { source } from '@/lib/source';
   import { toDocuments } from 'fumadocs-core/search/orama-cloud';

   export const Route = createFileRoute('/static.json')({
     server: {
       handlers: {
         GET: async () => Response.json(await toDocuments(source)),
       },
     },
   });

   ```

   ```ts tab="TanStack Start" title="vite.config.ts"
   import { tanstackStart } from '@tanstack/react-start/plugin/vite';
   import { nitro } from 'nitro/vite';
   import { defineConfig } from 'vite';

   export default defineConfig({
     plugins: [
       tanstackStart({
         prerender: {
           enabled: true,
         },
         pages: [ // [!code ++:3]
           { path: '/static.json' }
         ],
       }),
       nitro({
         preset: 'vercel',
       }),
     ],
   });

   ```

   ```ts tab="TanStack Start" title="scripts/sync-content.ts"
   import * as fs from 'node:fs/promises';
   import { type OramaDocument as DocumentRecord, sync } from 'fumadocs-core/search/orama-cloud';
   import { OramaCloud } from '@orama/core';

   const records = JSON.parse(await fs.readFile('.vercel/output/static/static.json', 'utf-8')) as DocumentRecord[];

   const orama = new OramaCloud({
     projectId: process.env.VITE_ORAMA_PROJECT_ID!,
     apiKey: process.env.ORAMA_PRIVATE_API_KEY!,
   });

   await sync(orama, {
     index: process.env.VITE_ORAMA_DATASOURCE_ID!,
     documents: records,
   });

   console.log(`search updated: ${records.length} records`);

   ```

   ```json tab="TanStack Start" title="package.json"
   {
     "scripts": {
       "build": "vite build && node --env-file-if-exists=.env.local scripts/sync-content.ts"
     }
   }
   ```

   ```ts tab="Waku" title="src/pages/_api/static.json.ts"
   import { source } from '@/lib/source';
   import { toDocuments } from 'fumadocs-core/search/orama-cloud';

   export async function GET() {
     return Response.json(await toDocuments(source));
   }

   export async function getConfig() {
     return {
       render: 'static' as const,
     } as const;
   }

   ```

   ```ts tab="Waku" title="scripts/sync-content.ts"
   import * as fs from 'node:fs/promises';
   import { type OramaDocument as DocumentRecord, sync } from 'fumadocs-core/search/orama-cloud';
   import { OramaCloud } from '@orama/core';

   const records = JSON.parse(await fs.readFile('dist/public/static.json', 'utf-8')) as DocumentRecord[];

   const orama = new OramaCloud({
     projectId: process.env.VITE_ORAMA_PROJECT_ID!,
     apiKey: process.env.ORAMA_PRIVATE_API_KEY!,
   });

   await sync(orama, {
     index: process.env.VITE_ORAMA_DATASOURCE_ID!,
     documents: records,
   });

   console.log(`search updated: ${records.length} records`);

   ```

   ```json tab="Waku" title="package.json"
   {
     "scripts": {
       "build": "waku build && node --env-file-if-exists=.env.local scripts/sync-content.ts"
     }
   }
   ```

   ```ts tab="Astro" title="src/pages/static.json.ts"
   import type { APIRoute } from 'astro';
   import { source } from '@/lib/source';
   import { toDocuments } from 'fumadocs-core/search/orama-cloud';

   export const prerender = true;

   export const GET: APIRoute = async () => Response.json(await toDocuments(source));

   ```

   ```ts tab="Astro" title="scripts/sync-content.ts"
   import * as fs from 'node:fs/promises';
   import { type OramaDocument as DocumentRecord, sync } from 'fumadocs-core/search/orama-cloud';
   import { OramaCloud } from '@orama/core';

   const records = JSON.parse(await fs.readFile('dist/static.json', 'utf-8')) as DocumentRecord[];

   const orama = new OramaCloud({
     projectId: process.env.PUBLIC_ORAMA_PROJECT_ID!,
     apiKey: process.env.ORAMA_PRIVATE_API_KEY!,
   });

   await sync(orama, {
     index: process.env.PUBLIC_ORAMA_DATASOURCE_ID!,
     documents: records,
   });

   console.log(`search updated: ${records.length} records`);

   ```

   ```json tab="Astro" title="package.json"
   {
     "scripts": {
       "build": "astro build && node --env-file-if-exists=.env.local scripts/sync-content.ts"
     }
   }
   ```

   `build` スクリプトはビルドのたびに同期を行うため、デプロイ先のプラットフォームにも同じ環境変数を設定してください。

### 検索クライアント [#search-client]

クライアント側でドキュメントを検索するには、次の方法を検討してください。

* [Fumadocs UI の検索ダイアログ](/docs/next/search/orama-cloud)を使用する。

* Fumadocs の組み込みフックを使用して、独自の検索 UI を作成する。

  ```ts
  import { useOramaCloudSearch } from 'fumadocs-core/search/client';
  import { OramaCloud } from '@orama/core';

  const orama = new OramaCloud({
    projectId: process.env.NEXT_PUBLIC_ORAMA_PROJECT_ID,
    apiKey: process.env.NEXT_PUBLIC_ORAMA_API_KEY,
  });

  const params = {
    // 任意の検索パラメーター
  };

  const { search, onSearchChange, isLoading, data } = useOramaCloudSearch({
    client: orama,
    params,
  });
  ```

* Orama の検索クライアントを直接使用する。

## Web Crawler [#web-crawler]

1. ダッシュボードで Crawler データソースを作成し、「Documentation」プリセットを使って適切に設定してください。
2. ダッシュボードから認証情報をコピーしてください。

### 検索クライアント [#search-client-1]

REST API 連携の場合と同じですが、`index` は必ず `crawler` に設定してください。

```ts
import { useOramaCloudSearch } from 'fumadocs-core/search/client';
import { OramaCloud } from '@orama/core';

const orama = new OramaCloud({
  projectId: '<project id>',
  apiKey: '<read only api key>',
});

const params = {
  // 検索パラメータ(任意)
};

const { search, onSearchChange, isLoading, data } = useOramaCloudSearch({
  index: 'crawler',
  client: orama,
  params,
});
```

Fumadocs UI でも同様です。