import { FileTree } from '@astrojs/starlight/components'; import PackageManagerTabs from '/components/tabs/PackageManagerTabs.astro'; import ReadMore from '/components/ReadMore.astro'; import Since from '~/components/Since.astro'; import { Steps } from '@astrojs/starlight/components';

Astro DBは、Astroエコシステム向けに設計された完全管理型のSQLデータベースです。Astro内でローカル開発を行い、libSQL互換のデータベースへデプロイできます。

Astro DBは、データの設定、開発、クエリ実行をまとめて行える完全なソリューションです。astro devを実行すると、.astro/content.db内にローカルデータベースが作成され、Dockerやネットワーク接続なしでデータを管理できます。

インストール

組み込みのastro addコマンドを使って@astrojs/dbインテグレーションをインストールします。

データベースを定義する

astro addコマンドで@astrojs/dbをインストールすると、プロジェクト内にdb/config.tsファイルが自動作成され、ここでデータベーステーブルを定義します。

ts
import { defineDb } from 'astro:db';export default defineDb({  tables: { },})

テーブル

Astro DBでは、データはSQLテーブルを使って保存されます。テーブルはデータを行と列で構造化し、各列は行の値の型を制約します。

既存のlibSQLデータベース内のデータ、または新規データベースで収集するデータの構造をdb/config.tsファイル内で定義します。これにより、Astroはそのテーブルにクエリを投げるためのTypeScriptインターフェースを生成します。結果として、プロパティの自動補完や型チェック付きでデータへアクセスでき、完全なTypeScriptサポートが得られます。

データベーステーブルを設定するには、astro:dbからdefineTable()columnユーティリティをインポートして使用します。その後、テーブルの名前(大文字小文字を区別)と各列に入るデータの型を定義します。

以下は、authorbodyという必須のテキスト列を持つCommentテーブルを設定し、それをdefineDb()のエクスポートでプロジェクト内で利用可能にする例です。

ts
import { defineDb, defineTable, column } from 'astro:db';const Comment = defineTable({  columns: {    author: column.text(),    body: column.text(),  }})export default defineDb({  tables: { Comment },})

テーブル構成を参照してください。

列(カラム)

Astro DBは以下の列タイプをサポートしています。

