💽

Tursoを軽く触ってみた

2025/03/31に公開

はじめに

Tursoを触ったので、Next.jsでTursoからデータ取得ができるまでのやり方を書いていきます。

ドキュメント等

https://turso.tech/

https://docs.turso.tech/introduction

Tursoとはなんぞや

Tursoは軽量で高速なSQLiteデータベースをベースにしたクラウドデータベースサービスです。
以下はTursoの主な特徴です:

アーキテクチャと特徴

  • SQLiteベース:SQLiteの安定性と互換性を受け継いでいます
  • libSQL:TursoはlibSQL(SQLiteのフォーク)を使用して拡張機能を提供
  • エッジデプロイメント:グローバルなエッジロケーションにデータを配置できます

パフォーマンスと設計について

  • 高速:低レイテンシで動作するように設計されています
  • 小型:リソース消費が少なく、軽量です
  • 組み込みレプリケーション機能

UXについて

  • CLIツールを提供

https://docs.turso.tech/cli/introduction

  • 複数の言語のSDKをサポート

Tursoでデータベース作成

Tursoを使用するにはアカウントを作成する必要があります。
以下から作成をしてください。

https://turso.tech/

Turso CLIをインストール

Turso CLIをインストールしておくと便利なので、インストールしておきます。
以下のドキュメントの手順に沿ってインストールできます。(Turso CLIを使わなくてもデータベースなどの作成などはできます。)

https://docs.turso.tech/cli/introduction

Macの場合は、以下のコマンドでインストールできます。

brew install tursodatabase/tap/turso

以下のコマンドで、Tursoにログインできます。

turso auth signup

データベース、テーブル作成手順

①以下のコマンドでテーブルを作成します。

turso db create test

②作成されているかを確認
以下のURLを開き、右上の「Login」を開くと、自分のダッシュボード画面に遷移するので、「Database」タブを開いて「test」が作成されているかを確認します。

https://turso.tech/

以下のように作成されているはず

スクリーンショット 2025-03-31 17.01.29.png

③テーブルを作成

  • 「test」を開き、「Outerbase Studio」を開きます。
    スクリーンショット 2025-03-31 17.02.36.png

    スクリーンショット 2025-03-31 17.06.56.png

  • 「New+」をクリックし、以下のようにテーブルの情報を設定し、「Save」をクリックすると、テーブルが作成されます。
    スクリーンショット 2025-03-31 17.07.59.png
    ↓「Save」をクリック
    スクリーンショット 2025-03-31 17.09.54.png

④データを追加
以下のようにデータを追加します。
スクリーンショット 2025-03-31 17.11.01.png

これでテーブルの準備は完了です。

Next.jsアプリケーションからTursoにアクセスしてみよう

Tursoのデータベースにアクセスするには、トークンの作成とアクセスしたいデータベースのURLを取得する必要があります。

トークンの作成、取得

まずは、CLIで以下のコマンドを実行しましょう。

turso db tokens create test

実行後、トークンが作成され、ターミナルに出力されるので、コピーしておきましょう。

URLを取得

URLは以下からコピーできます。
スクリーンショット 2025-03-31 17.16.17.png

Next.jsアプリケーションから呼び出してみよう

以下のコードを作成します。

TURSO_DATABASE_URL="取得したURL"
TURSO_AUTH_TOKEN="取得したトークン"
import { createClient } from "@libsql/client";

const url = process.env.TURSO_DATABASE_URL;
const authToken = process.env.TURSO_AUTH_TOKEN;

if (!url || !authToken) {
  throw new Error('TURSO_DATABASE_URL and TURSO_AUTH_TOKEN must be set');
}

export const turso = createClient({
  url,
  authToken,
});
import { createClient } from "@libsql/client";

const client = createClient({
  url: process.env.TURSO_DATABASE_URL || "libsql://test.turso.io",
  authToken: process.env.TURSO_AUTH_TOKEN,
});

async function initializeDb() {
  try {
    await client.execute(`
      CREATE TABLE IF NOT EXISTS items (
        id INTEGER PRIMARY KEY AUTOINCREMENT,
        name TEXT NOT NULL
      )
    `);
  } catch (error) {
    console.error("Error initializing database:", error);
  }
}

initializeDb();

export async function GET() {
  try {
    const result = await client.execute("SELECT * FROM items ORDER BY id DESC");
    return Response.json(result.rows);
  } catch (error) {
    console.error("Error fetching items:", error);
    return Response.json({ error: "Failed to fetch items" }, { status: 500 });
  }
}

export async function POST(request: Request) {
  try {
    const { name } = await request.json();

    if (!name || typeof name !== "string") {
      return Response.json({ error: "Name is required" }, { status: 400 });
    }

    await client.execute({
      sql: "INSERT INTO items (name) VALUES (?)",
      args: [name],
    });

    return Response.json({ success: true });
  } catch (error) {
    console.error("Error adding item:", error);
    return Response.json({ error: "Failed to add item" }, { status: 500 });
  }
}

export async function DELETE(request: Request) {
  try {
    const { searchParams } = new URL(request.url);
    const id = searchParams.get("id");

    if (!id) {
      return Response.json({ error: "ID is required" }, { status: 400 });
    }

    await client.execute({
      sql: "DELETE FROM items WHERE id = ?",
      args: [id],
    });

    return Response.json({ success: true });
  } catch (error) {
    console.error("Error deleting item:", error);
    return Response.json({ error: "Failed to delete item" }, { status: 500 });
  }
}

import { turso } from "@/lib/db";

export default async function Home() {
  const db = await turso.execute("SELECT * FROM users");
  const users = db.rows;

  return (
    <div className="grid grid-rows-[auto_1fr_20px] items-center justify-items-center min-h-screen p-8 pb-20 gap-8 sm:p-20 font-[family-name:var(--font-geist-sans)]">
      <h1 className="text-2xl font-bold">Turso Demo App</h1>

      <div className="w-full max-w-4xl">
        <h2 className="text-xl mb-4">ユーザー一覧</h2>

        {users.length > 0 ? (
          <div className="overflow-x-auto">
            <table className="min-w-full bg-white border border-gray-200">
              <thead className="bg-gray-100">
                <tr>
                  {Object.keys(users[0]).map((key) => (
                    <th key={key} className="px-4 py-2 text-left border-b">
                      {key}
                    </th>
                  ))}
                </tr>
              </thead>
              <tbody>
                {users.map((user, index) => (
                  <tr
                    key={index}
                    className={index % 2 === 0 ? "bg-gray-50" : "bg-white"}
                  >
                    {Object.values(user).map((value, valueIndex) => (
                      <td key={valueIndex} className="px-4 py-2 border-b">
                        {value !== null ? String(value) : "NULL"}
                      </td>
                    ))}
                  </tr>
                ))}
              </tbody>
            </table>
          </div>
        ) : (
          <p>ユーザーデータがありません</p>
        )}
      </div>

      <p className="text-sm text-gray-500">© 2025 Turso Demo</p>
    </div>
  );
}

以下のようにデータを取得できました!
スクリーンショット 2025-03-31 17.31.49.png

Discussion