Next.js Setup
This guide covers setting up SyncRabbit in a Next.js application with automatic engine management.
Installation
bash
npm install @syncrabbit/nextjsSetup
1. Environment Variables
Create or update your .env file:
bash
DATABASE_URL=postgresql://user:password@host:5432/database2. Initialize Database
Run the init command to create the replication slot (one-time setup):
bash
npx syncrabbit init3. Start Engine on Boot
Create instrumentation.ts in your project root:
typescript
export async function register() {
if (process.env.NEXT_RUNTIME === "nodejs") {
const { registerSyncRabbit } = await import("@syncrabbit/nextjs/server");
await registerSyncRabbit();
}
}4. Add Provider
Create a client component wrapper:
tsx
// components/SyncRabbitRootProvider.tsx
"use client";
import { SyncRabbitProvider } from "@syncrabbit/nextjs";
export function SyncRabbitRootProvider({
children,
}: {
children: React.ReactNode;
}) {
return <SyncRabbitProvider>{children}</SyncRabbitProvider>;
}Wrap your app in app/layout.tsx:
tsx
import { SyncRabbitRootProvider } from "@/components/SyncRabbitRootProvider";
export default function RootLayout({
children,
}: {
children: React.ReactNode;
}) {
return (
<html>
<body>
<SyncRabbitRootProvider>{children}</SyncRabbitRootProvider>
</body>
</html>
);
}Usage
useTable - Subscribe to a Table
tsx
"use client";
import { useTable } from "@syncrabbit/nextjs";
interface Todo {
id: number;
title: string;
completed: boolean;
}
export default function TodoList() {
const { data: todos, loading, error } = useTable<Todo>("todos", {
initialFetch: async () => {
const res = await fetch("/api/todos");
return res.json();
},
});
if (loading) return <p>Loading...</p>;
if (error) return <p>Error: {error.message}</p>;
return (
<ul>
{todos.map((todo) => (
<li key={todo.id}>{todo.title}</li>
))}
</ul>
);
}useWatch - React to Changes
tsx
"use client";
import { useWatch } from "@syncrabbit/nextjs";
import { useQueryClient } from "@tanstack/react-query";
export function OrderWatcher() {
const queryClient = useQueryClient();
useWatch(["orders", "order_items"], () => {
queryClient.invalidateQueries({ queryKey: ["orders"] });
});
return null;
}useMutation - Write with Instant Invalidation
tsx
"use client";
import { useMutation } from "@syncrabbit/nextjs";
export function CreateTodo() {
const { mutate, loading } = useMutation({
tables: ["todos"],
mutationFn: async (data: { title: string }) => {
const res = await fetch("/api/todos", {
method: "POST",
body: JSON.stringify(data),
});
return res.json();
},
});
const handleSubmit = (e: React.FormEvent<HTMLFormElement>) => {
e.preventDefault();
const formData = new FormData(e.currentTarget);
mutate({ title: formData.get("title") as string });
};
return (
<form onSubmit={handleSubmit}>
<input name="title" placeholder="New todo" />
<button type="submit" disabled={loading}>
Add
</button>
</form>
);
}