Skip to main content

neon-js-react

Sets up the full Neon SDK with authentication AND database queries in React apps (Vite, CRA). Creates typed client, generates database types, and configures auth UI. Use for auth + database integration.

Zur Installation springen

Quellinformationen

Repository
neondatabase/neon-js
Letzte Quellaktivität
22. Januar 2026 um 11:01
Erkannte Sprache von SKILL.md
Englisch
Sterne
16
Forks
15

Installationsoptionen

Standardmäßig ist der Prompt ausgewählt, der zuerst die Quelle prüft. Sie können zu einem direkten Befehl wechseln oder eine lokale Kopie herunterladen.

Quelldateien prüfen

Lesen Sie SKILL.md und alle von SkillsMP angezeigten Begleitdateien, bevor Sie sich für eine Installation entscheiden.

SKILL.md wird angezeigt

SKILL.md
Quellanweisungen · Schreibgeschützte Vorschau
name
neon-js-react
description
Sets up the full Neon SDK with authentication AND database queries in React apps (Vite, CRA). Creates typed client, generates database types, and configures auth UI. Use for auth + database integration.
allowed-tools
["Bash","Write","Read","Edit","Glob","Grep"]
# Neon JS for React Help developers set up @neondatabase/neon-js with authentication AND database queries in React applications (Vite, CRA, etc.). ## When to Use Use this skill when: - Setting up Neon Auth + Database in a React app (Vite, CRA, etc.) - User needs both authentication AND database queries - User mentions "neon-js", "neon auth + database", or "full neon SDK" - User is NOT using Next.js (for Next.js, use `neon-auth-nextjs` as a starting point and add Data API configuration, or see `examples/nextjs-neon-auth/`) ## Critical Rules 1. **Adapter Factory Pattern**: Always call adapters with `()` ```typescript adapter: SupabaseAuthAdapter() // Correct adapter: SupabaseAuthAdapter // Wrong - missing () ``` 2. **React Adapter Import**: NOT exported from main - use subpath ```typescript import { BetterAuthReactAdapter } from '@neondatabase/neon-js/auth/react/adapters'; ``` 3. **Type Safety**: Always use Database generic for type-safe queries ```typescript const client = createClient<Database>({...}); ``` 4. **CSS Import**: Choose ONE - either `/ui/css` OR `/ui/tailwind`, never both --- ## Setup ### 1. Install ```bash npm install @neondatabase/neon-js ``` ### 2. Generate Database Types ```bash npx neon-js gen-types --db-url "postgresql://user:pass@host:5432/db" --output src/database.types.ts ``` **CLI Options:** ```bash npx neon-js gen-types --db-url <url> [options] # Required --db-url <url> Database connection string # Optional --output, -o <path> Output file (default: database.types.ts) --schema, -s <name> Schema to include (repeatable, default: public) --postgrest-v9-compat Disable one-to-one relationship detection --query-timeout <duration> Query timeout (e.g., 30s, 1m, default: 15s) ``` ### 3. Create Client (`src/client.ts`) ```typescript import { createClient } from '@neondatabase/neon-js'; import type { Database } from './database.types'; export const neonClient = createClient<Database>({ auth: { url: import.meta.env.VITE_NEON_AUTH_URL, // allowAnonymous: true, // Enable for RLS access without login }, dataApi: { url: import.meta.env.VITE_NEON_DATA_API_URL, }, }); ``` ### 4. Create Provider (`src/providers.tsx`) ```typescript import { NeonAuthUIProvider } from '@neondatabase/neon-js/auth/react'; import { useNavigate } from 'react-router-dom'; import { Link } from 'react-router-dom'; import { neonClient } from './client'; // Import CSS (choose one) import '@neondatabase/neon-js/ui/css'; export function Providers({ children }: { children: React.ReactNode }) { const navigate = useNavigate(); return ( <NeonAuthUIProvider authClient={neonClient.auth} navigate={navigate} redirectTo="/dashboard" Link={({href, children}) => <Link to={href}>{children}</Link>} > {children} </NeonAuthUIProvider> ); } ``` ### 5. Wrap App (`src/main.tsx`) ```typescript import { BrowserRouter } from 'react-router-dom'; import { Providers } from './providers'; import App from './App'; createRoot(document.getElementById('root')!).render( <BrowserRouter> <Providers> <App /> </Providers> </BrowserRouter> ); ``` ### 6. Environment Variables (`.env.local`) ``` VITE_NEON_AUTH_URL=https://your-auth.neon.tech VITE_NEON_DATA_API_URL=https://your-data-api.neon.tech/rest/v1 ``` --- ## CSS & Styling ### Import Options **Without Tailwind** (pre-built CSS bundle ~47KB): ```typescript // In provider or main.tsx import '@neondatabase/neon-js/ui/css'; ``` **With Tailwind CSS v4**: ```css @import 'tailwindcss'; @import '@neondatabase/neon-js/ui/tailwind'; ``` **IMPORTANT**: Never import both - causes duplicate styles. ### Dark Mode ```typescript <NeonAuthUIProvider defaultTheme="system" // 'light' | 'dark' | 'system' // ... > ``` ### Custom Theming Override CSS variables in your stylesheet: ```css :root { --primary: oklch(0.7 0.15 250); --primary-foreground: oklch(0.98 0 0); --background: oklch(1 0 0); --foreground: oklch(0.1 0 0); --card: oklch(1 0 0); --border: oklch(0.9 0 0); --radius: 0.5rem; } .dark { --background: oklch(0.15 0 0); --foreground: oklch(0.98 0 0); } ``` --- ## NeonAuthUIProvider Props Full configuration: ```typescript <NeonAuthUIProvider // Required authClient={neonClient.auth} // Note: .auth property of neonClient // Navigation navigate={navigate} Link={({href, children}) => <Link to={href}>{children}</Link>} redirectTo="/dashboard" // Social/OAuth social={{ providers: ['google'], }} // Feature Flags emailOTP={true} emailVerification={true} magicLink={false} multiSession={false} credentials={{ forgotPassword: true }} // Sign Up Fields signUp={{ fields: ['name'] }} // Account Fields account={{ fields: ['image', 'name', 'company'] }} // Organizations organization={{}} // Dark Mode defaultTheme="system" // Custom Labels localization={{ SIGN_IN: 'Welcome Back', SIGN_UP: 'Create Account', }} > {children} </NeonAuthUIProvider> ``` --- ## Database Queries ### Select ```typescript // Basic select const { data, error } = await neonClient .from('todos') .select('*'); // Select with filter const { data, error } = await neonClient .from('todos') .select('*') .eq('user_id', userId) .order('created_at', { ascending: false }); // Select with relations const { data, error } = await neonClient .from('posts') .select(` *, author:users(name, avatar), comments(id, content) `); // Single row const { data, error } = await neonClient .from('todos') .select('*') .eq('id', todoId) .single(); ``` ### Insert ```typescript // Single insert const { data, error } = await neonClient .from('todos') .insert({ title: 'New todo', user_id: userId }) .select() .single(); // Bulk insert const { data, error } = await neonClient .from('todos') .insert([ { title: 'Todo 1', user_id: userId }, { title: 'Todo 2', user_id: userId }, ]) .select(); ``` ### Update ```typescript const { data, error } = await neonClient .from('todos') .update({ completed: true }) .eq('id', todoId) .select() .single(); ``` ### Delete ```typescript const { error } = await neonClient .from('todos') .delete() .eq('id', todoId); ``` ### Upsert ```typescript const { data, error } = await neonClient .from('profiles') .upsert({ user_id: userId, bio: 'Updated bio' }) .select() .single(); ``` ### Filters ```typescript // Equality .eq('column', value) .neq('column', value) // Comparison .gt('column', value) // greater than .gte('column', value) // greater than or equal .lt('column', value) // less than .lte('column', value) // less than or equal // Pattern matching .like('column', '%pattern%') .ilike('column', '%pattern%') // case insensitive // Arrays .in('column', [1, 2, 3]) .contains('tags', ['javascript']) .containedBy('tags', ['javascript', 'typescript']) // Null .is('column', null) .not('column', 'is', null) // Range .range(0, 9) // pagination ``` ### Ordering & Pagination ```typescript const { data, error } = await neonClient .from('posts') .select('*') .order('created_at', { ascending: false }) .range(0, 9) // First 10 items .limit(10); ``` --- ## Auth Methods ### Default API (BetterAuth) ```typescript // Sign up await neonClient.auth.signUp.email({ email, password, name }); // Sign in await neonClient.auth.signIn.email({ email, password }); // OAuth await neonClient.auth.signIn.social({ provider: 'google', callbackURL: '/dashboard', }); // Get session const session = await neonClient.auth.getSession(); // Sign out await neonClient.auth.signOut(); ``` ### With SupabaseAuthAdapter ```typescript import { createClient, SupabaseAuthAdapter } from '@neondatabase/neon-js'; const neonClient = createClient<Database>({ auth: { url: import.meta.env.VITE_NEON_AUTH_URL, adapter: SupabaseAuthAdapter(), }, dataApi: { url: import.meta.env.VITE_NEON_DATA_API_URL, }, }); // Supabase-style methods await neonClient.auth.signUp({ email, password, options: { data: { name } } }); await neonClient.auth.signInWithPassword({ email, password }); await neonClient.auth.signInWithOAuth({ provider: 'google', options: { redirectTo } }); const { data: session } = await neonClient.auth.getSession(); await neonClient.auth.signOut(); // Event listener neonClient.auth.onAuthStateChange((event, session) => { console.log(event); // 'SIGNED_IN', 'SIGNED_OUT', 'TOKEN_REFRESHED' }); ``` ### With BetterAuthReactAdapter ```typescript import { createClient } from '@neondatabase/neon-js'; import { BetterAuthReactAdapter } from '@neondatabase/neon-js/auth/react/adapters';
Auf GitHub ansehen
Diese SKILL.md ist sehr gross, daher zeigt SkillsMP hier nur den ersten Abschnitt. Auf GitHub ansehen