Usage
Turso에서 TypeScript, Python, Go로 동기화를 활성화하고 사용하는 방법을 다루는 가이드예요. 데이터베이스 준비부터 push/pull, 체크포인트, 통계 조회까지 차례로 따라 해 보세요.
출처: 문서
본문
이 가이드는 Turso 데이터베이스를 준비하고 애플리케이션에서 동기화 기능을 사용하는 방법을 보여 줘요.
이 사용법은 로컬 Turso 데이터베이스를 동기화하기 위해 Turso Cloud를 사용하며, 계정이 있다고 가정해요. * [Quickstart](/quickstart)를 따라 CLI를 설치하고 데이터베이스를 만들어요.* 데이터베이스 URL(`turso://...`)을 확인해요.
```
turso db show <db>
```
* 앱용 토큰을 만들어요.
```
turso db tokens create <db>
```
동기화를 켜려면 세 가지 필수 요소가 필요해요.
* Local path: 로컬에 저장되는 동기화된 tursodb 파일의 위치
* Remote URL: Turso Cloud URL (`turso://...`)
* Auth token: 요청을 인증하는 Turso Cloud 토큰
<CodeGroup>
```ts TypeScript
import { connect } from '@tursodatabase/sync';
const db = await connect({
path: './app.db', // local path
url: 'turso://...', // remote URL (turso db show <db-name> --url로 생성)
authToken: process.env.TURSO_AUTH_TOKEN, // authentication token (turso db tokens create <db-name>로 생성)
// longPollTimeoutMs: 10_000, // optional: server waits before replying to pull
// bootstrapIfEmpty: false, // set to false to avoid bootstrapping on first run
});
```
```py Python
import os
import turso.sync
conn = turso.sync.connect(
path="./app.db", # local path
remote_url="turso://...", # remote URL (turso db show <db-name> --url로 생성)
auth_token=os.environ["TURSO_AUTH_TOKEN"], # authentication token (turso db tokens create <db-name>로 생성)
# long_poll_timeout_ms=10_000, # optional: server waits before replying to pull
# bootstrap_if_empty=False, # set to false to avoid bootstrapping on first run
)
```
```go Go
package main
import (
\tturso "turso.tech/database/tursogo"
)
db, err := turso.NewTursoSyncDb(ctx, turso.TursoSyncDbConfig{
Path: "./app.db", // local path
RemoteUrl: "turso://...", // remote URL (turso db show <db-name> --url로 생성)
AuthToken: os.Getenv("TURSO_AUTH_TOKEN"), // authentication token (turso db tokens create <db-name>로 생성)
// LongPollTimeoutMs: 10_000, // optional: server waits before replying to pull
// BootstrapIfEmpty: new(bool), // *bool; point at false to avoid bootstrapping on first run
})
```
</CodeGroup>
<Note>
첫 실행에서 로컬 데이터베이스는 원격으로부터 자동으로 부트스트랩돼요. 그래서 초기 connect 시점에 원격에 접근할 수 있어야 해요.
`bootstrap_if_empty`를 `false`로 설정하면 로컬 데이터베이스는 비어 있는 상태로 시작해요.
이후 언제든 `pull()`을 명시적으로 호출해서 부트스트랩하거나 갱신할 수 있어요.
</Note>
push는 로컬 변경을 Turso Cloud 서버로 보내요. 내부적으로는 논리적 문장(logical statement)이 전송되고, 충돌이 나면 "last push wins" 전략을 따라요.
<CodeGroup>
```ts TypeScript
await db.exec("CREATE TABLE IF NOT EXISTS notes(id TEXT PRIMARY KEY, body TEXT)");
await db.exec("INSERT INTO notes VALUES ('n1', 'hello')");
await db.push();
```
```py Python
conn.execute("CREATE TABLE IF NOT EXISTS notes(id TEXT PRIMARY KEY, body TEXT)")
conn.commit()
conn.execute("INSERT INTO notes VALUES ('n1', 'hello')")
conn.commit()
conn.push()
```
```go Go
// create *sql.DB instance
conn, err := db.Connect(ctx)
if err != nil {
return err
}
_, err = conn.ExecContext(ctx, "CREATE TABLE IF NOT EXISTS notes(id TEXT PRIMARY KEY, body TEXT)")
if err != nil {
return err
}
_, err = conn.ExecContext(ctx, "INSERT INTO notes VALUES ('n1', 'hello')")
if err != nil {
return err
}
if err := db.Push(ctx); err != nil {
\treturn err
}
```
</CodeGroup>
pull은 원격 변경을 가져와 로컬에 적용해요. 무언가 바뀌었는지 알려 주는 불리언 값을 돌려줘요.
* 서버가 변경을 기다렸다가 빈 응답을 피하게 하려면 `long_poll_timeout_ms`/`LongPollTimeoutMs`를 설정하세요.
* 이전에 push했다면, 서버 쪽 충돌 해결 프레임 때문에 이후의 pull이 변경이 있었다고 알려줄 수 있어요.
<CodeGroup>
```ts TypeScript
// 로컬에서 무언가 바뀌었으면 true를 돌려줘요
const changed = await db.pull();
console.info('pulled changes:', changed);
```
```py Python
changed = conn.pull()
print("pulled changes:", changed)
```
```go Go
changed, err := db.Pull(ctx)
if err != nil {
\treturn err
}
log.Println("pulled changes:", changed)
```
</CodeGroup>
checkpoint는 동기화 상태를 유지하면서 로컬 WAL을 압축해 디스크 사용량을 한도 안으로 묶어 줘요.
<CodeGroup>
```ts TypeScript
await db.checkpoint();
```
```py Python
conn.checkpoint()
```
```go Go
if err := db.Checkpoint(ctx); err != nil {
\treturn err
}
```
</CodeGroup>
stats는 동기화 동작과 사용량(WAL 크기, 마지막 push/pull 시각, 네트워크 사용량, revision 등)을 관찰하게 해 줘요.
<CodeGroup>
```ts TypeScript
const s = await db.stats();
console.info({
cdcOperations: s.cdcOperations,
mainWalSize: s.mainWalSize,
revertWalSize: s.revertWalSize,
networkReceivedBytes: s.networkReceivedBytes,
networkSentBytes: s.networkSentBytes,
lastPullUnixTime: s.lastPullUnixTime,
lastPushUnixTime: s.lastPushUnixTime,
revision: s.revision,
});
```
```py Python
s = conn.stats()
print({
"cdc_operations": s.cdc_operations,
"main_wal_size": s.main_wal_size,
"revert_wal_size": s.revert_wal_size,
"network_received_bytes": s.network_received_bytes,
"network_sent_bytes": s.network_sent_bytes,
"last_pull_unix_time": s.last_pull_unix_time,
"last_push_unix_time": s.last_push_unix_time,
"revision": s.revision,
})
```
```go Go
s, err := db.Stats(ctx)
if err != nil {
\treturn err
}
log.Printf("stats: cdc=%v, main=%d revert=%d rx=%d tx=%d pull=%d push=%d revision=%s",
s.CdcOperations,
s.MainWalSize,
s.RevertWalSize,
s.NetworkReceivedBytes,
s.NetworkSentBytes,
s.LastPullUnixTime,
s.LastPushUnixTime,
s.Revision,
)
```
</CodeGroup>
Offline-first writes
인터넷 연결 없이도 쓰기를 받아야 하는 앱이라면, 로컬에 쓰고 연결이 살아나면 push()를 호출하세요. 모든 변경은 동기화될 수 있을 때까지 로컬 데이터베이스 파일에 안전하게 저장돼요.
// bootstrapIfEmpty: false는 첫 실행에서 원격에 접근하지 않고도 // 앱이 오프라인으로 시작할 수 있게 해 줘요 const db = await connect({ path: './local.db', url: process.env.TURSO_URL!, authToken: process.env.TURSO_AUTH_TOKEN!, bootstrapIfEmpty: false, });
async function syncWhenOnline(db) { try { await db.push(); } catch (e) { // 연결 없음 — 변경은 로컬 파일에 안전하게 보관되고 // 다음 push() 호출 때 동기화돼요 } }
// 앱 시작 시 온라인이라면 최신 상태를 pull해요 try { await db.pull(); } catch (e) { // 오프라인 — 로컬 데이터는 여전히 읽고 쓸 수 있어요 }
// 타이머나 연결 이벤트에서 await syncWhenOnline(db);
```py Python
import os
import turso.sync
# bootstrap_if_empty=False는 첫 실행에서 원격에 접근하지 않고도
# 앱이 오프라인으로 시작할 수 있게 해 줘요
conn = turso.sync.connect(
path="./local.db",
remote_url=os.environ["TURSO_URL"],
auth_token=os.environ["TURSO_AUTH_TOKEN"],
bootstrap_if_empty=False,
)
def sync_when_online(conn):
try:
conn.push()
except Exception:
# 연결 없음 — 변경은 로컬 파일에 안전하게 보관되고
# 다음 push() 호출 때 동기화돼요
pass
# 앱 시작 시 온라인이라면 최신 상태를 pull해요
try:
conn.pull()
except Exception:
# 오프라인 — 로컬 데이터는 여전히 읽고 쓸 수 있어요
pass
# 타이머나 연결 이벤트에서
sync_when_online(conn)
// BootstrapIfEmpty를 false로 가리키면 첫 실행에서 원격에 접근하지 않고도
// 앱이 오프라인으로 시작할 수 있어요
noBootstrap := false
db, err := turso.NewTursoSyncDb(ctx, turso.TursoSyncDbConfig{
\tPath: "./local.db",
\tRemoteUrl: os.Getenv("TURSO_URL"),
\tAuthToken: os.Getenv("TURSO_AUTH_TOKEN"),
\tBootstrapIfEmpty: &noBootstrap,
})
func syncWhenOnline(ctx context.Context, db *turso.TursoSyncDb) {
\tif err := db.Push(ctx); err != nil {
\t\t// 연결 없음 — 변경은 로컬 파일에 안전하게 보관되고
\t\t// 다음 Push() 호출 때 동기화돼요
\t\tlog.Println("push deferred:", err)
\t}
}
// 앱 시작 시 온라인이라면 최신 상태를 pull해요
if _, err := db.Pull(ctx); err != nil {
\t// 오프라인 — 로컬 데이터는 여전히 읽고 쓸 수 있어요
\tlog.Println("pull deferred:", err)
}
// 타이머나 연결 이벤트에서
syncWhenOnline(ctx, db)
이것은 @libsql/client Embedded Replicas의 offline: true 플래그에 해당하는 현대적인 방식이에요. Turso Sync에서는 모든 읽기와 쓰기가 기본적으로 로컬에서 일어나고, 명시적인 push()와 pull() 호출로 동기화 시점을 직접 제어해요.
더 알아보기 (Learn more)
- Checkpoint - 로컬 WAL 압축
- Conflict Resolution - last push wins 전략 상세
- Local Sync Server - 로컬 동기화 서버로 테스트
- Partial Sync - 필요한 페이지만 동기화
- Embedded Replicas - 이전 세대 임베디드 복제본