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.

Ir a la instalación

Datos de origen

Repositorio
neondatabase/neon-js
Última actividad en el origen
22 de enero de 2026 a las 11:01
Idioma detectado de SKILL.md
inglés
Estrellas
17
Forks
16

Opciones de instalación

De forma predeterminada está seleccionado el prompt que primero revisa el origen. Puedes cambiar a un comando directo o descargar una copia local.

Revisa los archivos de origen

Lee SKILL.md y los archivos complementarios que muestra SkillsMP antes de decidir si quieres instalarlo.

Mostrando SKILL.md

SKILL.md
Instrucciones de origen · Vista previa de solo lectura
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';
Ver en GitHub
Este SKILL.md es muy grande, por eso SkillsMP muestra aqui solo la primera seccion. Ver en GitHub