Tursoを軽く触ってみた
はじめに
Tursoを触ったので、Next.jsでTursoからデータ取得ができるまでのやり方を書いていきます。
ドキュメント等
Tursoとはなんぞや
Tursoは軽量で高速なSQLiteデータベースをベースにしたクラウドデータベースサービスです。
以下はTursoの主な特徴です:
アーキテクチャと特徴
- SQLiteベース:SQLiteの安定性と互換性を受け継いでいます
- libSQL:TursoはlibSQL(SQLiteのフォーク)を使用して拡張機能を提供
- エッジデプロイメント:グローバルなエッジロケーションにデータを配置できます
パフォーマンスと設計について
- 高速:低レイテンシで動作するように設計されています
- 小型:リソース消費が少なく、軽量です
- 組み込みレプリケーション機能
UXについて
- CLIツールを提供
- 複数の言語のSDKをサポート
Tursoでデータベース作成
Tursoを使用するにはアカウントを作成する必要があります。
以下から作成をしてください。
Turso CLIをインストール
Turso CLIをインストールしておくと便利なので、インストールしておきます。
以下のドキュメントの手順に沿ってインストールできます。(Turso CLIを使わなくてもデータベースなどの作成などはできます。)
Macの場合は、以下のコマンドでインストールできます。
brew install tursodatabase/tap/turso
以下のコマンドで、Tursoにログインできます。
turso auth signup
データベース、テーブル作成手順
①以下のコマンドでテーブルを作成します。
turso db create test
②作成されているかを確認
以下のURLを開き、右上の「Login」を開くと、自分のダッシュボード画面に遷移するので、「Database」タブを開いて「test」が作成されているかを確認します。
以下のように作成されているはず
③テーブルを作成
-
「test」を開き、「Outerbase Studio」を開きます。
↓
-
「New+」をクリックし、以下のようにテーブルの情報を設定し、「Save」をクリックすると、テーブルが作成されます。
↓「Save」をクリック
④データを追加
以下のようにデータを追加します。
これでテーブルの準備は完了です。
Next.jsアプリケーションからTursoにアクセスしてみよう
Tursoのデータベースにアクセスするには、トークンの作成とアクセスしたいデータベースのURLを取得する必要があります。
トークンの作成、取得
まずは、CLIで以下のコマンドを実行しましょう。
turso db tokens create test
実行後、トークンが作成され、ターミナルに出力されるので、コピーしておきましょう。
URLを取得
URLは以下からコピーできます。
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>
);
}
以下のようにデータを取得できました!
Discussion