Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.powersync.com/llms.txt

Use this file to discover all available pages before exploring further.

Introduction

@powersync/nuxt is a Nuxt module that wraps @powersync/vue and provides everything you need to build offline-first Nuxt applications. It re-exports all @powersync/vue composables so this is the only PowerSync dependency you need, and it adds a Nuxt Devtools integration with a PowerSync diagnostics panel for inspecting sync status, local data, config, and logs.

npm: @powersync/nuxt

Alpha: The Nuxt PowerSync integration is currently in Alpha. APIs and behavior may change. We welcome feedback in Discord or on GitHub.
PowerSync is tailored for client-side applications — there isn’t much benefit to using SSR with PowerSync. Nuxt evaluates plugins server-side unless you use the .client.ts suffix. The PowerSync Web SDK requires browser APIs that are not available in Node.js; it performs no-ops in a Node.js runtime rather than throwing errors, but you should not expect any data from PowerSync during server-side rendering. Always create your PowerSync plugin as plugins/powersync.client.ts to ensure it runs only in the browser.
For a complete working example, see the Nuxt + Supabase Todo List demo.

Setup

Install PowerSync Dependencies

npm install @powersync/nuxt
With npm (v7+), peer dependencies are installed automatically. With pnpm, you must install peer dependencies explicitly, as shown above.

Add the Module

Add @powersync/nuxt to the modules array in nuxt.config.ts and include the required Vite configuration:
nuxt.config.ts
export default defineNuxtConfig({
  modules: ['@powersync/nuxt'],
  vite: {
    optimizeDeps: {
      exclude: ['@powersync/web']
    },
    worker: {
      format: 'es'
    }
  }
});
If you are using Tailwind CSS in your project, see the Known Issues section.

Configure PowerSync in your Project

Define your Schema

Create a file at powersync/AppSchema.ts and define your local SQLite schema. PowerSync will hydrate these tables once the SDK connects to your PowerSync instance.
powersync/AppSchema.ts
import { column, Schema, Table } from '@powersync/web';

const lists = new Table({
  created_at: column.text,
  name: column.text,
  owner_id: column.text
});

const todos = new Table(
  {
    list_id: column.text,
    created_at: column.text,
    completed_at: column.text,
    description: column.text,
    created_by: column.text,
    completed_by: column.text,
    completed: column.integer
  },
  { indexes: { list: ['list_id'] } }
);

export const AppSchema = new Schema({
  todos,
  lists
});

// For types
export type Database = (typeof AppSchema)['types'];
export type TodoRecord = Database['todos'];
export type ListRecord = Database['lists'];
Learn more about defining your schema in the JavaScript Web SDK reference.

Create your Connector

Create a file at powersync/PowerSyncConnector.ts. The connector handles authentication and uploading local changes to your backend.
powersync/PowerSyncConnector.ts
import { UpdateType, type PowerSyncBackendConnector } from '@powersync/web';

export class PowerSyncConnector implements PowerSyncBackendConnector {
  async fetchCredentials() {
    // Return a JWT for the PowerSync Service to authenticate the client.
    // See https://docs.powersync.com/installation/authentication-setup
    // For quick local testing, use a development token:
    // https://docs.powersync.com/installation/authentication-setup/development-tokens
    return {
      endpoint: '[Your PowerSync instance URL]',
      token: '[Your auth token]'
    };
  }

  async uploadData(db: any) {
    // Send local changes to your backend.
    // See https://docs.powersync.com/client-sdk-references/javascript-web#3-integrate-with-your-backend
    const transaction = await db.getNextCrudTransaction();
    if (!transaction) return;

    try {
      for (const op of transaction.crud) {
        const record = { ...op.opData, id: op.id };
        switch (op.op) {
          case UpdateType.PUT:
            // TODO: send CREATE to your backend API
            break;
          case UpdateType.PATCH:
            // TODO: send PATCH to your backend API
            break;
          case UpdateType.DELETE:
            // TODO: send DELETE to your backend API
            break;
        }
      }
      await transaction.complete();
    } catch (error: any) {
      console.error('Data upload error - discarding', error);
      await transaction.complete();
    }
  }
}

Create the Plugin

Create a Nuxt plugin at plugins/powersync.client.ts. The .client.ts suffix ensures this only runs in the browser.
plugins/powersync.client.ts
import { NuxtPowerSyncDatabase, createPowerSyncPlugin } from '@powersync/nuxt';
import { AppSchema } from '~/powersync/AppSchema';
import { PowerSyncConnector } from '~/powersync/PowerSyncConnector';

export default defineNuxtPlugin({
  async setup(nuxtApp) {
    const db = new NuxtPowerSyncDatabase({
      database: {
        dbFilename: 'my-app.sqlite'
      },
      schema: AppSchema
    });

    const connector = new PowerSyncConnector();

    await db.init();
    await db.connect(connector);

    const plugin = createPowerSyncPlugin({ database: db });
    nuxtApp.vueApp.use(plugin);
  }
});

Using PowerSync

The module automatically exposes all @powersync/vue composables. You can import and use them directly in any component or composable.

Reading Data

components/TodoList.vue
<script setup lang="ts">
import { usePowerSync, useQuery, useStatus } from '@powersync/nuxt';

// Access the PowerSync database instance
const powersync = usePowerSync();

// Reactive query — re-renders automatically when data changes
const { data: lists, isLoading } = useQuery('SELECT * FROM lists ORDER BY created_at DESC');

// Connection status
const status = useStatus();
</script>

<template>
  <div>
    <p>Status: {{ status.connected ? 'Connected' : 'Offline' }}</p>
    <p v-if="isLoading">Loading...</p>
    <ul v-else>
      <li v-for="list in lists" :key="list.id">{{ list.name }}</li>
    </ul>
  </div>
</template>

Writing Data

Use execute to write to the local SQLite database. Changes are queued and uploaded to your backend via uploadData in the connector.
import { usePowerSync } from '@powersync/nuxt';
import { v4 as uuid } from 'uuid';

const powersync = usePowerSync();

await powersync.execute(
  'INSERT INTO lists (id, created_at, name, owner_id) VALUES (?, ?, ?, ?)',
  [uuid(), new Date().toISOString(), 'My List', currentUserId]
);

Kysely ORM (Optional)

The module optionally exposes a usePowerSyncKysely() composable for type-safe query building. You must install the driver and opt in via config. Install the driver:
npm install @powersync/kysely-driver
Enable it in nuxt.config.ts:
nuxt.config.ts
export default defineNuxtConfig({
  modules: ['@powersync/nuxt'],
  powersync: {
    kysely: true
  },
  vite: {
    optimizeDeps: {
      exclude: ['@powersync/web']
    },
    worker: {
      format: 'es'
    }
  }
});
Then use usePowerSyncKysely with your schema’s Database type for full type safety:
import { usePowerSyncKysely } from '@powersync/nuxt';
import { type Database } from '~/powersync/AppSchema';

const db = usePowerSyncKysely<Database>();

const lists = await db.selectFrom('lists').selectAll().execute();

DevTools

The @powersync/nuxt module includes a PowerSync diagnostics panel that integrates with Nuxt DevTools. It shows sync status, local data, config, and logs. See Nuxt DevTools Integration for setup instructions and available views.