ts
import { defineTable, column } from 'astro:db';const Comment = defineTable({  columns: {    // テキスト文字列。    author: column.text(),    // 整数値。    likes: column.number(),    // 真偽値。    flagged: column.boolean(),    // JavaScriptのDateオブジェクトとしてクエリされる日時値。    published: column.date(),    // 型指定されていないJSONオブジェクト。    metadata: column.json(),  }});

テーブル構成を参照してください。

テーブル参照

テーブル間のリレーションは、データベース設計における一般的なパターンです。たとえば、BlogテーブルはCommentAuthorCategoryといった他のテーブルと密接に関連する場合があります。

テーブル間の関係は参照カラムを使って定義し、データベーススキーマ内に保存できます。リレーションを確立するには、以下が必要です。

  • 参照される側のテーブルに識別子カラム(通常はprimaryKeyプロパティを持つidカラム)があること。
  • 基本テーブルに参照するidを保存するカラムを設置すること。このカラムはreferencesプロパティを使用して関係を確立します。

以下は、CommentテーブルのauthorIdカラムがAuthorテーブルのidカラムを参照している例です。

ts
const Author = defineTable({  columns: {    id: column.number({ primaryKey: true }),    name: column.text(),  }});const Comment = defineTable({  columns: {    authorId: column.number({ references: () => Author.columns.id }),    body: column.text(),  }});

開発用データベースのシード

開発環境では、AstroはDB設定を使用してスキーマに基づいたローカル型を生成します。これらの型は開発サーバー起動時に毎回シードファイルから新しく生成され、型安全性とオートコンプリート付きでデータのクエリや操作ができます。

開発中にリモートデータベースへ接続しない限り、本番データへアクセスすることはできません。これによりデータを保護しつつ、型安全性のある動作データベースを用いたテスト・開発が可能になります。

テストやデバッグ用の開発データをAstroプロジェクトにシードするには、db/seed.tsファイルを作成します。astro:dbから定義済みのdbオブジェクトやテーブルをインポートし、各テーブルに初期データをinsertします。この開発用データは、データベーススキーマおよび本番データの形式と一致させる必要があります。

以下の例では、CommentテーブルとAuthorテーブルにそれぞれ2行の開発用データを定義しています。

ts
import { db, Comment, Author } from 'astro:db';export default async function() {  await db.insert(Author).values([    { id: 1, name: "Kasim" },    { id: 2, name: "Mina" },  ]);  await db.insert(Comment).values([    { authorId: 1, body: 'Hope you like Astro DB!' },    { authorId: 2, body: 'Enjoy!'},  ])}

開発サーバーはこのファイルの変更を検知すると自動的にデータベースを再起動し、型を再生成し、seed.tsから新たに開発データをシードします。

本番用のlibSQLデータベースに接続する

Astro DBは、ローカルのlibSQLデータベース、またはlibSQLリモートプロトコルを公開しているマネージド・セルフホスト型サーバーのどちらにも接続できます。

Astro DBをlibSQLデータベースに接続するには、データベースプロバイダーから取得した以下の環境変数を設定します。

  • ASTRO_DB_REMOTE_URL: ローカルまたはリモートlibSQL DBの接続URL。このURLには、同期や暗号化などのURL設定オプションをパラメータとして含めることができます。
  • ASTRO_DB_APP_TOKEN: libSQLサーバーの認証トークン。これはリモートデータベースに必要であり、ローカルDB(ファイルまたはメモリ内)には不要です。

サービスによってはCLIやWeb UIを使ってこれらの値を取得できます。以下では、例としてTursoを使用し、この値を設定する手順を示しますが、他のプロバイダーも自由に利用できます。

Tursoの始め方

Tursoは、Astro DBを支えるオープンソースのSQLiteフォークlibSQLの開発元です。完全管理型のlibSQLデータベースプラットフォームを提供し、Astroと完全互換です。

以下の手順では、Turso CLIのインストール、ログイン(またはサインアップ)、新しいデータベースの作成、必要な環境変数の取得、スキーマのリモートデータベースへのプッシュ方法を案内します。

  1. Turso CLIをインストールします。

  2. Tursoにログインまたはサインアップします。

  3. 新しいデータベースを作成します。例として、データベース名をandromedaとします。

    sh
    turso db create andromeda
  4. showコマンドを実行して、新しく作成したデータベースの情報を確認します。

    sh
    turso db show andromeda

    出力されるURL値をコピーし、ASTRO_DB_REMOTE_URLに設定します。

    dotenv
    ASTRO_DB_REMOTE_URL=libsql://andromeda-houston.turso.io
  5. データベースへのリクエストを認証する新しいトークンを作成します。

    sh
    turso db tokens create andromeda

    コマンド出力をコピーし、ASTRO_DB_APP_TOKENに設定します。

    dotenv
    ASTRO_DB_REMOTE_URL=libsql://andromeda-houston.turso.ioASTRO_DB_APP_TOKEN=eyJhbGciOiJF...3ahJpTkKDw
  6. DBスキーマとメタデータを新しいTursoデータベースにプッシュします。

    sh
    astro db push --remote
  7. 接続が完了しました!少し休憩しましょう。👾

    sh
    turso relax

Tursoの詳細機能については、Tursoドキュメントを参照してください。

リモートデータベースへの接続

Astro DBでは、ローカルおよびリモートのデータベースへの接続が可能です。デフォルトでは、Astroはdevおよびbuildコマンド用にローカルデータベースファイルを使用し、毎回テーブルを再作成して開発用のシードデータを挿入します。

ホスティングされたリモートデータベースに接続するには、--remoteフラグを使用します。このフラグにより、リモートデータベースへの読み取りおよび書き込みアクセスが有効化され、本番環境でユーザーデータを受け取り、永続化できます。

:::note 静的レンダリングまたはサーバーレンダリングモードを使用する任意のデプロイメントプラットフォームで、リモート接続は一般的に可能ですが、現在いくつかの制限があります。CloudflareやDenoのようなNode.js以外のランタイムでは、libSQLを使用する場合にサーバーレンダリングルートでのデータベース接続がサポートされていません。これらのプラットフォームへの対応は、今後の実装計画に含まれています。 :::

ビルドコマンドに--remoteフラグを追加して構成します。

json
{  "scripts": {    "build": "astro build --remote"  }}

また、コマンドラインで直接フラグを使用することもできます。

bash
# リモート接続でビルドastro build --remote# リモート接続で開発astro dev --remote

:::caution 開発時に --remote フラグを使うと、本番データベースに対して直接操作が行われます。誤ってデータを追加、上書きや削除するリスクがあるため、十分注意してください。 :::

--remoteフラグは、ローカルのビルド中およびサーバー上の両方でリモートDBへの接続を使用します。ローカル開発環境とデプロイメントプラットフォームの両方に必要な環境変数を必ず設定してください。

Astro DBプロジェクトをデプロイする際は、デプロイメントプラットフォームのビルドコマンドをnpm run build(または使用するパッケージマネージャーの同等のコマンド)に設定し、package.json内で構成済みの--remoteフラグを利用できるようにしてください。

リモートURL設定オプション

ASTRO_DB_REMOTE_URL環境変数は、データベースの場所および同期や暗号化などの他のオプションを構成します。

URLスキームとホスト

libSQLは、リモートサーバー用のトランスポートプロトコルとしてHTTPおよびWebSocketの両方をサポートしています。また、ローカルファイルやインメモリDBの使用も可能です。これらは接続URL内の以下のスキームで構成できます。

  • memory: → インメモリDBを使用(この場合ホストは空)。
  • file: → ローカルファイルを使用(ホストはファイルへのパス例:file:path/to/file.db)。
  • libsql: → ライブラリが推奨するプロトコルでリモートサーバーを使用(バージョンによって異なる場合あり)。ホストはサーバーのアドレス(例:libsql://your.server.io)。
  • http: → HTTP経由でリモートサーバーを使用。https:を使用するとセキュアな接続が可能。ホストはlibsql:と同じ。
  • ws: → WebSocket経由でリモートサーバーを使用。wss:を使用するとセキュアな接続が可能。ホストはlibsql:と同じ。

libSQL接続の詳細(例:暗号化キー、レプリケーション、同期間隔)は、リモート接続URL内のクエリパラメータとして構成できます。

たとえば、暗号化されたローカルファイルをlibSQLサーバーの埋め込みレプリカとして使用する場合、以下の環境変数を設定します。

dotenv
ASTRO_DB_REMOTE_URL=file://local-copy.db?encryptionKey=your-encryption-key&syncInterval=60&syncUrl=libsql%3A%2F%2Fyour.server.ioASTRO_DB_APP_TOKEN=token-to-your-remote-url

encryptionKey

libSQLは暗号化データベースをネイティブにサポートしています。この検索パラメータを渡すことで、指定したキーを使用して暗号化が有効になります。

dotenv
ASTRO_DB_REMOTE_URL=file:path/to/file.db?encryptionKey=your-encryption-key

syncUrl

埋め込みレプリカは、libSQLクライアントの機能で、ローカルファイルまたはインメモリ上に完全に同期されたデータベースのコピーを作成し、超高速読み取りを実現します。書き込みはsyncUrlで定義されたリモートデータベースに送信され、ローカルコピーと同期されます。

このプロパティを使用して、別のデータベースの埋め込みレプリカに変換するための接続URLを渡します。使用できるのはfile:およびmemory:スキームのみです。パラメータはURLエンコードする必要があります。

たとえば、libsql://your.server.io上のデータベースのインメモリ埋め込みレプリカを作成する場合、次のように接続URLを設定します。

dotenv
ASTRO_DB_REMOTE_URL=memory:?syncUrl=libsql%3A%2F%2Fyour.server.io

syncInterval

埋め込みレプリカの同期間隔(秒単位)。デフォルトでは起動時と書き込み後のみ同期されます。

このプロパティはsyncUrlが設定されている場合のみ使用されます。たとえば、1分ごとに同期するインメモリ埋め込みレプリカを設定するには、次の環境変数を指定します。

dotenv
ASTRO_DB_REMOTE_URL=memory:?syncUrl=libsql%3A%2F%2Fyour.server.io&syncInterval=60

データベースをクエリする

プロジェクト内の任意のAstroページエンドポイント、またはアクションから、提供されているdb ORMおよびクエリビルダーを使用してデータベースをクエリできます。

Drizzle ORM

ts
import { db } from 'astro:db';

Astro DBには組み込みのDrizzle ORMクライアントが含まれています。クライアントを使うために特別なセットアップや手動設定は不要です。Astroを実行すると、Astro DBのdbクライアントはローカル・リモート両方のデータベースと通信するよう自動的に設定されます。データベーススキーマ定義を基に、存在しない列やテーブルを参照した際にはTypeScriptエラーを出す型安全なSQLクエリが実行されます。

Select

次の例はCommentテーブルの全行を選択します。これはdb/seed.tsからシードされた開発データの完全な配列を返し、ページテンプレート内で使用できます。

astro
---import { db, Comment } from 'astro:db';const comments = await db.select().from(Comment);---<h2>Comments</h2>{  comments.map(({ author, body }) => (    <article>      <p>Author: {author}</p>      <p>{body}</p>    </article>  ))}

Drizzleのselect() APIリファレンスを参照してください。

インサート

フォームリクエストの処理やリモートデータベースへのデータ挿入など、ユーザー入力を受け付けるには、Astroプロジェクトをオンデマンドレンダリング用に設定し、デプロイ環境に応じたアダプターを追加します。

次の例は、パースされたフォームのPOSTリクエストに基づきCommentテーブルに行を挿入する例です。

astro
---// src/pages/index.astroimport { db, Comment } from 'astro:db';if (Astro.request.method === 'POST') {  // POSTリクエストのフォームデータを解析します。  const formData = await Astro.request.formData();  const author = formData.get('author');  const body = formData.get('body');    if (typeof author === 'string' && typeof body === 'string') {    // Commentテーブルに行を挿入します。    await db.insert(Comment).values({ author, body });  }}// 新しいコメントリストを各リクエストでレンダリングします。const comments = await db.select().from(Comment);---<form method="POST" style="display: grid">	<label for="author">Author</label>	<input id="author" name="author" />	<label for="body">Body</label>	<textarea id="body" name="body"></textarea>	<button type="submit">Submit</button></form><!-- `comments`をレンダリング -->

また、Astroアクションを使用してAstro DBテーブルにデータを挿入することもできます。次の例はアクションを使用してCommentテーブルに行を挿入する例です。

ts
// src/actions/index.tsimport { db, Comment } from 'astro:db';import { defineAction } from 'astro:actions';import { z } from 'astro:schema';export const server = {  addComment: defineAction({    // Zodを使用して型安全性を提供します。    // Astroページでtypeof {value} === 'string'をチェックする必要がありません。    input: z.object({      author: z.string(),      body: z.string(),    }),    handler: async (input) => {      const updatedComments = await db        .insert(Comment)        .values(input)        .returning(); // 更新されたコメントを返します。      return updatedComments;    },  }),};

Drizzleのinsert() APIリファレンスを参照してください。

Delete

APIエンドポイントからデータベースをクエリすることもできます。次の例は、idパラメータに基づいてCommentテーブルから行を削除する例です。

ts
// src/pages/api/comments/[id].tsimport type { APIRoute } from "astro";import { db, Comment, eq } from 'astro:db';export const DELETE: APIRoute = async (ctx) => {  await db.delete(Comment).where(eq(Comment.id, ctx.params.id ));  return new Response(null, { status: 204 });}

Drizzleのdelete() APIリファレンスを参照してください。

フィルタリング

特定のプロパティに基づいてテーブル結果をクエリするには、Drizzleの部分選択用オプションを使用します。たとえば、select()クエリに.where()呼び出しを追加し、比較条件を渡します。

以下の例では、Commentテーブル内のbodyに"Astro DB"というフレーズを含む全行をクエリしています。like()演算子を使用して、フレーズが含まれているかを確認します。

astro
---import { db, Comment, like } from 'astro:db';const comments = await db.select().from(Comment).where(    like(Comment.body, '%Astro DB%'));---

Drizzleユーティリティ

クエリ構築用のすべてのDrizzleユーティリティはastro:dbモジュールから提供されます。これには以下が含まれます。

ts
import { eq, gt, count, sql } from 'astro:db';

リレーション

SQLのjoinを使って複数のテーブルから関連データをクエリできます。joinクエリを作成するには、db.select()ステートメントにjoin演算子を追加します。各関数は結合するテーブルと、2つのテーブル間で行を一致させる条件を受け取ります。

以下の例では、innerJoin()関数を使用し、Commentの著者と、それに関連するAuthor情報をauthorId列を基に結合しています。これにより、各AuthorおよびComment行がトップレベルのプロパティとして含まれるオブジェクトの配列が返されます。

astro
---import { db, eq, Comment, Author } from 'astro:db';const comments = await db.select()  .from(Comment)  .innerJoin(Author, eq(Comment.authorId, Author.id));---<h2>Comments</h2>{  comments.map(({ Author, Comment }) => (    <article>      <p>Author: {Author.name}</p>      <p>{Comment.body}</p>    </article>  ))}

Drizzleのjoinリファレンスですべての利用可能なjoin演算子や設定オプションを確認できます。

バッチトランザクション

すべてのリモートデータベースクエリはネットワークリクエストとして行われます。大量のクエリをまとめて単一のトランザクションにまとめたい場合や、クエリの一部が失敗した際に自動ロールバックを行いたい場合があります。

以下の例では、db.batch()メソッドを使って単一のリクエストで複数の行をシードしています。

ts
// db/seed.tsimport { db, Author, Comment } from 'astro:db';export default async function () {  const queries = [];  // 100件のサンプルコメントをリモートデータベースにシードします。  // これは単一のネットワークリクエストで行われます。  for (let i = 0; i < 100; i++) {    queries.push(db.insert(Comment).values({ body: `Test comment ${i}` }));  }  await db.batch(queries);}

Drizzleのdb.batch()ドキュメントで詳細を確認してください。

データベースへの変更をプッシュする

開発中に行った変更をデータベースにプッシュできます。

テーブルスキーマをプッシュする

プロジェクトが成長するにつれて、テーブルスキーマは変化する可能性があります。設定変更をローカルで安全にテストし、デプロイ時にリモートデータベースへプッシュできます。

ローカルのスキーマ変更をリモートデータベースにプッシュするには、CLIでastro db push --remoteコマンドを使用します。

このコマンドは、ローカルの変更がデータ損失なしに適用できるか検証し、必要に応じて安全にスキーマ変更を行う方法を提案します。

互換性のないスキーマ変更をプッシュする

リモートデータベース上の既存データと互換性のない形でテーブルスキーマを変更する場合は、本番データベースをリセットする必要があります。

互換性のないスキーマ更新をプッシュするには、--force-resetフラグを追加して本番データをすべてリセットします。

テーブルの名前変更

スキーマをリモートデータベースにプッシュした後でもテーブル名を変更できます。

重要な本番データがない場合は、--force-resetフラグを使用してデータベースをリセットできます。このフラグはデータベース内のすべてのテーブルを削除し、新しいスキーマに基づいて再作成します。

本番データを保持したままテーブル名を変更する場合は、非破壊的な変更を段階的に行う必要があります。

以下はCommentテーブルをFeedbackに名前を変え、古いテーブルを非推奨にする例です。

  1. データベース設定ファイル内で、リネーム対象のテーブルにdeprecated: trueプロパティを追加します。

    ts
    const Comment = defineTable({  deprecated: true,	columns: {		author: column.text(),		body: column.text(),	}});
  2. 既存テーブルのプロパティと完全に一致する新しい名前のテーブルスキーマを追加します。

    ts
    const Comment = defineTable({  deprecated: true,  columns: {  	author: column.text(),  	body: column.text(),  }});const Feedback = defineTable({  columns: {    author: column.text(),    body: column.text(),  }});
  3. astro db push --remoteリモートデータベースへプッシュします。これにより、新しいテーブルが追加され、古いテーブルが非推奨としてマークされます。

  4. プロジェクト内のコードをすべて新しいテーブルを使用するよう更新します。必要に応じてデータ移行も行います。

  5. 古いテーブルがプロジェクト内で完全に使用されなくなったことを確認したら、config.tsからスキーマを削除します。

    ts
    const Comment = defineTable({deprecated: true,columns: {author: column.text(),body: column.text(),}});const Feedback = defineTable({columns: {author: column.text(),body: column.text(),}});
  6. 再度astro db push --remoteでリモートデータベースにプッシュします。古いテーブルは削除され、新しい名前のテーブルだけが残ります。

テーブルデータをプッシュする

シードやデータマイグレーションのためにリモートデータベースにデータをプッシュする必要がある場合があります。astro:dbモジュールを使って型安全なクエリを記述した.tsファイルを作成し、astro db execute <ファイルパス> --remoteコマンドで実行します。

以下のコメントは、astro db execute db/seed.ts --remoteコマンドでシードできます。

ts
// db/seed.ts gimport { Comment } from 'astro:db';export default async function () {  await db.insert(Comment).values([    { authorId: 1, body: 'Hope you like Astro DB!' },    { authorId: 2, body: 'Enjoy!' },  ])}

CLIリファレンスですべてのコマンドを確認できます。

Astro DBインテグレーションを構築する

Astroインテグレーションを使って、追加のAstro DBテーブルやシードデータをユーザープロジェクトに拡張できます。

astro:db:setupフック内のextendDb()メソッドを使用して、追加のAstro DB設定やシードファイルを登録します。defineDbIntegration()ヘルパーを使うと、astro:db:setupフック内でTypeScriptサポートとオートコンプリートが利用できます。

js
// my-integration/index.tsimport { defineDbIntegration } from '@astrojs/db/utils';export default function MyIntegration() {  return defineDbIntegration({    name: 'my-astro-db-powered-integration',    hooks: {      'astro:db:setup': ({ extendDb }) => {        extendDb({          configEntrypoint: '@astronaut/my-package/config',          seedEntrypoint: '@astronaut/my-package/seed',        });      },      // その他のインテグレーションフック...    },  });}

インテグレーションの設定およびシードファイルは、ユーザー定義のものと同じ形式です。

インテグレーション内の型安全な操作

インテグレーション開発中は、astro:dbからエクスポートされるAstro生成のテーブル型を利用できない場合があります。完全な型安全性を確保するためには、asDrizzleTable()ユーティリティを使い、データベース操作用のテーブル参照オブジェクトを作成します。

たとえば、以下のようにPetsデータベーステーブルをセットアップするインテグレーションの場合:

js
// my-integration/config.tsimport { defineDb, defineTable, column } from 'astro:db';export const Pets = defineTable({  columns: {    name: column.text(),    species: column.text(),  },});export default defineDb({ tables: { Pets } });

シードファイルではPetsをインポートし、asDrizzleTable()を使って型チェック付きで行を挿入できます。

js
// my-integration/seed.tsimport { asDrizzleTable } from '@astrojs/db/utils';import { db } from 'astro:db';import { Pets } from './config';export default async function() {  const typeSafePets = asDrizzleTable('Pets', Pets);  await db.insert(typeSafePets).values([    { name: 'Palomita', species: 'cat' },    { name: 'Pan', species: 'dog' },  ]);}

asDrizzleTable('Pets', Pets)で返される値はimport { Pets } from 'astro:db'と同等ですが、Astroの型生成が実行できない場合でも利用可能です。データベースへのクエリや挿入が必要なインテグレーションコード内で使用できます。

Astro StudioからTursoへの移行

  1. Studioダッシュボードで、移行したいプロジェクトに移動します。設定タブ内の"Export Database"ボタンを使い、データベースのダンプをダウンロードします。

  2. 公式手順に従ってTurso CLIをインストールし、Tursoアカウントにサインアップまたはログインします。

  3. turso db createコマンドを使用してTurso上に新しいデータベースを作成します。

    sh
    turso db create [database-name]
  4. Turso CLIを使ってデータベースURLを取得し、それを環境変数ASTRO_DB_REMOTE_URLとして設定します。

    sh
    turso db show [database-name]
    dotenv
    ASTRO_DB_REMOTE_URL=[your-database-url]
  5. データベースへアクセスするためのトークンを作成し、それを環境変数ASTRO_DB_APP_TOKENとして設定します。

    sh
    turso db tokens create [database-name]
    dotenv
    ASTRO_DB_APP_TOKEN=[your-app-token]
  6. データベーススキーマとメタデータを新しいTursoデータベースにプッシュします。

    sh
    astro db push --remote
  7. ステップ1でダウンロードしたデータベースダンプを新しいTurso DBにインポートします。

    sh
    turso db shell [database-name] < ./path/to/dump.sql
  8. プロジェクトが新しいデータベースに正常に接続されていることを確認したら、Astro Studioからプロジェクトを安全に削除できます。