Skip to main content

Using Kysely with Cuttlefish

Learn how to use Kysely with Cuttlefish to get full type safety for your database queries.

Prerequisites

Before starting, complete the Quick Start guide to set up Cuttlefish in your Next.js app.

Installation

Install the Kysely packages:
npm install @cuttlefish-sync/kysely kysely

Define your database schema

Create a type definition file for your database schema. We’ll create lib/db.ts:
import { Kysely } from 'kysely'

interface Database {
  todos: {
    id: number
    title: string
    completed: boolean
    created_at: Date
  }
}

// Type-only export for Cuttlefish
export type DB = Database
This is a type-only definition. You don’t need to create a Kysely instance - Cuttlefish handles the database connection through the dev server.

Using Kysely queries

Replace raw SQL queries with Kysely’s type-safe query builder using fromKysely:
'use client'

import { fromKysely } from '@cuttlefish-sync/kysely'
import { useLiveQuery } from '@cuttlefish-sync/react'
import type { DB } from '@/lib/db'

export default function Home() {
  const { data, loading, error } = useLiveQuery(
    fromKysely<DB>((db) =>
      db.selectFrom('todos')
        .selectAll()
        .orderBy('created_at', 'desc')
    )
  )

  if (loading) return <div>Loading...</div>
  if (error) return <div>Error: {error.message}</div>

  return (
    <div>
      <h1>My Todos</h1>
      <ul>
        {data?.map((todo) => (
          <li key={todo.id}>
            {todo.title} {todo.completed ? '✓' : ''}
          </li>
        ))}
      </ul>
    </div>
  )
}

Type safety benefits

With Kysely, we get:
  • Autocomplete: Your editor suggests available tables and columns
  • Type checking: TypeScript catches typos in table/column names at compile time
  • Return type inference: The data variable is automatically typed based on your query
  • Refactoring safety: Renaming database types updates all query usages

Next steps