New Research: Supply Chain Attack on Axios Pulls Malicious Dependency from npm.Details
Socket
Book a DemoSign in
Socket

@neondatabase/neon-js

Package Overview
Dependencies
Maintainers
6
Versions
34
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@neondatabase/neon-js

TypeScript SDK for Neon Auth and Data API - authentication and PostgreSQL querying

latest
Source
npmnpm
Version
0.2.0-beta.1
Version published
Weekly downloads
14K
23.83%
Maintainers
6
Weekly downloads
 
Created
Source

@neondatabase/neon-js

npm version npm downloads TypeScript License

The official TypeScript SDK for Neon, combining authentication and database querying in a familiar interface.

Overview

@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:

  • Integrated Authentication - Works out of the box with optional adapters (Supabase-compatible, React hooks)
  • PostgreSQL Querying - Full PostgREST client with type-safe queries
  • Anonymous Access - Optional RLS-based data access for unauthenticated users
  • High Performance - Session caching, request deduplication
  • Automatic Token Management - Seamless token injection for database queries
  • TypeScript First - Fully typed with strict type checking
  • Universal - Works in Node.js, browsers, and edge runtimes

How to query your Neon Serverless Postgres database?

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).

Installation

npm install @neondatabase/neon-js
# or
bun add @neondatabase/neon-js

Prerequisites

Before using neon-js, you'll need:

1. A Neon Account and Project

  • Sign up at neon.tech
  • Create a new project in the Neon Console

2. Enable the Data API (for database queries)

  • Go to your project settings in Neon Console
  • Enable the Data API feature
  • Copy your Data API URL

Data API URL format:

https://ep-xxx.apirest.c-2.us-east-2.aws.neon.build/dbname/rest/v1

3. Enable Neon Auth (for authentication)

  • Go to your project settings in Neon Console
  • Enable Neon Auth
  • Copy your Auth URL

Auth URL format:

https://ep-xxx.neonauth.c-2.us-east-2.aws.neon.build/dbname/auth

4. Configure Environment Variables

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

Quick Start

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');

Using Adapters

You can optionally specify an adapter for different API styles:

SupabaseAuthAdapter (Supabase-compatible API)

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();

BetterAuthReactAdapter (React Hooks)

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>;
}

Anonymous Access

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();

Authentication

Sign Up

await client.auth.signUp.email({
  email: 'user@example.com',
  password: 'secure-password',
  name: 'John Doe',
});

Sign In

// Email & Password
await client.auth.signIn.email({
  email: 'user@example.com',
  password: 'secure-password',
});

// OAuth
await client.auth.signIn.social({
  provider: 'google',
  callbackURL: '/dashboard',
});

Session Management

// Get current session
const session = await client.auth.getSession();

// Sign out
await client.auth.signOut();

SupabaseAuthAdapter API

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);
});

Database Querying

SELECT Queries

// 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 Queries

// 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();

UPDATE Queries

const { data } = await client
  .from('users')
  .update({ status: 'inactive' })
  .eq('last_login', null)
  .select();

DELETE Queries

const { data } = await client
  .from('users')
  .delete()
  .eq('status', 'deleted')
  .select();

RPC (Stored Procedures)

const { data } = await client
  .rpc('get_user_stats', {
    user_id: 123,
    start_date: '2024-01-01',
  });

Configuration

Client Options

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',
        },
      },
    },
  },
});

Environment Variables

# 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!,
  },
});

UI Components

Pre-built login forms and auth pages are included. No extra installation needed.

1. Import CSS

Without Tailwind CSS:

import '@neondatabase/neon-js/ui/css';

With Tailwind CSS v4:

@import 'tailwindcss';
@import '@neondatabase/neon-js/ui/tailwind';

2. Setup Provider

"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>
  )
}

3. Use Components

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.

TypeScript

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

CLI Tool

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)

Performance

Session Caching

Sessions are cached in memory with intelligent TTL:

  • Cold start: ~200ms (single network request)
  • Cached reads: <1ms (in-memory, no I/O)
  • Cache TTL: 60 seconds or until JWT expires
  • Smart expiration: Automatic based on JWT claims

Request Deduplication

Concurrent authentication calls are automatically deduplicated:

  • Without deduplication: 10 concurrent calls = 10 requests (~2000ms)
  • With deduplication: 10 concurrent calls = 1 request (~200ms)
  • Result: 10x faster, N-1 fewer server requests

Environment Compatibility

  • Node.js 14+ (with native fetch or polyfill)
  • Browser (all modern browsers)
  • Edge Runtime (Vercel, Cloudflare Workers, Deno, etc.)
  • Bun (native support)

Error Handling

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);
}

Examples

Next.js App Router

// 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);
}

React Hook with BetterAuthReactAdapter

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(),
  };
}

Supabase Migration Guide

neon-js provides a Supabase-compatible API, making migration straightforward.

1. Update Dependencies

- "@supabase/supabase-js": "^2.74.0"
+ "@neondatabase/neon-js": "^0.1.0"

2. Update Environment Variables

- 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"

3. Update Client Initialization

- 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,
+   },
+ });

4. No Code Changes Needed

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:

Resources

Support

License

Apache-2.0

Keywords

neon

FAQs

Package last updated on 29 Jan 2026

Did you know?

Socket

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.

Install

Related posts