
Company News
Socket Named Top Sales Organization by RepVue
Socket won two 2026 Reppy Awards from RepVue, ranking in the top 5% of all sales orgs. AE Alexandra Lister shares what it's like to grow a sales career here.
@neondatabase/neon-js
Advanced tools
TypeScript SDK for Neon Auth and Data API - authentication and PostgreSQL querying
The official TypeScript SDK for Neon, combining authentication and database querying in a familiar interface.
@neondatabase/neon-js is a comprehensive SDK that brings together Neon Auth and Neon Data API. It provides a unified client for managing authentication and querying PostgreSQL databases with a familiar, intuitive interface.
Key Features:
It's up to you how you want to query your Postgres database! Neon Data API is a PostgREST-compatible REST service for your Neon database. neon-js exposes the REST-based query functions to leverage Data API. However, you can also use Data API directly with PostgREST and we also maintain a simple Postgres client here.
That said, you don't need Data API or neon-js to query Neon. Neon works great with all major ORMs (Drizzle, Prisma, Kysely) and Postgres clients (node-postgres, postgres.js). We also offer a serverless driver for edge and serverless environments without TCP client or connection pooling support (which also is available as a Drizzle and Prisma adapter).
npm install @neondatabase/neon-js
# or
bun add @neondatabase/neon-js
Before using neon-js, you'll need:
Data API URL format:
https://ep-xxx.apirest.c-2.us-east-2.aws.neon.build/dbname/rest/v1
Auth URL format:
https://ep-xxx.neonauth.c-2.us-east-2.aws.neon.build/dbname/auth
Create a .env or .env.local file:
# Next.js
NEON_AUTH_BASE_URL=https://ep-xxx.neonauth.c-2.us-east-2.aws.neon.build/dbname/auth
NEXT_PUBLIC_NEON_AUTH_URL=https://ep-xxx.neonauth.c-2.us-east-2.aws.neon.build/dbname/auth
NEON_DATA_API_URL=https://ep-xxx.apirest.c-2.us-east-2.aws.neon.build/dbname/rest/v1
# Vite/React
VITE_NEON_AUTH_URL=https://ep-xxx.neonauth.c-2.us-east-2.aws.neon.build/dbname/auth
VITE_NEON_DATA_API_URL=https://ep-xxx.apirest.c-2.us-east-2.aws.neon.build/dbname/rest/v1
import { createClient } from '@neondatabase/neon-js';
// Database type generated via: npx @neondatabase/neon-js gen-types --db-url "..."
// See "TypeScript" section below for details
const client = createClient<Database>({
auth: {
url: import.meta.env.VITE_NEON_AUTH_URL,
// Optional: allow unauthenticated users to query data via RLS
// allowAnonymous: true,
},
dataApi: {
url: import.meta.env.VITE_NEON_DATA_API_URL,
},
});
// Authenticate
await client.auth.signIn.email({
email: 'user@example.com',
password: 'secure-password',
});
// Query database (token automatically injected)
const { data: users } = await client
.from('users')
.select('*')
.eq('status', 'active');
You can optionally specify an adapter for different API styles:
Use this adapter if you're migrating from Supabase or prefer the Supabase API style:
import { createClient, SupabaseAuthAdapter } from '@neondatabase/neon-js';
// Database type generated via: npx @neondatabase/neon-js gen-types --db-url "..."
// See "TypeScript" section below for details
const client = createClient<Database>({
auth: {
adapter: SupabaseAuthAdapter(),
url: import.meta.env.VITE_NEON_AUTH_URL,
},
dataApi: {
url: import.meta.env.VITE_NEON_DATA_API_URL,
},
});
// Supabase-compatible API
await client.auth.signInWithPassword({
email: 'user@example.com',
password: 'secure-password',
});
const { data: session } = await client.auth.getSession();
Use this adapter in React applications to get access to hooks like useSession:
import { createClient } from '@neondatabase/neon-js';
import { BetterAuthReactAdapter } from '@neondatabase/neon-js/auth/react/adapters';
// Database type generated via: npx @neondatabase/neon-js gen-types --db-url "..."
// See "TypeScript" section below for details
const client = createClient<Database>({
auth: {
adapter: BetterAuthReactAdapter(),
url: import.meta.env.VITE_NEON_AUTH_URL,
},
dataApi: {
url: import.meta.env.VITE_NEON_DATA_API_URL,
},
});
// Use in React components
function MyComponent() {
const session = client.auth.useSession();
if (session.isPending) return <div>Loading...</div>;
if (!session.data) return <div>Not logged in</div>;
return <div>Hello, {session.data.user.name}</div>;
}
Enable allowAnonymous to let unauthenticated users query data. This uses an anonymous token for RLS-based access control:
import { createClient } from '@neondatabase/neon-js';
const client = createClient<Database>({
auth: {
url: import.meta.env.VITE_NEON_AUTH_URL,
allowAnonymous: true, // Enable anonymous data access
},
dataApi: {
url: import.meta.env.VITE_NEON_DATA_API_URL,
},
});
// Works without signing in - uses anonymous token for RLS
const { data: publicItems } = await client.from('public_items').select();
await client.auth.signUp.email({
email: 'user@example.com',
password: 'secure-password',
name: 'John Doe',
});
// Email & Password
await client.auth.signIn.email({
email: 'user@example.com',
password: 'secure-password',
});
// OAuth
await client.auth.signIn.social({
provider: 'google',
callbackURL: '/dashboard',
});
// Get current session
const session = await client.auth.getSession();
// Sign out
await client.auth.signOut();
When using SupabaseAuthAdapter, you get access to the Supabase-compatible API:
// Sign up with metadata
await client.auth.signUp({
email: 'user@example.com',
password: 'secure-password',
options: {
data: { name: 'John Doe' },
},
});
// Sign in
await client.auth.signInWithPassword({
email: 'user@example.com',
password: 'secure-password',
});
// OAuth
await client.auth.signInWithOAuth({
provider: 'google',
options: { redirectTo: '/dashboard' },
});
// Session with data wrapper
const { data: session } = await client.auth.getSession();
const { data: user } = await client.auth.getUser();
// Auth state changes
client.auth.onAuthStateChange((event, session) => {
console.log(event, session);
});
// Simple select
const { data } = await client
.from('users')
.select('id, name, email');
// With filters
const { data } = await client
.from('posts')
.select('*')
.eq('status', 'published')
.gt('views', 100)
.order('created_at', { ascending: false })
.limit(10);
// Joins
const { data } = await client
.from('posts')
.select(`
id,
title,
author:users(name, email)
`)
.eq('status', 'published');
// Insert single row
const { data } = await client
.from('users')
.insert({
name: 'Alice',
email: 'alice@example.com',
})
.select();
// Insert multiple rows
const { data } = await client
.from('users')
.insert([
{ name: 'Bob', email: 'bob@example.com' },
{ name: 'Carol', email: 'carol@example.com' },
])
.select();
const { data } = await client
.from('users')
.update({ status: 'inactive' })
.eq('last_login', null)
.select();
const { data } = await client
.from('users')
.delete()
.eq('status', 'deleted')
.select();
const { data } = await client
.rpc('get_user_stats', {
user_id: 123,
start_date: '2024-01-01',
});
import { createClient } from '@neondatabase/neon-js';
const client = createClient({
// Auth configuration
auth: {
url: 'https://your-auth-server.neon.tech/auth',
allowAnonymous: true, // Optional: enable anonymous data access
},
// Data API configuration
dataApi: {
url: 'https://your-data-api.neon.tech/rest/v1',
options: {
db: {
schema: 'public', // Default schema
},
global: {
headers: {
'X-Custom-Header': 'value',
},
},
},
},
});
# Auth URL
NEON_AUTH_URL=https://your-auth-server.neon.tech/auth
# Data API URL
NEON_DATA_API_URL=https://your-data-api.neon.tech/rest/v1
import { createClient } from '@neondatabase/neon-js';
const client = createClient({
auth: {
url: process.env.NEON_AUTH_URL!,
},
dataApi: {
url: process.env.NEON_DATA_API_URL!,
},
});
Pre-built login forms and auth pages are included. No extra installation needed.
Without Tailwind CSS:
import '@neondatabase/neon-js/ui/css';
With Tailwind CSS v4:
@import 'tailwindcss';
@import '@neondatabase/neon-js/ui/tailwind';
"use client"
import { NeonAuthUIProvider } from "@neondatabase/neon-js/auth/react/ui"
import "@neondatabase/neon-js/ui/css"
export function Providers({ children }) {
return (
<NeonAuthUIProvider authClient={client.auth} redirectTo="/dashboard">
{children}
</NeonAuthUIProvider>
)
}
Option A: Full Auth Pages (Recommended)
Use AuthView to render complete auth flows based on the URL path:
import { AuthView } from "@neondatabase/neon-js/auth/react/ui"
// Renders sign-in, sign-up, forgot-password, etc. based on path
<AuthView path="sign-in" />
Option B: Individual Components
import { SignInForm, UserButton } from "@neondatabase/neon-js/auth/react/ui"
<SignInForm />
<UserButton />
Available components: SignInForm, SignUpForm, UserButton, AuthView, AccountView, OrganizationView
For full documentation and theming, see @neondatabase/auth-ui.
Generate TypeScript types from your database schema:
npx @neondatabase/neon-js gen-types --db-url "postgresql://user:pass@host/db"
Use generated types for full type safety:
import type { Database } from './types/database';
import { createClient } from '@neondatabase/neon-js';
const client = createClient<Database>({
auth: {
url: process.env.NEON_AUTH_URL!,
},
dataApi: {
url: process.env.NEON_DATA_API_URL!,
},
});
// Fully typed queries!
const { data } = await client
.from('users') // Autocomplete for table names
.select('id, name, email') // Autocomplete for column names
.eq('status', 'active'); // Type checking for values
Generate TypeScript types from your database:
# Generate types
npx @neondatabase/neon-js gen-types \
--db-url "postgresql://user:pass@host/db" \
--output ./types/database.ts
# With schema filtering
npx @neondatabase/neon-js gen-types \
--db-url "postgresql://user:pass@host/db" \
--schemas public,auth \
--output ./types/database.ts
Options:
--db-url, -c - PostgreSQL connection string (required)--output, -o - Output file path (default: ./types/database.ts)--schemas, -s - Comma-separated list of schemas (default: public)Sessions are cached in memory with intelligent TTL:
Concurrent authentication calls are automatically deduplicated:
import { AuthError } from '@neondatabase/neon-js';
// Auth errors (SupabaseAuthAdapter)
try {
await client.auth.signInWithPassword({ email, password });
} catch (error) {
if (error instanceof AuthError) {
console.error('Auth error:', error.message);
}
}
// Database errors
const { data, error } = await client.from('users').select();
if (error) {
console.error('Database error:', error.message);
}
// app/lib/neon.ts
import { createClient } from '@neondatabase/neon-js';
export const neon = createClient({
auth: {
url: process.env.NEON_AUTH_URL!,
},
dataApi: {
url: process.env.NEON_DATA_API_URL!,
},
});
// app/api/users/route.ts
import { neon } from '@/lib/neon';
export async function GET() {
const { data: users } = await neon.from('users').select('*');
return Response.json(users);
}
import { createClient } from '@neondatabase/neon-js';
import { BetterAuthReactAdapter } from '@neondatabase/neon-js/auth/react/adapters';
const client = createClient({
auth: {
adapter: BetterAuthReactAdapter(),
url: process.env.NEXT_PUBLIC_NEON_AUTH_URL!,
},
dataApi: {
url: process.env.NEXT_PUBLIC_NEON_DATA_API_URL!,
},
});
export function useAuth() {
const session = client.auth.useSession();
return {
user: session.data?.user ?? null,
isPending: session.isPending,
signIn: (email: string, password: string) =>
client.auth.signIn.email({ email, password }),
signOut: () => client.auth.signOut(),
};
}
neon-js provides a Supabase-compatible API, making migration straightforward.
- "@supabase/supabase-js": "^2.74.0"
+ "@neondatabase/neon-js": "^0.1.0"
- VITE_SUPABASE_URL="https://xxx.supabase.co"
- VITE_SUPABASE_ANON_KEY="..."
+ VITE_NEON_DATA_API_URL="https://xxx.neon.tech/neondb/rest/v1"
+ VITE_NEON_AUTH_URL="https://your-auth-server.com"
- import { createClient } from '@supabase/supabase-js';
+ import { createClient, SupabaseAuthAdapter } from '@neondatabase/neon-js';
- export const client = createClient(
- import.meta.env.VITE_SUPABASE_URL,
- import.meta.env.VITE_SUPABASE_ANON_KEY
- );
+ export const client = createClient<Database>({
+ auth: {
+ adapter: SupabaseAuthAdapter(), // Must call as function!
+ url: import.meta.env.VITE_NEON_AUTH_URL,
+ },
+ dataApi: {
+ url: import.meta.env.VITE_NEON_DATA_API_URL,
+ },
+ });
All authentication methods work the same:
// These work identically
await client.auth.signInWithPassword({ email, password });
await client.auth.signUp({ email, password });
const { data: session } = await client.auth.getSession();
client.auth.onAuthStateChange((event, session) => { /* ... */ });
All database queries work the same:
// These work identically
const { data } = await client.from('items').select();
await client.from('items').insert({ name: 'New Item' });
await client.from('items').update({ status: 'done' }).eq('id', 1);
await client.from('items').delete().eq('id', 1);
See the todo-guardian-pro migration PR for a complete migration example.
This package combines two underlying packages:
@neondatabase/auth - Authentication adapters (can be used standalone)@neondatabase/postgrest-js - PostgreSQL client (can be used standalone)Apache-2.0
FAQs
TypeScript SDK for Neon Auth and Data API - authentication and PostgreSQL querying
The npm package @neondatabase/neon-js receives a total of 12,126 weekly downloads. As such, @neondatabase/neon-js popularity was classified as popular.
We found that @neondatabase/neon-js demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 6 open source maintainers collaborating on the project.
Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Company News
Socket won two 2026 Reppy Awards from RepVue, ranking in the top 5% of all sales orgs. AE Alexandra Lister shares what it's like to grow a sales career here.

Security News
NIST will stop enriching most CVEs under a new risk-based model, narrowing the NVD's scope as vulnerability submissions continue to surge.

Company News
/Security News
Socket is an initial recipient of OpenAI's Cybersecurity Grant Program, which commits $10M in API credits to defenders securing open source software.