Skill: leonaaardob/lb-neon-skill (version 0.1.0)

--- id: neon name: Neon Database version: 1.0.0 author: OpenClaw Community description: Complete Neon Serverless Postgres documentation. Covers serverless setup, branching, autoscaling, integrations (Vercel, Drizzle, Prisma), connection pooling, extensions, and best practices. categories: - database - documentation - postgresql - serverless tags: - neon - postgresql - serverless - database - vercel - drizzle - prisma - nextjs - branching - autoscaling homepage: https://neon.tech repository: https://github.com/neondatabase/neon documentation: https://neon.tech/docs --- ## ⚠️ Security Notice This skill contains Neon Database documentation with command examples. Commands are **for reference only** and should NEVER be auto-executed by agents without explicit user approval. # Neon Database Documentation Complete Neon Serverless Postgres documentation extracted from the official Neon website repository. ## Contents This skill includes **546 markdown files** (6.8MB) covering: ### Core Concepts - **Introduction** - What is Neon, architecture, and core concepts - **Get Started** - Quick start guides and initial setup - **Serverless** - Serverless PostgreSQL fundamentals ### Features - **Branching** - Database branching workflows (preview, development) - **Autoscaling** - Compute autoscaling and scale-to-zero - **Connection Pooling** - Connection pooling and serverless optimization - **Data API** - HTTP-based data access ### Integrations - **Vercel** - Vercel integration (env vars, preview branches) - **Drizzle ORM** - Drizzle setup and migrations - **Prisma** - Prisma integration - **Next.js** - Next.js + Neon patterns - **Auth** - Authentication integrations (Better Auth, Auth.js, Clerk, etc.) ### Database Management - **Manage** - Projects, branches, databases, roles, compute - **Import** - Data import strategies (PostgreSQL dump, CSV, etc.) - **Extensions** - PostgreSQL extensions (pgvector, PostGIS, timescaledb, etc.) - **Functions** - User-defined functions and stored procedures - **Data Types** - PostgreSQL data types and Neon-specific types ### Reference - **API Reference** - Neon API endpoints and CLI (neonctl) - **Security** - Security best practices, encryption, compliance - **PostgreSQL** - PostgreSQL-specific documentation - **AI/ML** - AI embeddings, RAG, pgvector ### Developer Resources - **Guides** - Step-by-step tutorials for common use cases - **Community** - Community resources and support channels ## Usage This skill provides comprehensive documentation for: 1. **Setting up Neon** - Creating projects, connecting to databases 2. **Integrations** - Connecting Neon to frameworks and ORMs (Vercel, Drizzle, Prisma, Next.js, Better Auth) 3. **Advanced Features** - Branching, autoscaling, connection pooling 4. **Best Practices** - Serverless optimization, security, performance 5. **API & CLI** - Programmatic access via API and neonctl CLI ## File Structure ``` docs/ ├── introduction/ # Core concepts, architecture ├── get-started/ # Quick start guides ├── serverless/ # Serverless PostgreSQL ├── connect/ # Connection strings, pooling ├── data-api/ # HTTP data access ├── manage/ # Project and database management ├── import/ # Data import guides ├── extensions/ # PostgreSQL extensions ├── functions/ # User-defined functions ├── data-types/ # PostgreSQL data types ├── reference/ # API reference, CLI ├── security/ # Security best practices ├── auth/ # Authentication integrations ├── ai/ # AI/ML features (pgvector) ├── guides/ # Step-by-step tutorials ├── community/ # Community resources └── shared-content/ # Reusable documentation snippets ``` ## Documentation Source Official Neon documentation extracted from: - Repository: https://github.com/neondatabase/website - Website: https://neon.tech/docs - Last Updated: 2026-02-07 ## License Documentation content © Neon Corporation. Used for educational purposes under fair use. Skill package © OpenClaw Community, MIT License.

path: IMPORTANT.md
content: # ⚠️ CRITICAL: Neon Serverless Driver

## 🔴 ALWAYS Use @neondatabase/serverless

When generating code for **Neon on serverless platforms** (Vercel, Netlify, Cloudflare Workers, etc.):

### ✅ CORRECT (HTTP Driver)

```typescript
import { neon } from '@neondatabase/serverless';

const sql = neon(process.env.DATABASE_URL);
const result = await sql`SELECT * FROM users`;
```

### ✅ CORRECT (Drizzle + HTTP Driver)

```typescript
import { neon } from '@neondatabase/serverless';
import { drizzle } from 'drizzle-orm/neon-http';

const sql = neon(process.env.DATABASE_URL);
const db = drizzle(sql);
```

### ❌ WRONG (Classic pg Driver)

```typescript
// ❌ DO NOT USE ON SERVERLESS
import { Pool } from 'pg';
import { drizzle } from 'drizzle-orm/node-postgres';

const pool = new Pool({ connectionString: process.env.DATABASE_URL });
const db = drizzle(pool);
```

## Why?

- **Neon HTTP driver** (`@neondatabase/serverless`) uses HTTP/WebSocket
- **Classic pg driver** uses TCP connections (doesn't work on edge/serverless)
- Serverless environments (Vercel Edge, Cloudflare Workers) don't support TCP
- HTTP driver is optimized for cold starts and edge runtime

## Exception

**ONLY use classic `pg` driver when:**
- Running on a **long-lived Node.js server** (not serverless)
- Using connection pooling (PgBouncer)
- Need advanced PostgreSQL features not available via HTTP

## Default Stack

For **Next.js + Vercel + Neon**, ALWAYS:

```typescript
import { neon } from '@neondatabase/serverless';
import { drizzle } from 'drizzle-orm/neon-http';
```

## Source

- Recommendation: Gemini analysis (2026-02-07)
- Context: serverless + Vercel + Next.js + Drizzle + Better Auth


path: README.md
content: # Neon Database Skill

Complete Neon Serverless Postgres documentation as an OpenClaw AgentSkill.

## What's Included

- **546 markdown files** with full Neon documentation
- Introduction, architecture, and core concepts
- Serverless PostgreSQL fundamentals
- Database branching and autoscaling
- Vercel, Drizzle, Prisma, Next.js integrations
- Better Auth, Auth.js, Clerk authentication guides
- Connection pooling and serverless optimization
- PostgreSQL extensions (pgvector, PostGIS, timescaledb)
- API reference and neonctl CLI documentation
- AI/ML features and pgvector guides
- Security best practices and compliance

## Installation

### From Local Directory

```bash
clawhub install /path/to/neon-skill
```

### From Archive

```bash
clawhub install neon.skill
```

## Usage

This skill is automatically loaded by OpenClaw when available in the workspace skills directory.

Agents with this skill can answer questions about:

- Setting up and configuring Neon projects
- Connecting Neon to frameworks (Vercel, Next.js, Drizzle, Prisma)
- Database branching workflows for preview environments
- Serverless optimization and connection pooling
- PostgreSQL extensions and best practices
- API and CLI usage (neonctl)
- AI/ML features (pgvector, embeddings, RAG)

## Documentation Source

Official documentation from:
- Website: https://neon.tech/docs
- Repository: https://github.com/neondatabase/website
- Extracted: 2026-02-07

## File Structure

```
neon/
├── SKILL.md              # Skill metadata and description
├── README.md             # This file
├── .gitignore            # Git ignore rules
└── docs/                 # Full Neon documentation (546 MD files, 6.8MB)
    ├── introduction/
    ├── get-started/
    ├── serverless/
    ├── connect/
    ├── manage/
    ├── extensions/
    ├── guides/
    ├── reference/
    └── ...
```

## Tags

`neon` `postgresql` `serverless` `database` `vercel` `drizzle` `prisma` `nextjs` `branching` `autoscaling` `documentation`

## License

Documentation content © Neon Corporation.
Skill package © OpenClaw Community, MIT License.


path: docs/README.md
content: ---
updatedOn: '2026-01-22T15:48:50.608Z'
---

# Docs

Welcome to Neon docs! This folder contains the source code of the [Neon docs](/docs/).

## Basic information

1. Every single Markdown file in this folder will be turned into a docs page.
2. Folder and file names should follow kebab-case.
3. `slug` is generated based on the folder structure and file names inside this folder. In order to see page `slug`, you can [start](../../README.md#run-the-website) and build the project with `npm run build` command that will display all generated pages.
4. Page `path` is generated by combining [`DOCS_BASE_PATH`](../../src/constants/docs.js) and page `slug`.
5. There is no need to add `h1` to the page since it will be displayed automatically with the value from `title` field.

## Fields

Right now Markdown files accept the following fields:

1. `title` — title of the page (required)
2. `subTitle` — subtitle of the page.
3. `tag` — tag for the page. It can be one of the following: `new`, `beta`, `coming soon`, `deprecated`, or you can use your own tag. Don't forget to add it to the `navigation.yaml` file as well.
4. `redirectFrom` — array of strings with paths to redirect from to the page, should start and end with a slash, e.g. `/docs/old-path/`
5. `isDraft` — flag that says the page is not ready yet. It won't appear in production but will appear in the development mode.
6. `enableTableOfContents` — flag that turns on the display of the outline for the page. The outline gets built out of second and third-level headings ([`h2`, `h3`]), thus appears as two-level nested max.
7. `ogImage` - the social preview image of the page.

> ⚠️ Please note that the project won't build if at least one of the Markdown files is missing a required field.

## Navigation

Navigation data is stored in the [navigation.yaml](./navigation.yaml) file.

### Navigation Structure

The navigation system is a unified structure where:

- **Top-level items** appear in the header navigation
- **Child items** appear in the left sidebar

This creates a seamless navigation experience where users select a main category from the header and see its detailed structure in the sidebar.

### Top Navigation Structure

Each top-level navigation item has the following structure:

```yaml
- nav: Get started # Navigation label (displayed in header)
  slug: introduction # URL slug for the section
  title: Neon Docs # Page title
  icon: home # Icon identifier
  subnav: # Sub-navigation items for header dropdowns
    - title: Neon platform
      slug: manage/platform
      icon: settings
      items: # Sidebar navigation items
        ...
```

**Important**: Top-level items can contain either:

- **`subnav`**: Sub-navigation items that appear as header dropdowns
- **`items`**: Navigation items that appear in the sidebar

### Sidebar Navigation Structure

The sidebar navigation supports multiple levels:

```yaml
  ...
  items: # Sidebar navigation items
    - section: Features # Section header
      icon: features
      slug: guides/neon-features
      items: # Section items
        - title: Serverless
          slug: introduction/serverless
        - title: Autoscaling
          slug: introduction/autoscaling
          items: # Section subitems
            - title: Introduction
              slug: introduction/autoscaling
            - title: Architecture
              slug: introduction/autoscaling-architecture
```

### How to add a new top navigation category

To add a new top-level navigation category, add a new item to the top level array with keys `nav`, `slug`, `title`, `icon`, and optionally `items` or `subnav`.

```diff
+- nav: New Category
+  slug: new-category
+  title: New Category Title
+  icon: new-icon
+  subnav:
+    ...
```

### How to add a new section

To add a new section within a navigation category, add a new item with keys `section`, `icon`, and `items`.

```diff
  ...
  items:
+   - section: Architecture
+     icon: architecture
+     items:
+       ...
```

### How to add a new page

To add a new page, add a new item with keys `title` and `slug` under the appropriate section or navigation level.

```diff
  ...
  items:
+   - title: Overview
+     slug: introduction/architecture-overview
```

### Navigation Properties

- `nav`: The label displayed in the top navigation header
- `slug`: The URL path for the page/section
- `title`: The display title for the page/section
- `icon`: Icon identifier for visual representation
- `section`: Section header for grouping related items
- `items`: Array of navigation items
- `subnav`: Sub-navigation items for the sidebar
- `tag`: Optional tag (e.g., "new", "beta") displayed next to the title

### Important Notes

- `title` in the sidebar may differ from `title` in the Markdown file
- `slug` should always match the page's slug
- The navigation supports unlimited nesting levels for complex documentation structures
- Icons are referenced by name and should match available icon components
- Tags like "new" or "beta" are automatically displayed with special styling

## Code blocks

All available languages for code blocks can be found [here](https://shiki.matsu.io/languages).

You can use fenced code blocks with three backticks (```) on the lines before and after the code block. And display code with options

- enable highlighting single lines, multiple lines, and ranges of code lines

  Examples:
  - Single line highlight

    ````md
    ```c++ {1}
    #include <iostream>

    int main() {
        std::cout << "Hello World";
        return 0;
    }
    ```
    ````

  - Multiple lines

    ````md
    ```c++ {1,2,5}
    #include <iostream>

    int main() {
        std::cout << "Hello World";
        return 0;
    }
    ```
    ````

  - Range of code lines

    ````md
    ```c++ {1-3,5}
    #include <iostream>

    int main() {
        std::cout << "Hello World";
        return 0;
    }
    ```
    ````

- use `[!code highlight]` to highlight a line.

  ```ts
  export function foo() {
    console.log('Highlighted'); // [!code highlight]
  }
  ```

- use `[!code word:xxx]` to highlight a word.

  ```ts
  export function foo() {
    // [!code word:Hello]
    const msg = 'Hello World';
    console.log(msg);
  }
  ```

- use `[!code --]` and `[!code ++]` to highlight a code diff.

  ```ts
  export function foo() {
    const msg = 'Hello Word'; // [!code --]
    const msg = 'Hello World'; // [!code ++]
  }
  ```

- `showLineNumbers` - flag to show on the line numbers in the code block.

  Example:

  ````md
  ```c++ showLineNumbers
  #include <iostream>

  int main() {
      std::cout << "Hello World";
      return 0;
  }
  ```
  ````

- `shouldWrap` - flag to enable code wrapping in the code block.

  Example:

  ````md
  ```powershell shouldWrap
  powershell -Command "Start-Process -FilePath powershell -Verb RunAs -ArgumentList '-NoProfile','-InputFormat None','-ExecutionPolicy Bypass','-Command ""iex (iwr -UseBasicParsing https://cli.configu.com/install.ps1)""'"
  ```
  ````

- `filename="..."` - add a filename label above the code block.

  Examples:

  ````md
  ```jsx filename="src/App.jsx"
  export default function App() {
    return <div>Hello</div>;
  }
  ```
  ````

  You can combine it with line highlighting and other flags:

  ````md
  ```jsx filename="src/App.jsx" {2} showLineNumbers shouldWrap
  export default function App() {
    return <div>Hello</div>;
  }
  ```
  ````

## Code Tabs

To display code tabs, wrap all pieces of code with `<CodeTabs></CodeTabs>` and write labels of code tabs in order:

````md
<CodeTabs labels={["Shell", "C++", "C#", "Java"]}>

```bash {2-4}
#!/bin/bash
STR="Hello World!"
echo $STR
```

```c++
#include <iostream>

int main() {
    std::cout << "Hello World";
    return 0;
}
```

```csharp
namespace HelloWorld
{
    class Hello {
        static void Main(string[] args)
        {
            System.Console.WriteLine("Hello World");
        }
    }
}
```

```java
import java.io.*;

class GFG {
    public static void main (String[] args) {
       System.out.println("Hello World");
    }
}
```

</CodeTabs>
````

<details>
<summary>Examples</summary>

![Code tabs example](images/code-tabs-example.jpg)

</details>

## External Code

The `ExternalCode` component allows embedding code content from external sources with syntax highlighting.

### Usage

```markdown
<ExternalCode
  url="https://raw.githubusercontent.com/neondatabase/neon/main/README.md"
/>
```

### Props

| Prop            | Type    | Default    | Description                                                   |
| --------------- | ------- | ---------- | ------------------------------------------------------------- |
| url             | string  | (required) | URL to the raw file                                           |
| language        | string  | (optional) | Language for syntax highlighting (defaults to file extension) |
| shouldWrap      | boolean | false      | Enables code wrapping in the code block                       |
| showLineNumbers | boolean | false      | Shows line numbers in the code block                          |
| className       | string  | ''         | Additional CSS classes to apply to the component              |

### Examples

```markdown
<ExternalCode
  url="https://raw.githubusercontent.com/neondatabase-labs/ai-rules/main/neon-auth.mdc"
  language="markdown"
  shouldWrap
  showLineNumbers
/>
```

### Best Practices

1. Always use raw URLs from the GitHub repository (e.g., `https://raw.githubusercontent.com/...`).
2. Use the `language` prop when the file extension doesn't match the actual content type.

## Tabs

To display the tabs with content as image, video, code block, .etc, wrap the `TabItem` with `Tabs`

````md
<Tabs labels={["Content", "CLI"]}>

<TabItem>
In your config v3 project, head to the `/metadata/databases/databases.yaml` file and add the database configuration as below.

```bash showLineNumbers
- name: <db_name>
  kind: postgres
  configuration:
    connection_info:
      database_url:
        from_env: <DB_URL_ENV_VAR>
    pool_settings:
      idle_timeout: 180
      max_connections: 50
      retries: 1
  tables: []
  functions: []
```

Apply the Metadata by running:

```bash
hasura metadata apply
```

If you've spun up the Hasura Engine with Docker, you can access the Hasura Console by accessing it in a browser at the URL of your Hasura Engine instance, usually http://localhost:8080.

<Admonition type="note">
To access the Hasura Console via the URL the HASURA_GRAPHQL_ENABLE_CONSOLE environment variable or the `--enable-console` flag must be set to true.
</Admonition>

</TabItem>

<TabItem>
Alternatively, you can create read replicas using the Neon API or Neon CLI.

```bash
curl --request POST \
     --url https://console.neon.tech/api/v2/projects/late-bar-27572981/endpoints \
     --header 'Accept: application/json' \
     --header "Authorization: Bearer $NEON_API_KEY" \
     --header 'Content-Type: application/json' \
     --data '
{
  "endpoint": {
    "type": "read_only",
    "branch_id": "br-young-fire-15282225"
  }
}
' | jq
```

</TabItem>

</Tabs>
````

## Admonition

To improve the documentation readability, one can leverage an Admonition custom component. Just wrap your piece of text with `<Admonition></Admonition>` and pass the type.

There are 6 types of Admonition: `note`, `important`, `tip`, `info`, `warning`, `comingSoon`; the default is `note`.

You may also specify an optional title with prop `title`.

Example:

```md
<Admonition type="note">
Highlights information that users should take into account, even when skimming.
</Admonition>

<Admonition type="important">
Crucial information necessary for users to succeed.
</Admonition>

<Admonition type="tip">
Optional information to help a user be more successful.
</Admonition>

<Admonition type="info">
Information that helps users understand the things better.
</Admonition>

<Admonition type="warning">
Critical content demanding immediate user attention due to potential risks.
</Admonition>

<Admonition type="comingSoon">
Information about features that are coming soon.
</Admonition>
```

<details>
<summary>Examples</summary>

![Admonition example](images/admonition-example.jpg)

</details>

## CTA

This is a simple block with title, description text and one CTA button that accomplish certain actions.

```md
<CTA />
```

Check the example for default data of CTA block

<details>
<summary>Example</summary>

![CTA example](images/cta-example.jpg)

</details>

To change text in CTA block, you can pass to the component props `title`, `description`, `buttonText`, `buttonUrl`:

```md
<CTA title="Try it on Neon!" description="Neon is Serverless Postgres built for the cloud. Explore Postgres features and functions in our user-friendly SQL Editor. Sign up for a free account to get started." buttonText="Sign Up" buttonUrl="https://console.neon.tech/signup" />
```

## Steps

To display numbered steps, wrap the content with `Steps` component.  
Steps will be splitted by `h2` headings.

```md
<Steps>

## Step 1: Create the Initial Schema

First, create a new database called `people` on the `main` branch and add some sample data to it.

## Step 2: Create a development branch

Create a new development branch off of `main`. This branch will be an exact, isolated copy of `main`.

</Steps>
```

<details>
<summary>Example</summary>

![Steps example](images/steps-example.jpg)

</details>

## Two Column Layout

The `TwoColumnLayout` component creates a two-column layout for tutorial pages and reference documentation. Use `TwoColumnLayout.Step` for numbered tutorial steps or `TwoColumnLayout.Item` for default items. Nested content blocks should be wrapped with `TwoColumnLayout.Block`.

> **Note:** Pages using `TwoColumnLayout` should include `layout: wide` prop to hide the right sidebar (Table of Contents) and provide more space for the two-column layout.

Check [Neon Auth with Next.js](https://neon.com/docs/auth/quick-start/nextjs) and [Neon Auth & Data API TypeScript SDKs](https://neon.com/docs/reference/javascript-sdk) for usage examples.

````md
<TwoColumnLayout>

<TwoColumnLayout.Step title="Install dependencies">
<TwoColumnLayout.Block>

Install the required packages for your project.

</TwoColumnLayout.Block>
<TwoColumnLayout.Block label="Terminal">

```bash
npm install @neondatabase/neon-js
```

</TwoColumnLayout.Block>
</TwoColumnLayout.Step>

<TwoColumnLayout.Item title="Sign in with email" method="auth.signIn.email()" id="signin-email">
<TwoColumnLayout.Block>

Authenticate a user with their email and password.

</TwoColumnLayout.Block>
<TwoColumnLayout.Block>

```typescript
await client.auth.signIn.email({
  email: '[REDACTED_SECRET]',
  [REDACTED_SECRET]',
});
```

</TwoColumnLayout.Block>
</TwoColumnLayout.Item>

<TwoColumnLayout.Footer>
<Admonition type="note">
Additional information that spans both columns
</Admonition>
</TwoColumnLayout.Footer>

</TwoColumnLayout>
````

**Components:**

- `TwoColumnLayout.Step` - Numbered step with `title` prop (for tutorials)
- `TwoColumnLayout.Item` - Default item with `title`, `method`, and `id` prop
- `TwoColumnLayout.Block` - Nested content block with optional `label` prop
- `TwoColumnLayout.Footer` - Full-width content at the bottom of a step

<details>
<summary>Examples</summary>

![Two Column Layout example](images/two-column-layout-example.jpg)

Example with steps:

![Two Column Layout example](images/two-column-layout-steps-example.jpg)

</details>

## Feature List

To display a list of features, use the `FeatureList` component.
Features will be splitted by `h2` and `h3` headings.

```md
<FeatureList>

### Agent creates an app

A vibe coder imagines an app. Your agent builds it, full-stack.

### Gets a working database instantly, with no friction

Neon provisions the database behind the scenes via API.

</FeatureList>
```

You can pass `icons` prop to the `FeatureList` component to display icons for each feature.

List of available icons (extendable): `src/components/shared/feature-list/icon/icon.jsx`.

```md
<FeatureList icons={['agent', 'speedometer']}>
```

<details>
<summary>Example</summary>

![Feature List example](images/feature-list-example.jpg)

</details>

## Checklist

To display a checklist, use the `CheckList` component with `CheckItem` items inside.

```md
<CheckList title="Checklist title">

<CheckItem title="Check item 1" href="#check-item-1">
  Check item 1 description
</CheckItem>

<CheckItem title="Check item 2" href="#check-item-2">
  Check item 2 description
</CheckItem>

</CheckList>
```

### Notes

- Checklist options saved in the browser local storage.
- Checklists with the same `title` will use the same local storage between pages.
- If you don't pass `title`, the id will be generated from the page `slug`.
- The best practice is to use `CheckList` with the `Steps` component on the page.

<details>
<summary>Example</summary>

![Checklist example](images/checklist-example.jpg)

</details>

## Images

The images should be sourced in `public/docs` directory and be used in `.md` with the relative path, that begins with a `/` slash

Example file structure:

```md
├── public
│ ├── docs
│ │ ├── conceptual-guides
│ │ ├── neon_architecture_2.png // put images in a directory with the same name as the .md file
├── content
│ ├── docs
│ │ ├── conceptual-guides
│ │ ├── architecture-overview.md
```

To display images using Markdown syntax, use the following syntax: `![alt text](image url)`. Example content in `architecture-overview.md`:

```md
![Neon architecture diagram](/docs/conceptual-guides/neon_architecture_2.png)
```

If you need an image without border to show an annotated piece of UI, use the `"no-border"` attribute as in the example below:

```md
![Neon architecture diagram](/docs/conceptual-guides/neon_architecture_2.png 'no-border')
```

With this approach, all images on your doc pages will be displayed both on the production and GitHub preview.

## Definition list

Custom `mdx` component that makes possible using [extended markdown syntax for descriptions lists](https://www.markdownguide.org/extended-syntax/#definition-lists). Fully [WCAG-compliant](https://www.w3.org/TR/WCAG20-TECHS/H40.html). It provides an accessible way to make term lists, and it's a generally good way to add structure to a text when a writer needs more than bullets and less than headings.

The usage is pretty [straightforward](https://github.com/neondatabase/website/pull/231/commits/8f795eaf700c31794a2267fc5978c22bfc649a0c):

```md
[comment]: <> (other content here)

<DefinitionList>
[comment]: <> (required new line)
Scenario executor
: First definition
: Second definition

Soak test
: First and only definition

Smoke test
Another term for smoke test
: First definition for both terms
: Second definition for both terms
: ...n definition for both terms

[Stress test](/)
: First and **only** definition for both terms with additional markup <br/> Read more: [link](/)

[comment]: <> (other content here)
</DefinitionList>

[comment]: <> (other content here)
```

### Acceptable markup for term

- `*italic*`
- `[link](/)`
- `**strong**` - but that doesn't make sense, by default terms appearance is already bold
- `inlineCode` - but it doesn't alter it's change in this context

### Constraints

- using emojis in `dt` is prohibited, as it potentially can mess up with `id` attribute, and `href` at anchor. We can not be sure which range will be used to display a particular symbol (depends on editor OS) and if it is going to be stripped.
- if there are multiple terms for a given set of descriptions, only the first one will have an `id` and an `anchor`
- make absolutely sure your `dt` text content is unique across the page to avoid `id` collisions

### Acceptable markup for description

- everything for term
- emojis
- any inline html
- line breaks `<br/>` (recommended way to separate visually something inside a single description)

<details>
<summary>Examples</summary>

![Definition list example](images/definition-list-example.jpg)

</details>

## Detail Icon Cards

`DetailIconCards` is a custom MDX component that displays data in a card format. Each card contains icon, title, href and description. This layout is especially useful for presenting grouped information in a visually pleasing and easy-to-understand way.

```md
<DetailIconCards>

<a href="https://api-docs.neon.tech/reference/getting-started-with-neon-api" description="Collaborate on open-source projects" icon="github">Headless vector search</a>

<a href="https://api-docs.neon.tech/reference/getting-started-with-neon-api" description="Collaborate on open-source projects" icon="github">Open AI completions</a>

</DetailIconCards>
```

List of available icons in folder: /website/src/components/pages/doc/detail-icon-cards/images

## Shared MDX components

Create a [markdown file](https://github.com/neondatabase/website/blob/main/content/docs/shared-content/need-help.md) in folder `content/docs/shared-content/`, add to `sharedMdxComponents` the name of component and the path to component.

```js
const sharedMdxComponents = {
  // ConponentName: 'shared-content/component-filename'
  NeedHelp: 'shared-content/need-help',
};

export default sharedMdxComponents;
```

Insert a shared markdown and render inline.

```md
## Resources

- [Open AI tiktoken source code on GitHub](https://github.com/openai/tiktoken)
- [pg_tiktoken source code on GitHub](https://github.com/kelvich/pg_tiktoken)

<NeedHelp/>
```

You can pass props to the shared component:

```md
<ComponentWithProps text="The pgvector extension" />
```

`component-with-props.md`

```md
<Admonition type="note" title="Test component with props">
  {text}
</Admonition>
```

## CopyPrompt

A reusable MDX component that shows a "copy prompt" box and lets users copy curated llm prompts from a file with one click.

**Usage:**

```mdx
<CopyPrompt
  src="/prompts/serverless-driver-prompt.md"
  displayText="Use this pre-built prompt to get started faster."
  buttonText="Copy prompt"
/>
```

`src` prop is mandatory. `displayText` and `buttonText` are optional, if you want to override the defaults.

| Prop          | Type   | Default                                            | Description                                         |
| ------------- | ------ | -------------------------------------------------- | --------------------------------------------------- |
| `src`         | string | (required)                                         | Path to the markdown file or prompt content to copy |
| `displayText` | string | "Use this pre-built prompt to get started faster." | CTA text shown on the left                          |
| `buttonText`  | string | "Copy prompt"                                      | Button label                                        |

### Where to place prompt files

Prompt markdown files should be placed in the `public/prompts/` directory of your project. This allows them to be fetched at runtime by the `CopyPrompt` component using a path like `/prompts/your-prompt-file.md`.

**Example:**

- Place your prompt file at: `public/prompts/serverless-driver-guardrail-prompt.md`
- Reference it in your MDX:

  ```mdx
  <CopyPrompt src="/prompts/serverless-driver-guardrail-prompt.md" />
  ```

## Contributing

For small changes and spelling fixes, we recommend using the GitHub UI because Markdown files are relatively easy to edit.

For larger contributions, consider [running the project locally](../../README.md#getting-started) to see how changes look like before making a pull request.


path: docs/ai/ai-agents-tools.md
content: ---
title: AI tools for Agents
subtitle: AI-powered tools for development and database management
summary: >-
  Covers the integration of AI tools with Neon for database management,
  including setup instructions, Model Context Protocol (MCP) usage, and plugins
  for Claude Code and GitHub Copilot.
enableTableOfContents: true
updatedOn: '2026-02-06T22:07:32.712Z'
---

Neon provides several ways to integrate with AI tools and agents, from natural language database control to autonomous agent frameworks. Choose the tools that fit your workflow.

## Quick setup

The fastest way to get started with Neon and AI:

```bash
npx neonctl@latest init
```

This authenticates via OAuth, creates an API key, configures your editor (Cursor, VS Code, or Claude Code), and installs [agent skills](https://github.com/neondatabase/agent-skills). Then restart and ask your AI assistant **"Get started with Neon"**.

## MCP integration

The Model Context Protocol (MCP) is a standardized way for AI tools to interact with Neon databases using natural language, providing secure and contextual access to your data and infrastructure.

<DetailIconCards>
<a href="/docs/ai/neon-mcp-server" description="Learn about managing your Neon projects using natural language with Neon MCP Server" icon="github">Neon MCP Server</a>
<a href="/docs/ai/connect-mcp-clients-to-neon" description="Learn how to connect MCP clients like Cursor, Claude Code, and ChatGPT to your Neon database" icon="github">Connect MCP clients</a>
</DetailIconCards>

## Claude Code plugin

If you're using Claude Code, install the Neon plugin to get Skills, MCP integration, and all the context rules in one package.

<DetailIconCards>
<a href="/docs/ai/ai-claude-code-plugin" description="Includes Claude Code Skills for Neon, Neon MCP integration, and context rules" icon="github">Claude Code plugin for Neon</a>
</DetailIconCards>

## GitHub Copilot agents

Custom agents for GitHub Copilot that bring Neon's branching workflow directly into VS Code for safe migrations and query optimization.

<DetailIconCards>
<a href="/docs/ai/ai-github-copilot-agents" description="Safe database migrations and query optimization using Neon branching" icon="github">Neon agents for GitHub Copilot</a>
</DetailIconCards>

## AI rules

For other AI tools like Cursor, use these individual `.mdc` context rule files. Copy them to your AI tool's custom rules directory — the format is tool-agnostic and works with any AI assistant that supports context rules.

<DetailIconCards>
<a href="/docs/ai/ai-rules-neon-auth" description="AI rules for implementing authentication with Neon" icon="github">Neon Auth</a>
<a href="/docs/ai/ai-rules-neon-drizzle" description="AI rules for using Drizzle ORM with Neon" icon="github">Neon Drizzle</a>
<a href="/docs/ai/ai-rules-neon-serverless" description="AI rules for serverless database connections" icon="github">Neon Serverless Driver</a>
<a href="/docs/ai/ai-rules-neon-typescript-sdk" description="AI rules for using the Neon API TypeScript SDK" icon="github">Neon API TypeScript SDK</a>
<a href="/docs/ai/ai-rules-neon-python-sdk" description="AI rules for using the Neon Python SDK" icon="github">Neon Python SDK</a>
<a href="/docs/ai/ai-rules-neon-api" description="AI rules for using the Neon API" icon="github">Neon API</a>
<a href="/docs/ai/ai-rules-neon-toolkit" description="AI rules for using the Neon Toolkit" icon="github">Neon Toolkit</a>
</DetailIconCards>

## Build AI agents

Create autonomous agents that can manage and interact with your Neon databases programmatically. Build with our terse JavaScript client or the Neon API.

<DetailIconCards>

<a href="https://neon.com/use-cases/ai-agents" description="Read about Neon as a solution for agents that need backends." icon="openai">Neon for AI agent platforms</a>

<a href="https://github.com/neondatabase/toolkit" description="A terse JavaScript client for spinning up Postgres databases and running SQL queries" icon="github">@neondatabase/toolkit</a>

<a href="/docs/ai/ai-database-versioning" description="How AI agents and codegen platforms use Neon snapshot APIs for database versioning" icon="openai">Database versioning</a>

<a href="/docs/reference/api-reference" description="Integrate using the Neon API" icon="transactions">Neon API</a>

</DetailIconCards>

## Agent frameworks

Build AI agents using popular frameworks that integrate with Neon.

<DetailIconCards>
<a href="/guides/agentstack-neon" description="Build and deploy AI agents with AgentStack's CLI and Neon integration" icon="openai">AgentStack Integration</a>
<a href="/guides/autogen-neon" description="Create collaborative AI agents with Microsoft AutoGen and Neon" icon="openai">AutoGen Integration</a>
<a href="/guides/azure-ai-agent-service" description="Build enterprise AI agents with Azure AI Agent Service and Neon" icon="openai">Azure AI Agent Service</a>
<a href="/guides/composio-crewai-neon" description="Create multi-agent systems with CrewAI and Neon" icon="openai">Composio + CrewAI</a>
<a href="/guides/langgraph-neon" description="Build stateful, multi-actor applications with LangGraph and Neon" icon="openai">LangGraph Integration</a>
</DetailIconCards>


path: docs/ai/ai-azure-notebooks.md
content: ---
title: Azure Data Studio Notebooks
subtitle: Use Azure Data Studio Notebooks with Neon for vector similarity search
summary: >-
  Covers the setup of Azure Data Studio Notebooks with Neon, detailing how to
  create a Python notebook, connect to a Neon database, install the `pgvector`
  extension, and execute vector search queries.
enableTableOfContents: true
updatedOn: '2026-02-06T22:07:32.715Z'
---

A Jupyter Notebook is an open-source web application that allows you to create and share documents containing live code, equations, visualizations, and narrative text. Azure Data Studio supports Jupyter Notebooks, enabling users to combine SQL queries, Python code, and markdown text in a single interactive document.

This guide describes how to create a new python notebook in Azure Data Studio, connect to a Neon database, install the `pgvector` extension to enable Neon as a vector store, and run a vector search query.

## Prerequisites

To perform the steps in this guide, you will require:

- Azure Data Studio - Download the latest version of Azure Data Studio for your operating system [here](https://learn.microsoft.com/en-us/azure-data-studio/download-azure-data-studio).

- A Neon account - If you do not have one, sign up at [Neon](https://console.neon.tech/signup). Your Neon project comes with a ready-to-use Postgres database named `neondb`. You can use it, or create your own by following the instructions [here](/docs/manage/databases#create-a-database).

## Retrieve your Neon database connection string

Click **Connect** on your **Project Dashboard** to open the **Connect to your database** modal, and select a branch, a user, and the database you want to connect to. A connection string is constructed for you.

![Connection modal](/docs/connect/connection_details.png)

## Create a notebook

1. Go to the **File** menu for Azure Data Studio and select **New Notebook**.
2. Select **Python 3** for the Kernel and set **Attach to** to "localhost" where it can access your Python installation.

You can save the notebook using the **Save** or **Save as...** command from the **File** menu.

## Configure Python for Notebooks

The first time you connect to the Python kernel in a notebook, the **Configure Python for Notebooks** page is displayed. You can select either:

- **New Python installation** to install a new copy of Python for Azure Data Studio, or
- **Use existing Python installation** to specify the path to an existing Python installation for Azure Data Studio to use

To view the location and version of the active Python kernel, you can create a code cell and run the following Python commands:

```python
import os
import sys
print(sys.version_info)
print(os.path.dirname(sys.executable))
```

## Running a code cell

You can create cells containing Python code that you can run in place by clicking the **Run cell** button (the round blue arrow) to the left of the cell. The results are shown in the notebook after the cell finishes running. In the `pgvector` example that follows, you'll add and execute several code cells.

## pgvector example

After you've set up Azure Data Studio and have created a notebook, you can use the following basic example to get started with Neon and `pgvector`.

### Install the psycopg driver

psycopg is a popular Postgres database adapter for the Python programming language. It allows Python applications to connect to and interact with Postgres databases.

Install the `psycopg` adapter by adding and executing the following code cell:

```python
!pip install psycopg
```

### Connect to your database

1. In your notebook, create a code block to define your Neon database connection and create a cursor object. Replace `postgresql://[user]:[password]@[neon_hostname]/[dbname]` with the database connection string you retrieved previously.

   ```python shouldWrap
   import os
   import psycopg

   # Provide your Neon connection string
   connection_string = "postgresql://[user]:[password]@[neon_hostname]/[dbname]"

   # Connect using the connection string
   connection = psycopg.connect(connection_string)

   # Create a new cursor object
   cursor = connection.cursor()
   ```

2. Execute the code block.

3. Add a code block for testing the database connection.

   ```python
   # Execute this query to test the database connection
   cursor.execute("SELECT 1;")
   result = cursor.fetchone()

   # Check the query result
   if result == (1,):
       print("Your database connection was successful!")
   else:
       print("Your connection failed.")
   ```

4. Execute the code block.

### Install the pgvector extension

1. Create a codeblock to install the `pgvector` extension to enable your Neon database as a vector store:

   ```python
   # Execute this query to install the pgvector extension
   cursor.execute("CREATE EXTENSION IF NOT EXISTS vector;")
   ```

2. Execute the code block.

### Create a table and add vector data

1. Add a code block to create a table and insert data:

   ```python shouldWrap
   create_table_sql = '''
   CREATE TABLE items (
   id BIGSERIAL PRIMARY KEY,
   embedding VECTOR(3)
   );
   '''

   # Insert data
   insert_data_sql = '''
   INSERT INTO items (embedding) VALUES ('[1,2,3]'), ('[4,5,6]'), ('[7,8,9]');
   '''

   # Execute the SQL statements
   cursor.execute(create_table_sql)
   cursor.execute(insert_data_sql)

   # Commit the changes
   connection.commit()
   ```

2. Execute the code block.

### Query your data

1. Add a codeblock to perform a vector similarity search.

   ```python shouldWrap
   cursor.execute("SELECT * FROM items ORDER BY embedding <-> '[3,1,2]' LIMIT 1;")
   all_data = cursor.fetchall()
   print(all_data)
   ```

2. Execute the code block.

### Next steps

For more information about using Neon with `pgvector`, see [The pgvector extension](/docs/extensions/pgvector).

<NeedHelp/>


path: docs/ai/ai-claude-code-plugin.md
content: ---
title: Claude Code plugin for Neon
summary: >-
  Covers the setup of the Neon Claude Code plugin, which integrates
  Neon-specific Skills and API access into Claude Code, enabling tasks like
  managing databases and configuring serverless connections.
description: >-
  Install the Neon Claude Code plugin to give Claude access to Neon’s APIs,
  Postgres workflows, and built-in Skills.
updatedOn: '2026-02-06T22:07:32.716Z'
---

The **Neon Claude Code plugin** adds Neon-specific Skills and API access to Claude Code, Anthropic’s AI development environment. It’s part of the [Neon AI Rules toolkit](https://github.com/neondatabase-labs/ai-rules), and it bundles four guided Skills plus an MCP (Model Context Protocol) server integration.

## Overview

Claude Skills are Markdown-based workflows that tell Claude how to complete specific tasks — like setting up a database connection, editing a file, or running a script. The Neon plugin packages several of these Skills into a reusable bundle, so Claude Code can interact directly with Neon Postgres.

Once installed, the plugin gives Claude the ability to:

- Create and manage Neon projects and databases
- Connect frameworks like Drizzle ORM
- Configure serverless Postgres connections
- Reference Neon documentation and best practices in context

## What’s included

The plugin contains:

- **4 Claude Skills**
- **An MCP server integration** that connects Claude to Neon’s APIs
- **Portable context rules (.mdc files)** for other AI tools such as Cursor

### Included Skills

| Skill                  | Description                                                                                                                                                                         |
| :--------------------- | :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **neon-drizzle**       | Guides Claude through setting up [Drizzle ORM](https://orm.drizzle.team) with Neon. Handles schema creation, connection setup, and project scaffolding.                             |
| **neon-serverless**    | Teaches Claude how to configure [Neon's serverless Postgres driver](https://neon.com/docs/serverless/serverless-driver) and test connections.                                       |
| **neon-toolkit**       | Provides workflows for using the [Neon Management API](https://api-docs.neon.tech/reference/getting-started-with-neon-api) to create databases, projects, and branches dynamically. |
| **add-neon-knowledge** | Gives Claude access to [Neon documentation](https://neon.com/docs/introduction) snippets and usage examples — the "Neon brain."                                                     |

## How it works

Each Skill is a Markdown file with a description and a step-by-step workflow. When you ask Claude to perform a task (for example, _“Integrate Neon with Drizzle”_), it checks the available Skill descriptions, finds a match, and loads the full instructions to complete the task.

The plugin’s MCP server integration lets Claude interact with Neon’s live API endpoints. That means Claude can:

- Query Neon for project information
- Create or delete branches and databases
- Validate connection strings
- Run SQL queries and migrations

## Install the plugin in Claude Code

1. Add the Neon marketplace:

   ```bash
   /plugin marketplace add neondatabase-labs/ai-rules
   ```

2. Install the Neon plugin:

   ```bash
   /plugin install neon-plugin@neon
   ```

3. Verify the installation:
   Ask Claude Code:

   ```bash
   which skills do you have access to?
   ```

   You should see the four Neon Skills listed.

4. Start using the Skills:
   Use natural language prompts like:
   > “Use the neon-drizzle Skill to set up Drizzle ORM with Neon.”

Claude will automatically select and execute the relevant workflow.

## Use the rules outside Claude Code

The [Neon AI Rules toolkit repository](https://github.com/neondatabase-labs/ai-rules) also includes portable `.mdc` context rule files.

You can use them in:

- **Cursor:** copy the `.mdc` files into `.cursor/rules/`
- **Other AI tools:** place them in your assistant’s custom rules directory

These files include best-practice prompts and code patterns for connecting to and developing with Neon Postgres.

## Repository structure

```
ai-rules/
├── .claude-plugin/
│   └── marketplace.json        # Marketplace metadata
├── neon-plugin/                # Claude Code plugin
│   ├── .claude-plugin/
│   │   └── plugin.json         # Plugin configuration
│   ├── .mcp.json               # MCP server connection
│   └── skills/                 # Guided skills
│       ├── neon-drizzle/       # Drizzle ORM skill
│       │   ├── SKILL.md
│       │   ├── guides/         # Workflow guides
│       │   ├── references/     # Technical docs
│       │   ├── scripts/        # Automation
│       │   └── templates/      # Code examples
│       ├── neon-serverless/    # Serverless skill
│       ├── neon-toolkit/       # Ephemeral DB skill
│       └── add-neon-docs/      # Docs installer skill
├── *.mdc                       # Context rules (13 files)
├── LICENSE
└── README.md
```

## Learn more

- [Neon AI Rules toolkit](https://github.com/neondatabase-labs/ai-rules)
- [Claude Skills documentation](https://docs.anthropic.com/en/docs/agents/claude-code)
- [AI Agents and Tools overview](/docs/ai/ai-agents-tools)

If you run into issues, visit our [Discord](https://discord.gg/neondatabase) or open an issue in the [ai-rules repository](https://github.com/neondatabase-labs/ai-rules/issues).


path: docs/ai/ai-concepts.md
content: ---
title: AI Concepts
subtitle: Learn how embeddings are used to build AI applications
summary: >-
  Covers the use, generation, and storage of embeddings in Postgres for AI
  applications, detailing how to transform unstructured data into structured
  formats and measure text similarity through vector distance calculations.
enableTableOfContents: true
updatedOn: '2026-02-06T22:07:32.717Z'
---

Embeddings are an essential component in building AI applications. This topic describes embeddings and how they are used, generated, and stored in Postgres.

## What are embeddings?

When working with unstructured data, a common objective is to transform it into a more structured format that is easier to analyze and retrieve. This transformation can be achieved through the use of 'embeddings', which are vectors containing an array of floating-point numbers that represent the features or dimensions of your data. For example, a sentence like "The cow jumped over the moon" might be represented by an embedding that looks like this: [0.5, 0.3, 0.1].

The advantage of embeddings is that they allow us to measure the similarity between different pieces of text. By calculating the distance between two embeddings, we can assess their relatedness - the smaller the distance, the greater the similarity, and vice versa. This quality is particularly useful as it enables embeddings to capture the underlying meaning of the text.

Take the following three sentences, for example:

- Sentence 1: "The cow jumped over the moon."
- Sentence 2: "The bovine leaped above the celestial body."
- Sentence 3: "I enjoy eating pancakes."

You can determine the most similar sentences by following these steps:

1. Generate embeddings for each sentence. For illustrative purposes, assume these values represent actual embeddings:
   - Embedding for sentence 1 → [0.5, 0.3, 0.1]
   - Embedding for sentence 2 → [0.6, 0.29, 0.12]
   - Embedding for sentence 3 → [0.1, -0.2, 0.4]

2. Compute the distance between all pairs of embeddings (1 & 2, 2 & 3, and 1 & 3).

3. Identify the pair of embeddings with the shortest distance between them.

When we apply this process, it is likely that sentences 1 and 2, both of which involve jumping cattle, will emerge as the most related according to a distance calculation.

## Vector similarity search

Transforming data into embeddings and computing similarities between one or more items is referred to as vector search or similarity search. This process has a wide range of applications, including:

- **Information retrieval:** By representing user queries as vectors, we can perform more accurate searches based on the meaning behind the queries, allowing us to retrieve more relevant information.
- **Natural language processing:** Embeddings capture the essence of the text, making them excellent tools for tasks such as text classification and sentiment analysis.
- **Recommendation systems:** Using vector similarity, we can recommend items similar to a given item, whether they be movies, products, books, or otherwise. This technique allows us to create more personalized and relevant recommendations.
- **Anomaly detection:** By determining the similarity between items within a dataset, we can identify outliers or anomalies—items that don't quite fit the pattern. This can be crucial in many fields, from cybersecurity to quality control.

### Distance metrics

Vector similarity search computes similarities (the distance) between data points. Calculating how far apart data points are helps us understand the relationship between them. Distance can be computed in different ways using different metrics. Some popular distance metrics include:

- Euclidean (L2): Often referred to as the "ordinary" distance you'd measure with a ruler.
- Manhattan (L1): Also known as "taxicab" or "city block" distance.
- Cosine: This calculates the cosine of the angle between two vectors.

Other distance metrics supported by the `pgvector` extension include [Hamming distance](https://en.wikipedia.org/wiki/Hamming_distance) and [Jaccard distance](https://en.wikipedia.org/wiki/Jaccard_index).

Different distance metrics can be more appropriate for different tasks, depending on the nature of the data and the specific relationships you're interested in. For instance, cosine similarity is often used in text analysis.

## Generating embeddings

A common approach to generating embeddings is to use an LLM API, such as [OpenAI’s Embeddings API](https://platform.openai.com/docs/api-reference/embeddings). This API allows you to input a text string into an API endpoint, which then returns the corresponding embedding. The "cow jumped over the moon" is a simplistic example with 3 dimensions. Most embedding models generate embeddings with a much larger number of dimensions. OpenAI's newest and most performant embedding models, `text-embedding-3-small` and `text-embedding-3-large`, generate embeddings with 1536 and 3072 dimensions by default, respectively.

Here's an example of how to use OpenAI's `text-embedding-3-small` model to generate an embedding:

```bash
curl https://api.openai.com/v1/embeddings \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer $OPENAI_API_KEY" \
  -d '{
    "input": "Your text string goes here",
    "model": "text-embedding-3-small"
  }'
```

<Admonition type="note">
Running the command above requires an OpenAI API key, which must be obtained from [OpenAI](https://platform.openai.com/).
</Admonition>

Upon successful execution, you'll receive a response similar to the following:

```json
{
  "object": "list",
  "data": [
    {
      "object": "embedding",
      "index": 0,
      "embedding": [
        -0.006929283495992422,
        -0.005336422007530928,
        ... (omitted for spacing)
        -4.547132266452536e-05,
        -0.024047505110502243
      ],
    }
  ],
  "model": "text-embedding-3-small",
  "usage": {
    "prompt_tokens": 5,
    "total_tokens": 5
  }
}
```

To learn more about OpenAI's embeddings, see [Embeddings](https://platform.openai.com/docs/guides/embeddings). Here, you'll find an example of obtaining embeddings from an [Amazon fine-food reviews](https://www.kaggle.com/datasets/snap/amazon-fine-food-reviews) dataset supplied as a CSV file. See [Obtaining the embeddings](https://platform.openai.com/docs/guides/embeddings/use-cases).

There are many embedding models you can use, such as those provided by Mistral AI, Cohere, Hugging Face, etc. AI tools like [LanngChain](https://www.langchain.com/) provide interfaces and integrations for working with a variety of models. See [LangChain: Text embedding models](https://js.langchain.com/v0.1/docs/integrations/text_embedding/). You'll also find a [Neon Postgres guide](https://js.langchain.com/v0.1/docs/integrations/vectorstores/neon/) on the LangChain site and [Class NeonPostgres](https://v02.api.js.langchain.com/classes/langchain_community_vectorstores_neon.NeonPostgres.html), which provides an interface for working with a Neon Postgres database.

## Storing vector embeddings in Postgres

Neon supports the [pgvector](/docs/extensions/pgvector) Postgres extension, which enables the storage and retrieval of vector embeddings directly within your Postgres database. When building AI applications, installing this extension eliminates the need to extend your architecture to include a separate vector store. Installing the `pgvector` extension simply requires running the following `CREATE EXTENSION` statement from the [Neon SQL Editor](/docs/get-started/query-with-neon-sql-editor) or any SQL client connected to your Neon Postgres database.

```sql
CREATE EXTENSION vector;
```

After installing the `pgvector` extension, you can create a table to store your embeddings. For example, you might define a table similar to the following to store your embeddings:

```sql
CREATE TABLE items(id BIGSERIAL PRIMARY KEY, embedding VECTOR(1536));
```

To add embeddings to the table, you would insert the data as shown:

```sql
INSERT INTO items(embedding) VALUES ('[
    -0.006929283495992422,
    -0.005336422007530928,
    ...
    -4.547132266452536e-05,
    -0.024047505110502243
]');
```

For detailed information about using `pgvector`, refer to our guide: [The pgvector extension](/docs/extensions/pgvector).


path: docs/ai/ai-database-versioning.md
content: ---
title: Database versioning with snapshots
subtitle: How AI agents and codegen platforms implement database version control using
  snapshots and preview branches
summary: >-
  Covers the implementation of database versioning using Neon's snapshot APIs,
  enabling the creation of point-in-time database versions, instant rollbacks,
  and stable connection strings for applications in AI agent and code generation
  contexts.
enableTableOfContents: true
updatedOn: '2026-02-06T22:07:32.718Z'
---

<Admonition type="note" title="Beta">
Snapshots are available in Beta. Please give us [Feedback](https://console.neon.tech/app/projects?modal=feedback) from the Neon Console or by connecting with us on [Discord](https://discord.gg/92vNTzKDGp).

**Limits and pricing:** The Free plan includes 1 snapshot, and paid plans (including the [Agent plan](https://neon.com/use-cases/ai-agents)) include 10 snapshots. Snapshots are provided free of charge during beta, and will be charged based on GB-month storage at a rate lower than standard project storage after GA. If you need higher limits, please reach out to [Neon support](/docs/introduction/support).
</Admonition>

## Overview

This guide describes how you can implement database versioning for AI agent and code generation platforms using Neon's snapshot APIs. With snapshots, you can create point-in-time database versions, perform instant rollbacks, and maintain stable database connection strings for your applications. See a working implementation in the [demonstration repository](https://github.com/neondatabase-labs/snapshots-as-checkpoints-demo).

> **Terminology note:** This guide uses "versions" to describe saved database states from the user's perspective, and "snapshots" when referring to Neon's technical implementation. You may also see these called "checkpoints" or "edits" in some AI agent contexts.

<Admonition type="tip" title="Synopsis">
Use the project's root branch for production, whose database connection string stays the same when a snapshot restore is finalized. Create snapshots to save database versions. For rollbacks, restore snapshots with `finalize_restore: true` and `target_branch_id` set to your root branch ID, then poll operations until complete before connecting. For previews, use `finalize_restore: false` to create temporary branches with their own database connection strings.
</Admonition>

## Why use snapshots for versioning

Standard database branching is great for development but less suitable for versioning. Each new branch gets a new database connection string and creates dependency chains that complicate deletion. This pattern solves both problems.

By restoring a Neon snapshot to your active branch with `finalize_restore: true`, you replace its data in-place while preserving the original, stable connection string. This makes the snapshot-restore pattern ideal for versioned environments where connection stability is needed.

## Quick start with the demo

The best way to understand this pattern is to see it in action:

1. **Clone the snapshots demo app**:
   - https://github.com/neondatabase-labs/snapshots-as-checkpoints-demo
2. **Key files to examine**:
   - [lib/neon/create-snapshot.ts](https://github.com/neondatabase-labs/snapshots-as-checkpoints-demo/blob/main/lib/neon/create-snapshot.ts) - Snapshot creation implementation
   - [lib/neon/apply-snapshot.ts](https://github.com/neondatabase-labs/snapshots-as-checkpoints-demo/blob/main/lib/neon/apply-snapshot.ts) - Complete restore workflow with operations polling
   - [lib/neon/operations.ts](https://github.com/neondatabase-labs/snapshots-as-checkpoints-demo/blob/main/lib/neon/operations.ts) - Operation status polling logic
   - [app/[checkpointId]/page.tsx](https://github.com/neondatabase-labs/snapshots-as-checkpoints-demo/blob/main/app/[checkpointId]/page.tsx) - UI integration showing versions and rollbacks
3. Run locally or use the [public demo](https://snapshots-as-checkpoints-demo.vercel.app/) to see version creation, rollbacks, and previews in action

> **Note:** The demo repository uses "checkpoint" terminology which maps to "version" in this guide.
> The demo implements a contacts application that evolves through agent prompts, demonstrating version creation and restoration at each stage:

**v0: empty app** → **v1: basic contacts** → **v2: add role/company** → **v3: add tags**

## The active branch pattern

Every agent project maps to one Neon project with a designated [root branch](/docs/reference/glossary#root-branch) that serves as the production database.

**Important:** Snapshots can only be created from root branches in Neon. A root branch is a branch with no parent (typically named `main` or `production`).

**The active branch:**

- Gets its data replaced during finalized rollbacks
- Maintains a consistent database connection string through Neon's restore mechanism — see [How restore works](#how-restore-works) for details
- Must be a root branch for snapshot creation

**The snapshots:**

- Capture point-in-time database versions
- Store only incremental changes (cost-efficient)
- Can be restored to the active branch or to a temporary preview branch

![Active branch pattern diagram](/docs/guides/active_branch_pattern.jpg)

## Implementation

### Creating snapshots

Create a snapshot to capture the current database version using the [snapshot endpoint](https://api-docs.neon.tech/reference/createsnapshot):

```bash
POST /api/v2/projects/{project_id}/branches/{branch_id}/snapshot
```

> **Demo implementation:** See [lib/neon/create-snapshot.ts](https://github.com/neondatabase-labs/snapshots-as-checkpoints-demo/blob/main/lib/neon/create-snapshot.ts) for an example with error handling and operation polling.
> **Path parameters:**

- `project_id` (string, required): The Neon project ID
- `branch_id` (string, required): The active branch ID (must be a root branch)

**Query parameters:**

- `lsn` (string): Target Log Sequence Number. Cannot be used with `timestamp`
- `timestamp` (string): Target timestamp (RFC 3339). Cannot be used with `lsn`
- `name` (string): Name for the snapshot
- `expires_at` (string): Auto-deletion time (RFC 3339)

**Example:**

```bash
curl --request POST \
     --url 'https://console.neon.tech/api/v2/projects/{project_id}/branches/{branch_id}/snapshot?name=version-session-1&expires_at=2025-08-13T00:00:00Z' \
     --header 'authorization: Bearer $NEON_API_KEY'
```

**When to create snapshots:**

- Start of each agent session
- Before database schema changes
- After successful operations
- User-initiated save points

<Admonition type="tip">
Learn how our Developer Advocate approaches snapshot-based workflows in [Promoting Postgres changes safely to production](https://neon.com/blog/promoting-postgres-changes-safely-production).
</Admonition>

### Rolling back to (restoring) a snapshot

Restore any snapshot to recover a previous version using the [restore endpoint](https://api-docs.neon.tech/reference/restoresnapshot):

```bash
POST /api/v2/projects/{project_id}/snapshots/{snapshot_id}/restore
```

> **Demo implementation:** See [lib/neon/apply-snapshot.ts](https://github.com/neondatabase-labs/snapshots-as-checkpoints-demo/blob/main/lib/neon/apply-snapshot.ts) for the complete restore workflow including operation polling and error handling.
> **Path parameters:**

- `project_id` (string, required): The Neon project ID
- `snapshot_id` (string, required): The snapshot ID being restored

**Body parameters:**

- `name` (string): A name for the newly restored branch. If omitted, a default name is generated
- `target_branch_id` (string): The ID of the branch to restore the snapshot into. If not specified, the branch from which the snapshot was originally created will be used. **Set this value to your root branch ID for rollbacks to preserve connection strings**
- `finalize_restore` (boolean): Set to `true` to finalize the restore operation immediately. This will complete the restore and move computes from the current branch to the new branch, which keeps the database connection string the same. Defaults to `false`. **Set to `true` when restoring to the active branch for rollbacks, `false` to create preview branches**

<Admonition type="note" title="Connection warning">
Do not connect to the database until current API operations are complete. Any connection attempt before operations finish will either fail or connect to the old database state, not your restored version.
</Admonition>

#### How restore works

Understanding the restore mechanism explains why the connection string remains stable:

1. **New branch creation**: When you restore with `finalize_restore: true`, Neon first creates a new branch from your snapshot. This new branch has a different, system-generated branch ID.

2. **Endpoint transfer**: Neon then transfers the compute endpoint (and its associated connection string) from your original active branch to this newly created branch.

3. **Settings migration**: All branch settings, including its name, are copied to the new active branch, making it appear identical to the old one. Only the branch ID is different.

4. **Branch orphan**: Your original branch becomes "orphaned." It is disconnected from the compute endpoint and renamed by adding an "(old)" suffix (e.g., `main (old)`) to the branch name.

<Admonition type="info" title="Branch ID changes after restore">
The connection string remains stable, but the branch ID changes with every `finalize_restore: true` operation. If you store the branch ID for use in subsequent API calls (e.g., to create the next snapshot), you must retrieve and store the new branch ID after the restore operation completes.
</Admonition>

#### Rollback workflow

Restore any snapshot to your active branch, preserving the connection string:

```json
{
  "target_branch_id": "br-active-branch-123456", // Your root branch ID
  "finalize_restore": true // Moves computes and preserves connection string
}
```

> **Important:** When restoring with `finalize_restore: true`, your previous active branch becomes orphaned and is renamed with `(old)` appended, such as `production (old)` or similar. This orphaned branch is no longer connected to any compute endpoint but preserves your pre-restore state. Delete it during cleanup to avoid unnecessary costs.
> After calling the restore API:

1. Extract the array of operation IDs from the API response.
2. For each operation ID, poll the operations endpoint until its status reaches a terminal state (finished, failed, cancelled, or skipped).
3. Do not attempt to connect to the database until all operations are complete. Connections made before completion will point to the old, pre-restore database state.
4. After verifying a successful restore, delete the orphaned branch (e.g., `main (old)`) to avoid incurring storage costs.

> See the [poll operation status](/docs/manage/operations#poll-operation-status) documentation for related information.
> **Polling operations example:**

```javascript
// Poll operation status until complete
async function waitForOperation(projectId, operationId) {
  while (true) {
    const response = await fetch(
      `https://console.neon.tech/api/v2/projects/${projectId}/operations/${operationId}`,
      { headers: { Authorization: `Bearer ${NEON_API_KEY}` } }
    );
    const { status } = await response.json();

    // Terminal states - safe to proceed
    if (['finished', 'skipped', 'cancelled'].includes(status)) {
      return;
    }

    // Error state - handle appropriately
    if (status === 'failed') {
      throw new Error('Operation failed');
    }

    // Still running - wait and retry
    await new Promise((resolve) => setTimeout(resolve, 5000));
  }
}

// After restore API call
const restoreResponse = await restoreSnapshot(projectId, snapshotId);
const operationIds = restoreResponse.operations.map((op) => op.id);

// Wait for all operations to complete
for (const id of operationIds) {
  await waitForOperation(projectId, id);
}
// NOW safe to connect to the restored database
```

![Polling operations flow diagram](/docs/guides/polling_operations_flow.jpg)

**Potential restore-related problems:**

- **Connection to old state**: Ensure all operations completed
- **Target branch not found**: Verify branch exists
- **Operation timeout**: Retry with longer timeout
- **Accumulating orphaned branches**: Delete orphaned branches (e.g., `production (old)`) after successful restore verification

#### Preview environments

Create a temporary branch to preview a version without affecting the active branch:

```json
{
  "name": "preview-version-123",
  "finalize_restore": false // Creates new branch for preview without moving computes
}
```

This creates a new branch with its own connection string for preview. The active branch remains unchanged. Preview branches should be deleted after use to avoid storage costs.

### Managing snapshots

#### List available snapshots

Get all snapshots with IDs, names, and timestamps using the [list snapshots endpoint](https://api-docs.neon.tech/reference/listsnapshots):

```bash
GET /api/v2/projects/{project_id}/snapshots
```

**Path parameters:**

- `project_id` (string, required): The Neon project ID

#### Delete snapshot

Remove a snapshot using the [delete endpoint](https://api-docs.neon.tech/reference/deletesnapshot):

```bash
DELETE /api/v2/projects/{project_id}/snapshots/{snapshot_id}
```

**Path parameters:**

- `project_id` (string, required): The Neon project ID
- `snapshot_id` (string, required): The snapshot ID

#### Update snapshot name

Rename a snapshot using the [update endpoint](https://api-docs.neon.tech/reference/updatesnapshot):

```bash
PATCH /api/v2/projects/{project_id}/snapshots/{snapshot_id}
```

**Path parameters:**

- `project_id` (string, required): The Neon project ID
- `snapshot_id` (string, required): The snapshot ID

**Body:**

```json
{
  "snapshot": {
    "name": "important-milestone"
  }
}
```

#### Cleanup strategy

Proper cleanup reduces costs and keeps your project manageable:

- Delete snapshots when no longer reachable by users
- Restoring from a snapshot doesn't lock that snapshot from deletion, unlike branches where creating child branches prevents deleting the parent
- Delete orphaned branches created during restores (named like `production (old)`)
- These orphaned branches accumulate with each restore and consume storage
- Reduces snapshot management fees while shared storage remains
- Set `expires_at` for automatic cleanup or delete manually as needed
- Consider removing snapshots after merging features or completing rollback testing

## Concepts and terminology

### Neon core concepts

- [Project](/docs/reference/glossary#project): Neon project that owns branches, computes, and snapshots, and more
- [Branch](/docs/reference/glossary#branch): An isolated database environment with its own data and schema that you can connect to and modify
- [Snapshot](/docs/reference/glossary#snapshot): An immutable, point-in-time backup of a branch's schema and data. Read-only until restored
- [Root branch](/docs/reference/glossary#root-branch): A branch with no parent (typically named `main` or `production`). The only type of branch from which snapshots can be created
- [Operations](/docs/manage/operations#operations-and-the-neon-api): Backend operations that return operation IDs you must poll to completion

### Pattern-specific terminology

- **Active branch**: The root branch that serves as your agent's production database (though technically replaced during restores). Connection string never changes even when data is replaced via restore. Preview branches may be created alongside for temporary exploration.
- **Version**: A saved database state captured as a snapshot, which may also be referred to a checkpoint or edit. Users create and restore versions through your application interface.
- **Orphaned branch**: Created when restoring with `finalize_restore: true`. The previous active branch becomes orphaned (disconnected from compute) and is renamed to `branch-name (old)`. Can be safely deleted after verifying the restore.
- **Preview branch**: Temporary branch created from a snapshot for safe exploration, to preview a version

## API quick reference

| Operation                                                                               | Endpoint                                                             | Description                                  |
| --------------------------------------------------------------------------------------- | -------------------------------------------------------------------- | -------------------------------------------- |
| [Create snapshot](https://api-docs.neon.tech/reference/createsnapshot)                  | `POST /api/v2/projects/{project_id}/branches/{branch_id}/snapshot`   | Save current database state as a new version |
| [Restore snapshot](https://api-docs.neon.tech/reference/restoresnapshot)                | `POST /api/v2/projects/{project_id}/snapshots/{snapshot_id}/restore` | Restore database to a previous version       |
| [List snapshots](https://api-docs.neon.tech/reference/listsnapshots)                    | `GET /api/v2/projects/{project_id}/snapshots`                        | Get all available versions                   |
| [Delete snapshot](https://api-docs.neon.tech/reference/deletesnapshot)                  | `DELETE /api/v2/projects/{project_id}/snapshots/{snapshot_id}`       | Remove a saved version                       |
| [Update snapshot](https://api-docs.neon.tech/reference/updatesnapshot)                  | `PATCH /api/v2/projects/{project_id}/snapshots/{snapshot_id}`        | Rename a version                             |
| [Poll operation](https://api-docs.neon.tech/reference/getprojectoperation)              | `GET /api/v2/projects/{project_id}/operations/{operation_id}`        | Check restore status                         |
| [List branches](https://api-docs.neon.tech/reference/listprojectbranches) (for cleanup) | `GET /api/v2/projects/{project_id}/branches`                         | Find orphaned branches to clean up           |

## Implementation checklist

- [ ] Create one Neon project per agent project
- [ ] Designate the root branch (main/production) as the "active" branch
- [ ] Store the active branch connection string and branch ID
- [ ] Create snapshots at key points to save database versions
- [ ] For rollbacks: restore with `finalize_restore: true` and set `target_branch_id` to the root branch ID
- [ ] After a rollback, update your stored active branch ID
- [ ] For previews: restore with `finalize_restore: false` to create temporary branches
- [ ] Poll all operation IDs to terminal states before connecting
- [ ] Implement a cleanup strategy: set snapshot expiration dates and delete orphaned branches

## Best practices

- **Set `target_branch_id` for rollbacks**: When restoring to the active branch, always specify `target_branch_id` to prevent accidental restores.
- **Poll operations**: Wait for terminal states before connecting to the database.
- **Snapshot naming conventions**: Use descriptive conventions like `prod_snap_2025-01-17_pre-promotion`, `dev_snap_2025-01-17_candidate_v2`, `prod_snap_2025-01-17_after-promotion` to make automation easier.
- **Snapshot production before promotion**: Take a snapshot of your production branch before promoting changes to provide a rollback point if needed.
- **Differential retention**: Keep production snapshots longer for potential rollback, and development snapshots briefly (hours max) for promotion cycles only.
- **Implement connection retry logic**: Design application code to retry queries automatically, as restore operations briefly drop active connections (typically milliseconds, occasionally up to a second).
- **Keep backup branches briefly**: After restore, keep the automatically-created backup branch (e.g., `prod (old)`) for sanity checks before deletion, or assign a [time to live](/docs/guides/branch-expiration) for automatic cleanup.
- **Cleanup strategy**: Set `expires_at` on temporary snapshots and preview branches. Delete orphaned branches (e.g., `production (old)`) created during restores.
- **Version metadata**: Keep version metadata separate to preserve audit trail across restores.

## FAQ

<DefinitionList>
Why must I poll operations after restore?
: With `finalize_restore: true`, Neon moves compute resources to the new state. Until operations complete, connections still point to the old compute.

What happens to my active branch when I restore?
: When restoring with `finalize_restore: true`, your current active branch becomes orphaned (disconnected from the compute endpoint) and is renamed with "(old)" appended. This orphaned branch preserves your pre-restore state temporarily, but you should delete it after verifying the restore to avoid storage costs.

What if we need multiple preview environments?
: Restore different snapshots to new branches using `finalize_restore: false`. Each restore creates a new branch with its own connection string.

Why use snapshots instead of branches for versioning?
: **Snapshots**: Restoring a snapshot onto your active branch (`finalize_restore: true`) replaces the data but keeps the same database connection string. This is ideal for production rollbacks.
: **Branches**: Creating a new branch always generates a new connection string, which would require reconfiguring your application for every version change. Branches also create dependency chains that can complicate deletion.

</DefinitionList>

## Summary

The active branch pattern with Neon snapshots provides a simple, reliable versioning solution for AI agent and codegen platforms. By keeping database connection strings stable through the restore mechanism and using snapshots to implement version control, you get stable connection strings for your main database, instant rollbacks to previous versions, and the flexibility to create preview branches when needed. The implementation is straightforward: create snapshots to save versions, restore with `finalize_restore: true` to the active branch for rollbacks, or with `finalize_restore: false` for preview branches. Always poll operations to completion before connecting. See the [demo repository](https://github.com/neondatabase-labs/snapshots-as-checkpoints-demo) for a complete example.

<NeedHelp />


path: docs/ai/ai-github-copilot-agents.md
content: ---
title: Neon agents for GitHub Copilot
subtitle: Custom agents for safe database migrations and query optimization in VS Code
summary: >-
  Covers the setup of custom agents for GitHub Copilot that facilitate safe
  database migrations and query optimization in VS Code, utilizing Neon's
  branching workflow for efficient development.
enableTableOfContents: true
updatedOn: '2026-02-06T22:07:32.719Z'
---

GitHub Copilot now supports custom agents, and we've built two specialized agents that bring Neon's branching workflow directly into your IDE. These agents help you run safe database migrations and identify slow queries — all without leaving VS Code.

## Available agents

### Neon Migration Specialist

The [Neon Migration Specialist](https://github.com/github/awesome-copilot/blob/main/agents/neon-migration-specialist.agent.md) helps you run safe Postgres migrations with zero downtime using Neon's branching workflow.

**What it does:**

1. Creates a temporary database branch from your main branch
2. Runs your migration on the test branch to validate it works
3. Validates the changes thoroughly
4. Deletes the test branch after validation
5. Creates migration files and opens a PR — letting you or your CI/CD apply the migration to your main branch

The agent works with your existing ORM migration system (Prisma, Drizzle, SQLAlchemy, Django, Rails, and more) and falls back to [migra](https://github.com/djrobstep/migra) if no migration system exists.

<Admonition type="important">
The Migration Specialist never runs migrations directly on your main branch. All changes are tested on temporary branches first, and the actual migration is committed to your git repository for you or your CI/CD to execute.
</Admonition>

### Neon Performance Analyzer

The [Neon Performance Analyzer](https://github.com/github/awesome-copilot/blob/main/agents/neon-optimization-analyzer.agent.md) helps you identify and fix slow Postgres queries automatically.

**What it does:**

1. Creates an analysis branch from your main branch
2. Enables `pg_stat_statements` if not already installed
3. Identifies slow queries by analyzing execution statistics
4. Uses `EXPLAIN` to understand bottlenecks
5. Investigates your codebase to understand query context
6. Tests optimizations (indexes, query rewrites) on a temporary branch
7. Provides recommendations via PR with clear before/after metrics
8. Cleans up all temporary branches

The agent provides actionable code fixes with performance metrics showing execution time improvements, rows scanned, and other relevant data.

## Prerequisites

Both agents require:

- **Neon API Key**: Create one at [console.neon.tech/app/settings/api-keys](https://console.neon.tech/app/settings#api-keys)
- **Project ID or connection string**: The agent will ask for this if not provided

## Installation

### Option 1: Install from VS Code marketplace

The agents are available in the GitHub Copilot agent marketplace in VS Code:

1. Open VS Code
2. Go to the Extensions view
3. Search for "Neon Migration Specialist" or "Neon Performance Analyzer"
4. Click **Install**

### Option 2: Add to your repository

You can add the agent definition files directly to your project:

1. Create a `.github/copilot/agents/` directory in your repository
2. Download the agent files:
   - [neon-migration-specialist.agent.md](https://raw.githubusercontent.com/github/awesome-copilot/main/agents/neon-migration-specialist.agent.md)
   - [neon-optimization-analyzer.agent.md](https://raw.githubusercontent.com/github/awesome-copilot/main/agents/neon-optimization-analyzer.agent.md)
3. Save them to your `.github/copilot/agents/` directory

## Usage

Once installed, invoke the agents in GitHub Copilot Chat by mentioning their name:

### Migration examples

```
@neon-migration-specialist Add a new email column to my users table
```

```
@neon-migration-specialist Create a posts table with title, content, and author_id columns
```

```
@neon-migration-specialist Add a foreign key from orders.customer_id to customers.id
```

### Performance analysis examples

```
@neon-performance-analyzer Find and fix slow queries in my database
```

```
@neon-performance-analyzer Analyze why my user search query is slow
```

```
@neon-performance-analyzer Optimize the queries in my checkout flow
```

## How branching keeps your data safe

Both agents leverage Neon's instant branching to create isolated environments for testing. This means:

- **No changes to production**: All migrations and optimizations are tested on temporary branches first
- **Full data copy**: Test branches include a complete copy of your schema and data
- **Automatic cleanup**: Temporary branches are deleted after validation (default TTL: 4 hours)
- **Git-based workflow**: Changes are committed to your repository, not applied directly

This workflow ensures you can safely experiment with schema changes and performance optimizations without risking your production data.

## Resources

- [Neon Migration Specialist on GitHub](https://github.com/github/awesome-copilot/blob/main/agents/neon-migration-specialist.agent.md)
- [Neon Performance Analyzer on GitHub](https://github.com/github/awesome-copilot/blob/main/agents/neon-optimization-analyzer.agent.md)
- [Neon branching documentation](/docs/introduction/branching)
- [awesome-copilot repository](https://github.com/github/awesome-copilot)

<NeedHelp />


path: docs/ai/ai-google-colab.md
content: ---
title: Google Colab
subtitle: Use Google Colab with Neon for vector similarity search
summary: >-
  Step-by-step guide for using Google Colab with Neon to create a notebook,
  connect to a Neon database, install the `pgvector` extension, and execute
  vector similarity search queries.
enableTableOfContents: true
updatedOn: '2026-02-06T22:07:32.720Z'
---

[Google Colab](https://colab.research.google.com/) is a hosted Jupyter Notebook service that requires no setup to use and provides free access to computing resources, including GPUs and TPUs.
You can use Google Colab to run python code through the browser.

This guide shows how to create a notebook in Colab, connect to a Neon database, install the `pgvector` extension to enabled Neon as a vector store, and run a vector search query.

## Prerequisites

To perform the steps in this guide, you require a Neon database for storing vectors. You can use the ready-to-use `neondb` database or create your own. See [Create a database](/docs/manage/databases#create-a-database) for instructions.

## Retrieve your database connection string

Click **Connect** on your **Project Dashboard** to open the **Connect to your database** modal, and select a branch, a user, and the database you want to connect to. A connection string is constructed for you.

![Connection modal](/docs/connect/connection_details.png)

## Create a notebook

In your browser, navigate to [Google Colab](https://colab.research.google.com/), and click **New notebook**.

![Google Colab](/docs/ai/google_colab.png)

Alternatively, you can open a predefined Google Colab notebook for this guide by clicking the **Open in Colab** button below.

<a target="_blank" href="https://colab.research.google.com/github/neondatabase/neon-google-colab-notebooks/blob/main/neon_pgvector_quickstart.ipynb">
  <img src="https://colab.research.google.com/assets/colab-badge.svg" alt="Open In Colab"/>
</a>

## Connect to your database

1. In your Colab notebook, create a code block to define your database connection and create a cursor object. Replace `postgresql://[user]:[password]@[neon_hostname]/[dbname]` with the database connection string you retrieved in the previous step.

   ```python shouldWrap
   import os
   import psycopg2

   # Provide your Neon connection string
   connection_string = "postgresql://[user]:[password]@[neon_hostname]/[dbname]"

   # Connect using the connection string
   connection = psycopg2.connect(connection_string)

   # Create a new cursor object
   cursor = connection.cursor()
   ```

2. Execute the code block (**Ctrl** + **Enter**).

3. Add a code block for testing the database connection.

   ```python
   # Execute this query to test the database connection
   cursor.execute("SELECT 1;")
   result = cursor.fetchone()

   # Check the query result
   if result == (1,):
       print("Your database connection was successful!")
   else:
       print("Your connection failed.")
   ```

4. Execute the code block (**Ctrl** + **Enter**).

## Install the pgvector extension

1. Create a codeblock to install the `pgvector` extension to enable your Neon database as a vector store:

   ```python
   # Execute this query to install the pgvector extension
   cursor.execute("CREATE EXTENSION IF NOT EXISTS vector;")
   ```

2. Execute the code block (**Ctrl** + **Enter**).

## Create a table and add vector data

1. Add a code block to create a table and insert data:

   ```python shouldWrap
   create_table_sql = '''
   CREATE TABLE items (
   id BIGSERIAL PRIMARY KEY,
   embedding VECTOR(3)
   );
   '''

   # Insert data
   insert_data_sql = '''
   INSERT INTO items (embedding) VALUES ('[1,2,3]'), ('[4,5,6]'), ('[7,8,9]');
   '''

   # Execute the SQL statements
   cursor.execute(create_table_sql)
   cursor.execute(insert_data_sql)

   # Commit the changes
   connection.commit()
   ```

2. Execute the code block (**Ctrl** + **Enter**).

## Query your data

1. Add a codeblock to perform a vector similarity search.

   ```python shouldWrap
   cursor.execute("SELECT * FROM items ORDER BY embedding <-> '[3,1,2]' LIMIT 3;")
   all_data = cursor.fetchall()
   print(all_data)
   ```

2. Execute the code block (**Ctrl** + **Enter**).

## Next steps

For more information about using Neon with `pgvector`, see [The pgvector extension](/docs/extensions/pgvector).

<NeedHelp/>


path: docs/ai/ai-intro.md
content: ---
title: AI Starter Kit
subtitle: Resources for building AI applications with Neon Postgres
summary: >-
  Covers resources for building AI applications with Neon Postgres, including
  core concepts, framework integrations, and starter applications for developing
  tools like chatbots and semantic search engines.
enableTableOfContents: true
redirectFrom:
  - /docs/ai/ai-app-build
updatedOn: '2026-02-06T22:07:32.721Z'
---

This guide collects resources for building AI applications with Neon Postgres. You'll find core concepts, starter applications, framework integrations, and deployment guides. Use these resources to build applications like RAG chatbots, semantic search engines, or custom AI tools.

<CTA title="Start building AI apps with Neon" description="Sign up for Neon Postgres and jumpstart your AI application with our starter apps and resources." buttonText="Sign Up" buttonUrl="https://console.neon.tech/signup" />

## Getting started

Learn the fundamentals of building AI applications with Neon:

<DetailIconCards>

<a href="/docs/ai/ai-concepts" description="Learn the fundamentals of embeddings and vector search for AI applications" icon="openai">AI concepts</a>

<a href="/docs/extensions/pgvector" description="Get started with pgvector for storing and querying vector embeddings" icon="openai">pgvector extension</a>

</DetailIconCards>

## AI frameworks and integrations

Build AI applications faster with these popular frameworks, tools, and services:

<DetailIconCards>

<a href="/docs/ai/langchain" description="Create AI applications using LangChain with OpenAI and Neon" icon="langchain">LangChain</a>

<a href="/docs/ai/llamaindex" description="Build RAG applications using LlamaIndex with OpenAI and Neon" icon="llamaindex">LlamaIndex</a>

<a href="/docs/ai/semantic-kernel" description="Develop AI applications using Semantic Kernel with Azure OpenAI" icon="openai">Semantic Kernel</a>

<a href="/docs/ai/inngest" description="Build reliable AI workflows with Inngest and Neon" icon="openai">Inngest</a>

<a href="/docs/ai/ai-app-build" description="Generate and deploy web applications using the open-source app.build agent" icon="gear">app.build</a>

</DetailIconCards>

## Starter applications

Hackable, fully-featured, pre-built starter apps to get you up and running:

<DetailIconCards>

<a href="https://github.com/neondatabase/examples/tree/main/ai/llamaindex/chatbot-nextjs" description="A Next.js AI chatbot starter app built with OpenAI and LlamaIndex" icon="github">AI chatbot (OpenAI + LllamIndex)</a>

<a href="https://github.com/neondatabase/examples/tree/main/ai/langchain/chatbot-nextjs" description="A Next.js AI chatbot starter app built with OpenAI and LangChain" icon="github">AI chatbot (OpenAI + LangChain)</a>

<a href="https://github.com/neondatabase/examples/tree/main/ai/llamaindex/rag-nextjs" description="A Next.js RAG chatbot starter app built with OpenAI and LlamaIndex" icon="github">RAG chatbot (OpenAI + LlamaIndex)</a>

<a href="https://github.com/neondatabase/examples/tree/main/ai/langchain/rag-nextjs" description="A Next.js RAG chatbot starter app built with OpenAI and LangChain" icon="github">RAG chatbot (OpenAI + LangChain)</a>

<a href="https://github.com/neondatabase/examples/tree/main/ai/llamaindex/semantic-search-nextjs" description="A Next.js Semantic Search chatbot starter app built with OpenAI and LlamaIndex" icon="github">Semantic search (OpenAI + LlamaIndex)</a>

<a href="https://github.com/neondatabase/examples/tree/main/ai/langchain/semantic-search-nextjs" description="A Next.js Semantic Search chatbot starter app built with OpenAI and LangChain" icon="github">Semantic search (OpenAI + LangChain)</a>

<a href="https://github.com/neondatabase/examples/tree/main/ai/hybrid-search-nextjs" description="A Next.js Hybrid Search starter app built with OpenAI" icon="github">Hybrid search (OpenAI)</a>

<a href="https://github.com/neondatabase/examples/tree/main/ai/llamaindex/reverse-image-search-nextjs" description="A Next.js Reverse Image Search Engine starter app built with OpenAI and LlamaIndex" icon="github">Reverse image search (OpenAI + LlamaIndex)</a>

<a href="https://github.com/neondatabase/examples/tree/main/ai/llamaindex/chat-with-pdf-nextjs" description="A Next.js Chat with PDF chatbot starter app built with OpenAI and LlamaIndex" icon="github">Chat with PDF (OpenAI + LlamaIndex)</a>

<a href="https://github.com/neondatabase/examples/tree/main/ai/langchain/chat-with-pdf-nextjs" description="A Next.js Chat with PDF chatbot starter app built with OpenAI and LangChain" icon="github">Chat with PDF (OpenAI + LangChain)</a>

</DetailIconCards>

## Scale your AI application

<DetailIconCards>

<a href="/docs/ai/ai-scale-with-neon" description="Learn how to scale your AI application with Autoscaling and Read Replicas" icon="openai">Scale with Neon</a>

<a href="/docs/ai/ai-vector-search-optimization" description="Best practices for optimizing vector search performance" icon="openai">Optimize vector search</a>

</DetailIconCards>

## Featured examples

Real-world AI applications built with Neon that you can reference as code examples or inspiration.

<Admonition type="tip" title="Built something cool?">
Share your AI app on our [#showcase](https://discord.gg/neon) channel on Discord.
</Admonition>

<DetailIconCards>

<a href="https://github.com/neondatabase/ai-vector-db-per-tenant" description="Deploy an AI vector database per-tenant architecture with Neon" icon="github">AI vector database per tenant</a>

<a href="/guides/chatbot-astro-postgres-llamaindex" description="Build a RAG chatbot in an Astro application with LlamaIndex and Postgres" icon="openai">Guide: Build a RAG chatbot</a>

<a href="/guides/llamaindex-postgres-search-images" description="Using LlamaIndex with Postgres to Build your own Reverse Image Search Engine" icon="openai">Guide: Build a Reverse Image Search Engine</a>

<a href="https://github.com/neondatabase/ask-neon" description="An Ask Neon AI-powered chatbot built with pgvector" icon="github">Ask Neon Chatbot</a>

<a href="https://vercel.com/templates/next.js/postgres-pgvector" description="Enable vector similarity search with Vercel Postgres powered by Neon" icon="github">Vercel Postgres pgvector Starter</a>

<a href="https://github.com/neondatabase/yc-idea-matcher" description="YCombinator semantic search application" icon="github">YCombinator Semantic Search App</a>

<a href="https://github.com/neondatabase/postgres-ai-playground" description="An AI-enabled SQL playground application for natural language queries" icon="github">Web-based AI SQL Playground</a>

<a href="https://github.com/neondatabase/neon-vector-search-openai-notebooks" description="Jupyter Notebook for vector search with Neon, pgvector, and OpenAI" icon="github">Jupyter Notebook for vector search with Neon</a>

<a href="https://github.com/ItzCrazyKns/Neon-Image-Search" description="Community: An image search app built with Neon and Vertex AI" icon="github">Image search with Neon and Vertex AI</a>

<a href="https://github.com/mistralai/cookbook/blob/main/third_party/Neon/neon_text_to_sql.ipynb" description="A Text-to-SQL conversion app built with Mistral AI, Neon, and LangChain" icon="github">Text-to-SQL conversion with Mistral + LangChain</a>

<a href="/blog/openais-gpt-store-is-live-create-and-publish-a-custom-postgres-gpt-expert" description="Blog + repo: Create and publish a custom Postgres GPT Expert using OpenAI's GPT" icon="openai">Postgres GPT Expert</a>

</DetailIconCards>

## Vector search tools and notebooks

Optimize your vector search implementation and experiment with different approaches:

<DetailIconCards>

<a href="/docs/ai/ai-vector-search-optimization" description="Best practices for optimizing vector search performance" icon="openai">Vector search optimization</a>

<a href="https://github.com/neondatabase/neon-vector-search-openai-notebooks" description="Interactive notebooks for vector search with OpenAI" icon="github">Vector search notebooks</a>

<a href="/docs/ai/ai-google-colab" description="Use Neon with Google Colab for ML experiments" icon="openai">Google Colab guide</a>

<a href="/docs/ai/ai-azure-notebooks" description="A cloud-based Jupyter notebook service integrated with Azure Data Studio" icon="openai">Azure Data Studio Notebooks</a>

</DetailIconCards>


path: docs/ai/ai-rules-neon-api.md
content: ---
title: 'AI Rules: Neon API'
subtitle: Context rules for AI tools to use the Neon API to programmatically manage Neon
  projects, branches, databases, and other resources.
summary: >-
  Covers the setup of AI rules for using the Neon API to manage projects,
  branches, databases, and resources programmatically, with options for copying
  rules or cloning from a repository.
enableTableOfContents: true
updatedOn: '2026-02-06T22:07:32.722Z'
---

<Admonition type="note" title="AI Rules are in Beta">
AI Rules are currently in beta. We're actively improving them and would love to hear your feedback. Join us on [Discord](https://discord.gg/92vNTzKDGp) to share your experience and suggestions.
</Admonition>

<InfoBlock>
<DocsList title="Related docs" theme="docs">
  <a href="/docs/reference/api-reference">Neon API</a>
</DocsList>

<DocsList title="Repository" theme="repo">
  <a href="https://api-docs.neon.tech/reference/getting-started-with-neon-api">Neon API Reference Docs</a>
  <a href="https://github.com/neondatabase-labs/ai-rules/blob/main/neon-api-guidelines.mdc">neon-api-guidelines.mdc</a>
</DocsList>
</InfoBlock>

<AIRule file="neon-api-guidelines.mdc" name="Neon API" />

## How to use

You can use the following Neon API rules in two ways:

<Steps>
## Option 1: Copy from this page

With Cursor, save the [rules](https://docs.cursor.com/context/rules-for-ai#project-rules-recommended) to `.cursor/rules/file_name.mdc` and they'll be automatically applied when working with matching files.

For other AI tools, you can include these rules as context when chatting with your AI assistant - check your tool's documentation for the specific method (like using "Include file" or context commands).

## Option 2: Clone from repository

If you prefer, you can clone or download the rules directly from our [AI Rules repository](https://github.com/neondatabase-labs/ai-rules).

Once added to your project, AI tools will automatically use these rules when working with Neon API. You can also reference them explicitly in prompts.
</Steps>

## Neon API rules: General guidelines

Save the following content to a file named `neon-api-guidelines.mdc` in your AI tool's rules directory.

<ExternalCode
  url="https://raw.githubusercontent.com/neondatabase-labs/ai-rules/main/neon-api-guidelines.mdc"
  language="md"
/>

## Neon API rules: Manage API keys

Save the following content to a file named `neon-api-keys.mdc` in your AI tool's rules directory.

<ExternalCode
  url="https://raw.githubusercontent.com/neondatabase-labs/ai-rules/main/neon-api-keys.mdc"
  language="md"
/>

## Neon API rules: Manage operations

Save the following content to a file named `neon-api-operations.mdc` in your AI tool's rules directory.

<ExternalCode
  url="https://raw.githubusercontent.com/neondatabase-labs/ai-rules/main/neon-api-operations.mdc"
  language="md"
/>

## Neon API rules: Manage projects

Save the following content to a file named `neon-api-projects.mdc` in your AI tool's rules directory.

<ExternalCode
  url="https://raw.githubusercontent.com/neondatabase-labs/ai-rules/main/neon-api-projects.mdc"
  language="md"
/>

## Neon API Rules: Manage Branches

Save the following content to a file named `neon-api-branches.mdc` in your AI tool's rules directory.

<ExternalCode
  url="https://raw.githubusercontent.com/neondatabase-labs/ai-rules/main/neon-api-branches.mdc"
  language="md"
/>

## Neon API Rules: Manage Compute Endpoints

Save the following content to a file named `neon-api-endpoints.mdc` in your AI tool's rules directory.

<ExternalCode
  url="https://raw.githubusercontent.com/neondatabase-labs/ai-rules/main/neon-api-endpoints.mdc"
  language="md"
/>

## Neon API Rules: Manage Organizations

Save the following content to a file named `neon-api-organizations.mdc` in your AI tool's rules directory.

<ExternalCode
  url="https://raw.githubusercontent.com/neondatabase-labs/ai-rules/main/neon-api-organizations.mdc"
  language="md"
/>


path: docs/ai/ai-rules-neon-auth.md
content: ---
title: 'AI Rules: Neon Auth'
subtitle: Context rules for AI tools to help implement authentication with Neon Auth
summary: >-
  Covers the implementation of authentication rules for AI tools using Neon
  Auth, providing context and guidelines for effective integration.
enableTableOfContents: true
updatedOn: '2026-02-06T22:07:32.722Z'
---

<Admonition type="note" title="AI Rules are in Beta">
AI Rules are currently in beta. We're actively improving them and would love to hear your feedback. Join us on [Discord](https://discord.gg/92vNTzKDGp) to share your experience and suggestions.
</Admonition>

<InfoBlock>

<DocsList title="Related docs" theme="docs">
  <a href="/docs/guides/neon-auth">Neon Auth</a>
</DocsList>

<DocsList title="Repository" theme="repo">
  <a href="https://github.com/neondatabase-labs/ai-rules">READ ME</a>
  <a href="https://github.com/neondatabase-labs/ai-rules/blob/main/neon-auth.mdc">neon-auth.mdc</a>
</DocsList>
</InfoBlock>

<AIRule file="neon-auth.mdc" name="Neon Auth" />

## Rules

<ExternalCode
  url="https://raw.githubusercontent.com/neondatabase-labs/ai-rules/main/neon-auth.mdc"
  language="md"
/>


path: docs/ai/ai-rules-neon-drizzle.md
content: ---
title: 'AI Rules: Neon with Drizzle'
subtitle: Context rules for AI tools to help implement Drizzle ORM with Neon databases
summary: >-
  Covers the implementation of Drizzle ORM with Neon databases, including
  context rules for AI tools to enhance the integration process.
enableTableOfContents: true
updatedOn: '2026-02-06T22:07:32.723Z'
---

<Admonition type="note" title="AI Rules are in Beta">
AI Rules are currently in beta. We're actively improving them and would love to hear your feedback. Join us on [Discord](https://discord.gg/92vNTzKDGp) to share your experience and suggestions.
</Admonition>

<InfoBlock>
<DocsList title="Related docs" theme="docs">
  <a href="https://orm.drizzle.team/docs/get-started/neon-new">Get started with Drizzle and Neon</a>
</DocsList>

<DocsList title="Repository" theme="repo">
  <a href="https://github.com/neondatabase-labs/ai-rules">README</a>
  <a href="https://github.com/neondatabase-labs/ai-rules/blob/main/neon-drizzle.mdc">neon-drizzle.mdc</a>
</DocsList>
</InfoBlock>

<AIRule file="neon-drizzle.mdc" name="Neon with Drizzle" />

## Rules

<ExternalCode
  url="https://raw.githubusercontent.com/neondatabase-labs/ai-rules/main/neon-drizzle.mdc"
  language="md"
/>


path: docs/ai/ai-rules-neon-python-sdk.md
content: ---
title: 'AI Rules: Neon Python SDK'
subtitle: Context rules for AI tools to use the Neon Python SDK
summary: >-
  Covers the context rules for AI tools utilizing the Neon Python SDK, currently
  in beta, and invites user feedback for improvements.
enableTableOfContents: true
updatedOn: '2026-02-06T22:07:32.724Z'
---

<Admonition type="note" title="AI Rules are in Beta">
AI Rules are currently in beta. We're actively improving them and would love to hear your feedback. Join us on [Discord](https://discord.gg/92vNTzKDGp) to share your experience and suggestions.
</Admonition>

<InfoBlock>
<DocsList title="Related docs" theme="docs">
  <a href="/docs/reference/python-sdk">Get started with Neon Python SDK</a>
  <a href="/docs/reference/api-reference">Neon API Reference</a>
</DocsList>

<DocsList title="Repository" theme="repo">
  <a href="https://github.com/neondatabase/neon-api-python">Github Repo</a>
  <a href="https://neon-api-python.readthedocs.io/en/latest/">Python SDK Docs</a>
  <a href="https://github.com/neondatabase-labs/ai-rules/blob/main/neon-python-sdk.mdc">neon-python-sdk.mdc</a>
</DocsList>
</InfoBlock>

<AIRule file="neon-python-sdk.mdc" name="Neon Python SDK" />

## Rules

<ExternalCode
  url="https://raw.githubusercontent.com/neondatabase-labs/ai-rules/main/neon-python-sdk.mdc"
  language="md"
/>


path: docs/ai/ai-rules-neon-serverless.md
content: ---
title: AI Rules Neon Serverless Driver
subtitle: Context rules for AI tools to help implement the Neon Serverless driver
summary: >-
  Covers the implementation of AI rules for the Neon Serverless driver,
  providing context and guidance for integrating AI tools within the Neon
  environment.
enableTableOfContents: true
updatedOn: '2026-02-06T22:07:32.724Z'
---

<Admonition type="note" title="AI Rules are in Beta">
AI Rules are currently in beta. We're actively improving them and would love to hear your feedback. Join us on [Discord](https://discord.gg/92vNTzKDGp) to share your experience and suggestions.
</Admonition>

<InfoBlock>
<DocsList title="Related docs" theme="docs">
  <a href="/docs/serverless/serverless-driver">Neon Serverless Driver</a>
</DocsList>

<DocsList title="Repository" theme="repo">
  <a href="https://github.com/neondatabase-labs/ai-rules#readme">README</a>
  <a href="https://github.com/neondatabase-labs/ai-rules/blob/main/neon-serverless.mdc">neon-serverless.mdc</a>
</DocsList>
</InfoBlock>

<AIRule file="neon-serverless.mdc" name="Neon Serverless" />

## Rules

<ExternalCode
  url="https://raw.githubusercontent.com/neondatabase-labs/ai-rules/main/neon-serverless.mdc"
  language="md"
/>


path: docs/ai/ai-rules-neon-toolkit.md
content: ---
title: 'AI Rules: The @neondatabase/toolkit'
subtitle: Context rules for AI tools to use the @neondatabase/toolkit for ephemeral
  Postgres databases
summary: >-
  Covers the context rules for utilizing the @neondatabase/toolkit with
  ephemeral Postgres databases, currently in beta, and invites user feedback for
  improvements.
enableTableOfContents: true
updatedOn: '2026-02-06T22:07:32.725Z'
---

<Admonition type="note" title="AI Rules are in Beta">
AI Rules are currently in beta. We're actively improving them and would love to hear your feedback. Join us on [Discord](https://discord.gg/92vNTzKDGp) to share your experience and suggestions.
</Admonition>

<InfoBlock>
<DocsList title="Related docs" theme="docs">
  <a href="/docs/reference/neondatabase-toolkit">Get started with the @neondatabase/toolkit</a>
  <a href="/docs/reference/typescript-sdk">Neon API TypeScript SDK</a>
  <a href="/docs/reference/api-reference">Neon API Reference</a>
</DocsList>

<DocsList title="Repository" theme="repo">
  <a href="https://www.npmjs.com/package/@neondatabase/toolkit">`@neondatabase/toolkit` on npm</a>
  <a href="https://jsr.io/@neon/toolkit">`@neon/toolkit` on JSR</a>
  <a href="https://github.com/neondatabase-labs/ai-rules/blob/main/neon-toolkit.mdc">neon-toolkit.mdc</a>
</DocsList>
</InfoBlock>

<AIRule file="neon-toolkit.mdc" name="@neondatabase/toolkit" />

## Rules

<ExternalCode
  url="https://raw.githubusercontent.com/neondatabase-labs/ai-rules/main/neon-toolkit.mdc"
  language="md"
/>


path: docs/ai/ai-rules-neon-typescript-sdk.md
content: ---
title: 'AI Rules: Neon API TypeScript SDK'
subtitle: Context rules for AI tools to use the Neon API TypeScript SDK
summary: >-
  Covers the context rules for utilizing the Neon API TypeScript SDK, currently
  in beta, to enhance AI tool integration and functionality.
enableTableOfContents: true
updatedOn: '2026-02-06T22:07:32.726Z'
---

<Admonition type="note" title="AI Rules are in Beta">
AI Rules are currently in beta. We're actively improving them and would love to hear your feedback. Join us on [Discord](https://discord.gg/92vNTzKDGp) to share your experience and suggestions.
</Admonition>

<InfoBlock>
<DocsList title="Related docs" theme="docs">
  <a href="/docs/reference/typescript-sdk">Get started with Neon API TypeScript SDK</a>
  <a href="/docs/reference/api-reference">Neon API Reference</a>
</DocsList>

<DocsList title="Repository" theme="repo">
  <a href="https://www.npmjs.com/package/@neondatabase/api-client">`@neondatabase/api-client` on npm</a>
  <a href="https://github.com/neondatabase-labs/ai-rules/blob/main/neon-typescript-sdk.mdc">neon-typescript-sdk.mdc</a>
</DocsList>
</InfoBlock>

<AIRule file="neon-typescript-sdk.mdc" name="Neon TypeScript SDK" />

## Rules

<ExternalCode
  url="https://raw.githubusercontent.com/neondatabase-labs/ai-rules/main/neon-typescript-sdk.mdc"
  language="md"
/>


path: docs/ai/ai-rules.md
content: ---
title: AI rules and prompts
subtitle: Enhance your AI development experience with Neon-specific context rules
summary: >-
  Covers the setup of AI context rules for Neon, including installation
  instructions for the Claude Code plugin and individual context rule files for
  other AI tools, enhancing code suggestions and reducing errors.
enableTableOfContents: true
updatedOn: '2026-02-06T22:07:32.726Z'
---

Boost your productivity with AI context rules for Neon. These rules help AI assistants understand Neon's features, leading to more accurate code suggestions and fewer common mistakes.

If you're using **Claude Code**, install the comprehensive Neon plugin that bundles Skills, MCP integration, and all context rules in one package. For other AI tools like **Cursor**, use the individual `.mdc` context rule files.

<Admonition type="note" title="AI Rules are in Beta">
AI Rules are currently in beta. We're actively improving them and would love to hear your feedback. Join us on [Discord](https://discord.gg/92vNTzKDGp) to share your experience and suggestions.
</Admonition>

## For Claude Code

If you're using Claude Code, install the Neon plugin to get Skills, MCP integration, and all the context rules in one package:

<DetailIconCards>

<a href="/docs/ai/ai-claude-code-plugin" description="Install the Neon Claude Code plugin to give Claude access to Neon's APIs, Postgres workflows, and built-in Skills" icon="github">Claude Code plugin for Neon</a>

</DetailIconCards>

## Individual AI rules

For other AI tools like Cursor, you can use these individual `.mdc` context rule files. Copy them to your AI tool's custom rules directory — the format is tool-agnostic and works with any AI assistant that supports context rules.

<DetailIconCards>

<a href="/docs/ai/ai-rules-neon-auth" description="AI rules for implementing authentication with Neon" icon="lock-landscape">Neon Auth</a>

<a href="/docs/ai/ai-rules-neon-serverless" description="AI rules for serverless database connections" icon="network">Neon Serverless Driver</a>

<a href="/docs/ai/ai-rules-neon-drizzle" description="AI rules for using Drizzle ORM with Neon" icon="drizzle">Neon Drizzle</a>

<a href="/docs/ai/ai-rules-neon-typescript-sdk" description="AI rules for using the Neon API TypeScript SDK" icon="code">Neon API TypeScript SDK</a>

<a href="/docs/ai/ai-rules-neon-python-sdk" description="AI rules for using the Neon Python SDK" icon="code">Neon Python SDK</a>

<a href="/docs/ai/ai-rules-neon-api" description="AI rules for using the Neon API" icon="code">Neon API</a>

<a href="/docs/ai/ai-rules-neon-toolkit" description="AI rules for using the Neon Toolkit" icon="database">Neon Toolkit</a>

</DetailIconCards>

## How it works

AI rules are `.mdc` files that specify which types of files they apply to (such as `*.tsx` or `schema.sql`). When you're working with a matching file, your AI tool automatically applies the relevant rules to provide better suggestions.

### Example: AI rules in action

Here's a practical example using [Cursor](https://www.cursor.so). A developer has implemented authentication in their server-rendered page and wants to confirm best practices:

**Developer query**: _"Using the neon-auth.mdc rule, how do I secure a server-rendered page?"_

![Screenshot of Cursor applying the neon-auth.mdc rule](/docs/ai/ai-rules.png)

The AI confirms that using `stackServerApp.getUser({ or: "redirect" })` is the correct approach for server-side authentication, providing additional context and explanation.

## Add rules to your project

All `.mdc` files are available in the [Neon AI Rules toolkit repository](https://github.com/neondatabase-labs/ai-rules). Copy the files you need to your project's `.cursor/rules` folder (or your AI tool's equivalent):

```text
.cursor/
  rules/
    neon-auth.mdc
    neon-serverless.mdc
    neon-drizzle.mdc
    neon-toolkit.mdc
    neon-typescript-sdk.mdc
    neon-python-sdk.mdc
    neon-api-guidelines.mdc
    neon-api-projects.mdc
    neon-api-branches.mdc
    neon-api-endpoints.mdc
    neon-api-organizations.mdc
    neon-api-keys.mdc
    neon-api-operations.mdc
```

Most AI tools will automatically apply these rules when you're working with Neon-related code. You can also reference them explicitly in prompts for more targeted assistance.


path: docs/ai/ai-scale-with-neon.md
content: ---
title: Scale your AI application with Neon
subtitle: Scale your AI application with Neon's Autoscaling and Read Replica features
summary: >-
  Covers the scaling of AI applications using Neon's Autoscaling and Read
  Replica features, detailing vertical and horizontal scaling options with
  specific compute sizes and associated memory configurations.
enableTableOfContents: true
updatedOn: '2026-02-06T22:07:32.727Z'
---

You can scale your AI application built on Postgres with `pgvector` in the same way you would any Postgres app: Vertically with added CPU, RAM, and storage, or horizontally with read replicas.

In Neon, scaling vertically is a matter of selecting the desired compute size. Neon supports compute sizes ranging from .25 CU (1 GB RAM) up to 56 CU (224 GB RAM). Autoscaling is supported up to 16 CU. Larger computes are fixed size computes (no autoscaling). The `maintenance_work_mem` values shown below are approximate.

| Compute Units (CU) | RAM    | maintenance_work_mem |
| :----------------- | :----- | :------------------- |
| 0.25               | 1 GB   | 64 MB                |
| 0.50               | 2 GB   | 64 MB                |
| 1                  | 4 GB   | 67 MB                |
| 2                  | 8 GB   | 134 MB               |
| 3                  | 12 GB  | 201 MB               |
| 4                  | 16 GB  | 268 MB               |
| 5                  | 20 GB  | 335 MB               |
| 6                  | 24 GB  | 402 MB               |
| 7                  | 28 GB  | 470 MB               |
| 8                  | 32 GB  | 537 MB               |
| 9                  | 36 GB  | 604 MB               |
| 10                 | 40 GB  | 671 MB               |
| 11                 | 44 GB  | 738 MB               |
| 12                 | 48 GB  | 805 MB               |
| 13                 | 52 GB  | 872 MB               |
| 14                 | 56 GB  | 939 MB               |
| 15                 | 60 GB  | 1007 MB              |
| 16                 | 64 GB  | 1074 MB              |
| 18                 | 72 GB  | 1208 MB              |
| 20                 | 80 GB  | 1342 MB              |
| 22                 | 88 GB  | 1476 MB              |
| 24                 | 96 GB  | 1610 MB              |
| 26                 | 104 GB | 1744 MB              |
| 28                 | 112 GB | 1878 MB              |
| 30                 | 120 GB | 2012 MB              |
| 32                 | 128 GB | 2146 MB              |
| 34                 | 136 GB | 2280 MB              |
| 36                 | 144 GB | 2414 MB              |
| 38                 | 152 GB | 2548 MB              |
| 40                 | 160 GB | 2682 MB              |
| 42                 | 168 GB | 2816 MB              |
| 44                 | 176 GB | 2950 MB              |
| 46                 | 184 GB | 3084 MB              |
| 48                 | 192 GB | 3218 MB              |
| 50                 | 200 GB | 3352 MB              |
| 52                 | 208 GB | 3486 MB              |
| 54                 | 216 GB | 3620 MB              |
| 56                 | 224 GB | 3754 MB              |

See [Edit a compute](/docs/manage/computes#edit-a-compute) to configure your compute size. Available compute sizes differ according to your Neon plan.

To optimize `pgvector` index build time, you can increase the `maintenance_work_mem` setting for the current session beyond the preconfigured default shown in the table above with a command similar to this:

```sql
SET maintenance_work_mem='10 GB';
```

The recommended `maintenance_work_mem` setting is your working set size (the size of your tuples for vector index creation). However, your `maintenance_work_mem` setting should not exceed 50 to 60 percent of your compute's available RAM (see the table above). For example, the `maintenance_work_mem='10 GB'` setting shown above has been successfully tested on a 7 CU compute, which has 28 GB of RAM, as 10 GB is less than 50% of the RAM available for that compute size.

## Autoscaling

You can also enable Neon's autoscaling feature for automatic scaling of compute resources. Neon's _Autoscaling_ feature automatically scales up compute on demand in response to application workload and down to zero on inactivity.

For example, if your AI application experiences heavy load during certain hours of the day or at different times throughout the week, month, or calendar year, Neon automatically scales compute resources without manual intervention according to the compute size boundaries that you configure. This enables you to handle peak demand while avoiding consuming compute resources during periods of low activity.

Enabling autoscaling is also recommended for initial data loads and memory-intensive index builds to ensure sufficient compute resources for this phase of your AI application setup.

To learn more about Neon's autoscaling feature and how to enable it, refer to our [Autoscaling guide](/docs/introduction/autoscaling).

## Storage

On the Free plan, you get 0.5 GB of storage plus 0.5 GB of storage per branch. Storage on paid plans is usage based. See [Neon plans](/docs/introduction/plans) for details.

## Read replicas

Neon supports read replicas, which are independent read-only computes designed to perform read operations on the same data as your primary read-write compute. Read replicas do not replicate data across database instances. Instead, read requests are directed to the same data source. This architecture enables read replicas to be created instantly, enabling you to scale out CPU and RAM, but because data is read from a single source, there are no additional storage costs.

Since vector similarity search is a read-only workload, you can leverage read replicas to offload reads from your primary read-write compute to a dedicated compute when deploying AI applications. After you create a read replica, you can simply swap out your current Neon connecting string for the read replica connection string, which makes deploying a read replica for your AI application very simple.

Neon's read replicas support the same compute sizes outlined above. Read replicas also support autoscaling.

To learn more about the Neon read replicas, see [read replicas](/docs/introduction/read-replicas) and refer to our [Working with Neon read replicas](/docs/guides/read-replica-guide) guide.


path: docs/ai/ai-vector-search-optimization.md
content: ---
title: Optimize pgvector search
subtitle: Fine-tune parameters for efficient and accurate similarity searches in
  Postgres
summary: >-
  Step-by-step guide for optimizing `pgvector` searches in Postgres, focusing on
  profiling queries, indexing strategies, and parameter tuning to enhance
  performance and accuracy in AI applications.
enableTableOfContents: true
updatedOn: '2026-02-06T22:07:32.728Z'
---

This guide explores how to effectively use `pgvector` for vector similarity searches in your AI applications. We'll address the following key questions:

1. How to profile your vector search queries, when using `pgvector`?
2. When to use indexes and tradeoffs between the available options?
3. Which parameters to tune for best performance?

We'll examine sequential scans, HNSW indexing, and IVFFlat indexing, providing benchmarks and practical recommendations for various dataset sizes. This will help you optimize `pgvector` queries in your Neon database for both accuracy and speed.

Without indexes, `pgvector` performs a sequential scan on the database and calculates the distance between the query vector and all vectors in the table. This approach does an exact search and guarantees 100% **recall**, but it can be costly with large datasets.

<Admonition type="note" title="what is recall?">
Recall is a metric used to evaluate the performance of a search algorithm. It measures how effectively the search retrieves relevant items from a dataset. It is defined as the ratio of the number of relevant items retrieved by the search to the total number of relevant items in the dataset.
</Admonition>

The query below uses `EXPLAIN ANALYZE` to generate an execution plan and display the performance of the similarity search query.

```sql shouldWrap
EXPLAIN ANALYZE SELECT * FROM items ORDER BY embedding <-> '[0.011699999682605267,..., 0.008700000122189522]' LIMIT 100;
```

This is what the query plan looks like:

```sql
Limit  (cost=748.19..748.44 rows=100 width=173) (actual time=39.475..39.487 rows=100 loops=1)
  ->  Sort  (cost=748.19..773.19 rows=10000 width=173) (actual time=39.473..39.480 rows=100 loops=1)
        Sort Key: ((vec <-> '[0.0117,..., 0.0866]'::vector))
        Sort Method: top-N heapsort  Memory: 70kB
        ->  Seq Scan on items  (cost=0.00..366.00 rows=10000 width=173) (actual time=0.087..37.571 rows=10000 loops=1)
Planning Time: 0.213 ms
Execution Time: 39.527 ms
```

You can see in the plan that the query performs a sequential scan (`Seq Scan`) on the `items` table, which means that the query compares the query vector against all vectors in the `items` table. In other words, the query does not use an index.

To understand how queries perform at scale, we tested sequential scan vector searches with `pgvector` on subsets of the [GIST-960 dataset](http://corpus-texmex.irisa.fr/) with 10k, 50k, 100k, 500k, and 1M rows using a Neon database instance with 4 CU (16 GB of RAM).

The sequential scan search performed reasonably well for tables with 10k rows (~36ms). However, sequential scans start to become costly at 50k rows.

So, when should you use sequential scans rather than defining an index?

- When your dataset is small and you do not intend to scale it.
- When you need 100% recall (accuracy). Adding indexes trades recall for performance.
- When you do not expect a high volume of queries per second, which would require indexes for performance.

Otherwise, consider adding an index for better performance.

## Indexing with HNSW

HNSW is a graph-based approach to indexing multi-dimensional data. It constructs a multi-layered graph, where each layer is a subset of the previous one. During a vector similarity search, the algorithm navigates through the graph from the top layer to the bottom to quickly find the nearest neighbor. An HNSW graph is known for its superior performance in terms of speed and accuracy.

<Admonition type="note">
An HNSW index performs better than IVFFlat (in terms of speed-recall tradeoff) and can be created without any data in the table since there isn’t a training step like there is for an IVFFlat index. However, HNSW indexes have slower build times and use more memory.
</Admonition>

![HNSW graph](/docs/extensions/hnsw_graph.png)

The search process begins at the topmost layer of the HNSW graph. From the starting node, the algorithm navigates to the nearest neighbor in the same layer. The algorithm repeats this step until it can no longer find neighbors more similar to the query vector.

Using the found node as an entry point, the algorithm moves down to the next layer in the graph and repeats the process of navigating to the nearest neighbor. The process of navigating to the nearest neighbor and moving down a layer is repeated until the algorithm reaches the bottom layer.

In the bottom layer, the algorithm continues navigating to the nearest neighbor until it cannot find any nodes that are more similar to the query vector. The current node is then returned as the most similar node to the query vector.

The key idea behind HNSW is that by starting the search at the top layer and moving down through each layer, the algorithm can quickly navigate to the area of the graph that contains the node that is most similar to the query vector. This makes the search process much faster than if it had to search through every node in the graph.

### Tuning the HNSW algorithm

The following options allow you to tune the HNSW algorithm when creating an index:

- `m`: Defines the maximum number of links created for each node during graph construction. A higher value increases accuracy (recall), but it also increases the size of the index in memory and index construction time. Higher values are typically used with high-dimensionality datasets or when a high degree of accuracy is required. The default value is 16. Acceptable values for m typically fall between 2 and 100. For many applications, beginning with a range of 12 to 48 is advisable.
- `ef_construction`: Defines the size of the list for the nearest neighbors. This value influences the tradeoff between index quality and construction speed. A high `ef_construction` value creates a higher quality graph, enabling more accurate search results but also means that index construction takes longer. The value should be set to at least twice the value of `m`. The default setting is 64. There comes a point where increasing `ef_construction` no longer improves index quality. To evaluate search accuracy, you can start by setting `ef_construction` equal to `ef_search` and incrementally increasing `ef_construction` to achieve the desired result. If accuracy is lower than 0.9, there may be opportunity for improvement by increasing `ef_construction`.

This example demonstrates how to set the parameters:

```sql shouldWrap
CREATE INDEX ON items USING hnsw (embedding vector_l2_ops) WITH (m = 16, ef_construction = 64);
```

HNSW search tuning:

- `ef_search`: Defines the size of the dynamic candidate list for search. The default value is 40. This value influences the trade-off between query accuracy (recall) and speed. A higher value increases accuracy at the cost of speed. The value should be equal to or larger than `k`, which is the number of nearest neighbors you want your search to return (defined by the `LIMIT` clause in your `SELECT` query).

To configure this value, do so using a `SET` statement before executing queries:

```sql
SET hnsw.ef_search = 100;
```

You can also use `SET LOCAL` inside a transaction to set it for a single query:

```sql
BEGIN;
SET LOCAL hnsw.ef_search = 100;
SELECT ...
COMMIT;
```

In summary:

- To prioritize search speed over accuracy, use lower values for `m` and `ef_search`.
- Conversely, to prioritize accuracy over search speed, use a higher value for `m` and `ef_search`.
- Using a higher value for `ef_construction` yields more accurate search results at the cost of index build time.

## Indexing with IVFFlat

IVFFlat indexes partition the dataset into clusters ("lists") to optimize for vector search.

You can create an IVFFlat index using the query below:

```sql shouldWrap
CREATE INDEX items_embedding_cosine_idx ON items USING ivfflat (embedding vector_l2_ops) WITH (lists = 1000);
```

IVFFlat in `pgvector` has two parameters:

1. `lists`
   - This parameter specifies the number of [k-means clusters](https://en.wikipedia.org/wiki/K-means_clustering) (or "lists") to divide the dataset into
   - Each cluster contains a subset of the data, and each data point belongs to the closest cluster centroid.

2. `probes`
   - This parameter determines the number of lists to explore during the search for the nearest neighbors.
   - By probing multiple lists, the search algorithm can find the closest points more accurately, balancing between speed and accuracy.

By default, the `probes` parameter is set to `1`. This means that during a search, only one cluster is explored. This approach is fine if your query vector is close to the centroid. However, if the query vector is located near the edge of the cluster, closer neighbors in adjacent clusters will not be included in the search, which can result in a lower recall.

You must specify the number of probes in the same connection as the search query:

```sql shouldWrap
SET ivfflat.probes = 100;
SET enable_seqscan=off;
SELECT * FROM items ORDER BY embedding <-> '[0.011699999682605267,..., 0.008700000122189522]' LIMIT 100;
```

<Admonition type="note">
In the example above, `enable_seqscan=off` forces Postgres to use index scans.
</Admonition>

The output of this query appears as follows:

```sql
Limit  (cost=1971.50..1982.39 rows=100 width=173) (actual time=4.500..5.738 rows=100 loops=1)
  ->  Index Scan using items_embedding_idx on vectors  (cost=1971.50..3060.50 rows=10000 width=173) (actual time=4.499..5.726 rows=100 loops=1)
        Order By: (vec <-> '[0.0117, ... ,0.0866]'::vector)
Planning Time: 0.295 ms
Execution Time: 5.867 ms
```

We've experimented with `lists` equal to 1000, 2000, and 4000, and `probes` equal to 1, 2, 10, 50, 100, 200.

Although there is a substantial gain in recall for increasing the number of `probes`, you will reach a point of diminishing returns when recall plateaus and execution time increases.

Therefore, we encourage experimenting with different values for `probes` and `lists` to achieve optimal search performance for your queries. Good places to start are:

- Using a `lists` size equal to rows / 1000 for tables with up to 1 million rows, and `sqrt(rows)` for larger datasets.
- Start with a `probes` value equal to lists / 10 for tables up to 1 million rows, and `sqrt(lists)` for larger datasets.

## Conclusion

The sequential scan approach of `pgvector` performs well for small datasets but can be costly for larger ones. Use sequential scans if you require 100% accuracy, but expect performance issues with higher volumes of queries per second.

You can optimize searches using HNSW or IVFFlat indexes for approximate nearest neighbor (ANN) search, but HNSW indexes have better query performance than IVFFlat with build time and memory usage tradeoffs.

Be sure to test different index tuning parameter settings to find the right balance between speed and accuracy for your specific use case and dataset.


path: docs/ai/connect-mcp-clients-to-neon.md
content: ---
title: Connect MCP clients to Neon
subtitle: Learn how to connect MCP clients such as Cursor, Claude Code, VS Code,
  ChatGPT, and other tools to your Neon Postgres database.
summary: >-
  Covers the setup of connecting MCP clients like Cursor, Claude Code, and VS
  Code to the Neon Postgres database, including quick setup, OAuth
  authentication, and local server options.
enableTableOfContents: true
updatedOn: '2026-02-06T22:07:32.729Z'
---

This guide covers connecting MCP clients to the Neon MCP Server for natural language interaction with your Neon Postgres databases.

<Admonition type="important" title="Security">
The Neon MCP Server is intended for **development and testing only**. Always review LLM-requested actions before execution. See [MCP security guidance](/docs/ai/neon-mcp-server#mcp-security-guidance).
</Admonition>

## Quick setup (Cursor, VS Code, Claude Code)

The fastest way to get started:

```bash
npx neonctl@latest init
```

This installs the MCP server for all your projects with API key-based authentication so you can skip OAuth windows. It also adds the VS Code extension for editors that support it and adds Neon's [agent skills](https://github.com/neondatabase/agent-skills) to help agents use Neon the right way. Then restart and ask your AI assistant **"Get started with Neon"**.

If you only want the MCP server and nothing else, use:

```bash
npx add-mcp https://mcp.neon.tech/mcp
```

This adds the MCP config to your editor's configuration files. Add `-g` for global (user-level) setup instead of project-level. Restart your editor (or enable the MCP server in your editor's settings); when you use the connection, an OAuth window will open to authorize. For API key authentication, add `--header "Authorization: Bearer $NEON_API_KEY"`. For more options, see the [add-mcp repository](https://github.com/neondatabase/add-mcp).

## Setup options

- **Quick Setup:** Cursor, Claude Code, and VS Code support automatic setup with `npx neonctl@latest init` (MCP server with API key auth, VS Code extension where supported, and agent skills)
- **OAuth:** Connect to Neon's remote MCP server (no local installation needed)
- **Local:** Run the MCP server locally with your API key (requires Node.js >= v18)

For Local setup, you'll need a [Neon API key](/docs/manage/api-keys#creating-api-keys).

## Cursor

<Tabs labels={["Quick Setup", "OAuth", "Local"]}>
<TabItem>

Run the [init](/docs/reference/cli-init) command:

```bash
npx neonctl@latest init
```

Authenticates via OAuth, creates an API key, installs the [Neon extension](/docs/local/vscode-extension) (which includes the MCP Server), and installs [agent skills](https://github.com/neondatabase/agent-skills). Then ask your AI assistant **"Get started with Neon"**.

</TabItem>
<TabItem>

```bash
npx add-mcp https://mcp.neon.tech/mcp -a cursor
```

Restart Cursor (or enable the MCP server in settings). When the OAuth window opens, click **Authorize** to complete the connection.

</TabItem>
<TabItem>

1.  Open Cursor. Create a `.cursor` directory in your project root if needed.
2.  Create or open the `mcp.json` file in the `.cursor` directory.
3.  Add the "Neon" server entry within the `mcpServers` object. Replace `<YOUR_NEON_API_KEY>` with your Neon API key:

    ```json
    {
      "mcpServers": {
        "neon": {
          "command": "npx",
          "args": ["-y", "@neondatabase/mcp-server-neon", "start", "<YOUR_NEON_API_KEY>"]
        }
      }
    }
    ```

4.  Save the configuration file. Cursor may detect the change or require a restart.

</TabItem>
</Tabs>

For more, see [Get started with Cursor and Neon Postgres MCP Server](/guides/cursor-mcp-neon).

## Claude Code

<Tabs labels={["Quick Setup", "OAuth", "Local"]}>
<TabItem>

Run the [init](/docs/reference/cli-init) command:

```bash
npx neonctl@latest init
```

Authenticates via OAuth, creates an API key, configures the MCP Server in `~/.claude.json`, and installs [agent skills](https://github.com/neondatabase/agent-skills). Then ask your AI assistant **"Get started with Neon"**.

</TabItem>

<TabItem>

```bash
npx add-mcp https://mcp.neon.tech/mcp -a claude-code
```

Restart Claude Code (or enable the MCP server in settings). When the OAuth window opens, click **Authorize** to complete the connection.

</TabItem>

<TabItem>

```bash
claude mcp add neon -- npx -y @neondatabase/mcp-server-neon start "<YOUR_NEON_API_KEY>"
```

Replace `<YOUR_NEON_API_KEY>` with your [Neon API key](/docs/manage/api-keys).

</TabItem>
</Tabs>

For more, see [Get started with Claude Code and Neon Postgres MCP Server](/guides/claude-code-mcp-neon).

## VS Code (with GitHub Copilot)

<Admonition type="note">
To use MCP servers with VS Code, you need [GitHub Copilot](https://marketplace.visualstudio.com/items?itemName=GitHub.copilot) and [GitHub Copilot Chat](https://marketplace.visualstudio.com/items?itemName=GitHub.copilot-chat) extensions installed
</Admonition>

<Tabs labels={["Quick Setup", "OAuth", "Local"]}>
<TabItem>

Run the [init](/docs/reference/cli-init) command:

```bash
npx neonctl@latest init
```

Authenticates via OAuth, creates an API key, installs the [Neon extension](/docs/local/vscode-extension) (which includes the MCP Server), and installs [agent skills](https://github.com/neondatabase/agent-skills). Then ask your AI assistant **"Get started with Neon"**.

</TabItem>

<TabItem>

```bash
npx add-mcp https://mcp.neon.tech/mcp -a vscode
```

Restart VS Code (or enable the MCP server in settings). When the OAuth window opens, click **Authorize** to complete the connection. Then open GitHub Copilot Chat and [switch to Agent mode](https://code.visualstudio.com/docs/copilot/chat/chat-agent-mode).

</TabItem>

<TabItem>

Add the Neon MCP server to your [User Settings (JSON)](https://code.visualstudio.com/docs/copilot/chat/mcp-servers#_add-an-mcp-server-to-your-user-settings):

```json
{
  "mcp": {
    "servers": {
      "neon": {
        "command": "npx",
        "args": ["-y", "@neondatabase/mcp-server-neon", "start", "<YOUR_NEON_API_KEY>"]
      }
    }
  }
}
```

Replace `<YOUR_NEON_API_KEY>` with your [Neon API key](/docs/manage/api-keys). Then open GitHub Copilot Chat and [switch to Agent mode](https://code.visualstudio.com/docs/copilot/chat/chat-agent-mode).

</TabItem>

</Tabs>

For a detailed guide including an Azure Function REST API example, see [Using Neon MCP Server with GitHub Copilot in VS Code](/guides/neon-mcp-server-github-copilot-vs-code).

## ChatGPT

Connect ChatGPT to Neon using custom MCP connectors. Enable Developer mode, add the Neon connector, then enable it per chat.

![ChatGPT with Neon MCP Server](/docs/changelog/chatgpt_mcp.png)

1. **Add MCP server to ChatGPT**

   In your ChatGPT account settings, go to **Settings** → **Connectors** → **Advanced Settings** and enable **Developer mode**.

   Still on the Connectors tab, you can then **create** a Neon connection from the **Browse connectors** section. Use the following URL:

   ```bash
   https://mcp.neon.tech/mcp
   ```

   Make sure you choose **OAuth** for authentication and check "I trust this application", then complete the authorization flow when prompted.

   <div style={{display: 'flex', gap: '0.5rem', margin: '1rem 0'}}>
     <div style={{flex: 1}}>
       ![ChatGPT connector configuration](/docs/ai/chatgpt_mcp_add_connector.png)
     </div>
     <div style={{flex: 1}}>
       ![ChatGPT with Neon MCP tools enabled](/docs/ai/chatgpt_mcp_tools.png)
     </div>
   </div>

2. **Enable Neon per chat**

   In each chat where you want to use Neon, click the **+** button and enable Developer Mode for that chat. Under **Add sources**, you can then enable the Neon connector you just created.

   Once connected, you can use natural language to manage your Neon databases directly in ChatGPT.

## Claude Desktop

<Tabs labels={["OAuth", "Local"]}>

<TabItem>

```bash
npx add-mcp https://mcp.neon.tech/mcp -a claude-desktop
```

Restart Claude Desktop. When the OAuth window opens, click **Authorize** to complete the connection.

</TabItem>

<TabItem>

```bash
npx @neondatabase/mcp-server-neon init <YOUR_NEON_API_KEY>
```

Replace `<YOUR_NEON_API_KEY>` with your [Neon API key](/docs/manage/api-keys), then restart Claude Desktop.

</TabItem>
</Tabs>

For more, see [Get started with Neon MCP server with Claude Desktop](/guides/neon-mcp-server).

## Cline (VS Code Extension)

<Tabs labels={["OAuth", "Local"]}>
<TabItem>

1. Open Cline in VS Code (Sidebar -> Cline icon).
2. Click **MCP Servers** Icon -> **Installed** -> **Configure MCP Servers** to open the configuration file.
3. Add the "Neon" server entry within the `mcpServers` object:

   ```json
   {
     "mcpServers": {
       "neon": {
         "command": "npx",
         "args": ["-y", "mcp-remote@latest", "https://mcp.neon.tech/mcp"]
       }
     }
   }
   ```

4. Save the file. Cline should reload the configuration automatically.
5. When the OAuth window opens in your browser, review the requested permissions and click **Authorize** to complete the connection.

</TabItem>
<TabItem>

1. Open Cline in VS Code (Sidebar -> Cline icon).
2. Click **MCP Servers** Icon -> **Installed** -> **Configure MCP Servers** to open the configuration file.
3. Add the "Neon" server entry within the `mcpServers` object:

   ```json
   {
     "mcpServers": {
       "neon": {
         "command": "npx",
         "args": ["-y", "@neondatabase/mcp-server-neon", "start", "<YOUR_NEON_API_KEY>"]
       }
     }
   }
   ```

   > Replace `<YOUR_NEON_API_KEY>` with your Neon API key.

4. Save the file. Cline should reload the configuration automatically.

</TabItem>
</Tabs>

For more, see [Get started with Cline and Neon Postgres MCP Server](/guides/cline-mcp-neon).

## Windsurf (Codeium)

<Tabs labels={["OAuth", "Local"]}>
<TabItem>

1.  Open Windsurf and navigate to the Cascade assistant sidebar.
2.  Click the hammer (MCP) icon, then **Configure** which opens up the "Manage MCPs" configuration file.
3.  Click on "View raw config" to open the raw configuration file in Windsurf.
4.  Add the "Neon" server entry within the `mcpServers` object:

    ```json
    {
      "mcpServers": {
        "neon": {
          "command": "npx",
          "args": ["-y", "mcp-remote@latest", "https://mcp.neon.tech/mcp"]
        }
      }
    }
    ```

5.  Save the file.
6.  Click the **Refresh** button in the Cascade sidebar next to "available MCP servers".
7.  When the OAuth window opens in your browser, review the requested permissions and click **Authorize** to complete the connection.

</TabItem>
<TabItem>

1.  Open Windsurf and navigate to the Cascade assistant sidebar.
2.  Click the hammer (MCP) icon, then **Configure** which opens up the "Manage MCPs" configuration file.
3.  Click on "View raw config" to open the raw configuration file in Windsurf.
4.  Add the "Neon" server entry within the `mcpServers` object:

    ```json
    {
      "mcpServers": {
        "neon": {
          "command": "npx",
          "args": ["-y", "@neondatabase/mcp-server-neon", "start", "<YOUR_NEON_API_KEY>"]
        }
      }
    }
    ```

    > Replace `<YOUR_NEON_API_KEY>` with your Neon API key.

5.  Save the file.
6.  Click the **Refresh** button in the Cascade sidebar next to "available MCP servers".

</TabItem>
</Tabs>

For more, see [Get started with Windsurf and Neon Postgres MCP Server](/guides/windsurf-mcp-neon).

## Zed

<Admonition type="note">
MCP support in Zed is currently in **preview**. Ensure you're using the Preview version of Zed to add MCP servers (called **Context Servers** in Zed). Download the preview version from [zed.dev/releases/preview](https://zed.dev/releases/preview).
</Admonition>

<Tabs labels={["OAuth", "Local"]}>
<TabItem>

```bash
npx add-mcp https://mcp.neon.tech/mcp -a zed
```

Restart Zed (or enable the MCP server in settings). When the OAuth window opens, click **Authorize** to complete the connection.

</TabItem>

<TabItem>

1. Open the Zed Preview application.
2. Click the Assistant (✨) icon, then **Settings** > **Context Servers** > **+ Add Context Server**.
3. Enter **neon** as the name and this command:

   ```bash
   npx -y @neondatabase/mcp-server-neon start <YOUR_NEON_API_KEY>
   ```

4. Replace `<YOUR_NEON_API_KEY>` with your [Neon API key](/docs/manage/api-keys) and click **Add Server**.

</TabItem>
</Tabs>

For more details, including workflow examples and troubleshooting, see [Get started with Zed and Neon Postgres MCP Server](/guides/zed-mcp-neon).

## Other MCP clients

For Cursor, VS Code, and Claude Code, use `npx neonctl@latest init` as the preferred setup (see [Quick setup](#quick-setup-cursor-vs-code-claude-code) above). For other clients, or if you only want the MCP server, use **add-mcp**:

```bash
npx add-mcp https://mcp.neon.tech/mcp
```

This tool auto-detects supported clients and configures them. Use `-a <agent>` to target a specific agent (e.g., `-a cursor`). Add `-g` for global (user-level) setup instead of project-level. For more options (including global vs project-level), see the [add-mcp repository](https://github.com/neondatabase/add-mcp). For manual configuration, add one of these to your client's `mcpServers` section:

**OAuth (remote server):**

```json
"neon": {
  "command": "npx",
  "args": ["-y", "mcp-remote@latest", "https://mcp.neon.tech/mcp"]
}
```

**Local setup:**

```json
"neon": {
  "command": "npx",
  "args": ["-y", "@neondatabase/mcp-server-neon", "start", "<YOUR_NEON_API_KEY>"]
}
```

For Windows-specific configurations, see [Local MCP Server](/docs/ai/neon-mcp-server#other-setup-options).

## Troubleshooting

### Configuration Issues

If your client does not use `JSON` for configuration of MCP servers (such as older versions of Cursor), you can use the following command when prompted:

```bash
# For OAuth (remote server)
npx -y mcp-remote https://mcp.neon.tech/mcp

# For Local setup
npx -y @neondatabase/mcp-server-neon start <YOUR_NEON_API_KEY>
```

<Admonition type="note">
For clients that don't support Streamable HTTP, you can use the deprecated SSE endpoint: `https://mcp.neon.tech/sse`. SSE is not supported with API key authentication.
</Admonition>

### OAuth Authentication Errors

When using the remote MCP server with OAuth authentication, you might encounter the following error:

```
{"code":"invalid_request","error":"invalid redirect uri"}
```

This typically occurs when there are issues with cached OAuth credentials. To resolve this:

1. Remove the MCP authentication cache directory:
   ```bash
   rm -rf ~/.mcp-auth
   ```
2. Restart your MCP client application
3. The OAuth flow will start fresh, allowing you to properly authenticate

This error is most common when using OAuth authentication and can occur after OAuth configuration changes or when cached credentials become invalid.

## Next steps

Once connected, explore the [available MCP tools](/docs/ai/neon-mcp-server#supported-actions-tools) to see what you can do with natural language.

## Resources

- [MCP Protocol](https://modelcontextprotocol.org)
- [Neon API Reference](https://api-docs.neon.tech/reference/getting-started-with-neon-api)
- [Neon API Keys](/docs/manage/api-keys#creating-api-keys)
- [Neon MCP server GitHub](https://github.com/neondatabase/mcp-server-neon)
- [VS Code MCP Server Documentation](https://code.visualstudio.com/docs/copilot/chat/mcp-servers)

<NeedHelp/>


path: docs/ai/inngest.md
content: ---
title: Inngest
subtitle: Quickly build AI RAG and Agentic workflows that scale with Inngest and Neon
summary: >-
  Covers the setup of Inngest for building scalable AI RAG and Agentic
  workflows, including automatic retries, caching, and integration with Neon
  Postgres for triggering workflows based on database changes.
enableTableOfContents: true
updatedOn: '2026-02-06T22:07:32.731Z'
---

Inngest is a popular framework for building AI RAG and Agentic workflows. [Inngest](https://www.inngest.com/?utm_source=neon&utm_medium=inngest-ai-integration) provides automatic retries, caching along with concurrency and throttling management and AI requests offloading.

Inngest also integrates with Neon Postgres to trigger workflows based on database changes.

## Build RAG with `step.run()`

Inngest provides a `step.run()` API that allows you to compose your workflows into cacheable, retryable, and concurrency-safe steps:

![A RAG workflow built with Inngest. A failing step is retried while the previous steps results are cached.](/docs/guides/inngest-rag-workflow.png)

In the above workflow, a network issue prevented the AI workflow to connect to the vector store. Fortunately, Inngest retries the failed step and uses the cached results from the previous steps, avoiding an unnecessary additional OpenAI call.

This workflow translates to the following code:

```typescript
import { inngest } from '@/inngest';
import { getToolsForMessage, vectorSearch } from '@/helpers';

export const ragWorkflow = client.createFunction(
  { id: 'rag-workflow', concurrency: 10 },
  { event: 'chat.message' },
  async ({ event, step }) => {
    const { message } = event.data;

    const page = await step.run('tools.search', async () => {
      // Calls OpenAI
      return getToolsForMessage(message);
    });

    await step.run('vector-search', async () => {
      // Search in Neon's vector store
      return vectorSearch(page);
    });

    // step 3 and 4...
  }
);
```

Configuring [concurrency](https://www.inngest.com/docs/guides/concurrency?utm_source=neon&utm_medium=inngest-ai-integration) or [throttling](https://www.inngest.com/docs/guides/throttling?utm_source=neon&utm_medium=inngest-ai-integration) to match your LLM provider's limits is achieved with a single line of code.

Learn more about using Inngest for RAG in the following article: [Multi-Tenant RAG With One Neon Project Per User](/blog/multi-tenant-rag).

## AI requests offloading: `step.ai.infer()`

Inngest also provides a `step.ai.infer()` API that offloads AI requests.
By using `step.ai.infer()` your AI workflows will pause while waiting for the slow LLM response, avoiding unnecessary compute use on Serverless environments:

![An AI workflow built with Inngest. The AI request is offloaded to the LLM provider.](/docs/guides/inngest-with-step-ai-infer.png)

![An AI workflow built with Inngest. The AI request is offloaded to the LLM provider.](/docs/guides/inngest-without-step-ai-infer.png)

The previous RAG workflow can be rewritten to use [`step.ai.infer()`](https://www.inngest.com/docs/features/inngest-functions/steps-workflows/step-ai-orchestration?utm_source=neon&utm_medium=inngest-ai-integration#step-ai-infer) to offload the AI request to the LLM provider:

```typescript
import { inngest } from '@/inngest';
import { getPromptForToolsSearch, vectorSearch } from '@/helpers';

export const ragWorkflow = client.createFunction(
  { id: 'rag-workflow', concurrency: 10 },
  { event: 'chat.message' },
  async ({ event, step }) => {
    const { message } = event.data;

    const prompt = getPromptForToolsSearch(message);
    await step.ai.infer('tools.search', {
      model: openai({ model: 'gpt-4o' }),
      body: {
        messages: prompt,
      },
    });

    // other steps...
  }
);
```

`step.ai.infer()`, combined with Neon's Scale-to-zero feature, allows you to build AI workflows that scale costs with its success!

Learn more about using `step.ai.infer()` in the following article: [step.ai: Build Serverless AI Applications That Won't Break the Bank](https://www.inngest.com/blog/step-ai-for-serverless-ai-applications?utm_source=neon&utm_medium=inngest-ai-integration).

## Trigger AI workflows based on database changes

Inngest also integrates with Neon Postgres to trigger AI workflows based on database changes:

![Inngest integrates with Neon Postgres to trigger AI workflows based on database changes](/docs/guides/inngest.jpg)

This integration allows you to trigger AI workflows based on database changes, such as generating embeddings as soon as a new row is inserted into a table (see example below).

Configure the Inngests Neon integration to trigger AI workflows from your Neon database changes [by following this guide](/docs/guides/trigger-serverless-functions).

## Starter apps

Hackable, fully-featured, pre-built [starter apps](https://github.com/neondatabase/examples/tree/main/ai/inngest) to get you up and running with Inngest and Postgres.

<DetailIconCards>

<a href="https://github.com/neondatabase/examples/tree/main/ai/inngest/rag-starter-nextjs" description="A Next.js RAG starter app built with OpenAI and Inngest" icon="github">RAG starter (OpenAI + Inngest)</a>

<a href="https://github.com/inngest/multi-tenant-rag-example" description="A Next.js contacts importer multi-tenant RAG built with OpenAI and Inngest" icon="github">multi-tenant RAG (OpenAI + Inngest)</a>

<a href="https://github.com/neondatabase/examples/tree/main/ai/inngest/auto-embeddings-nextjs" description="A Next.js app example of auto-embedding with Inngest" icon="github">Auto-embedding (OpenAI + Inngest)</a>

</DetailIconCards>


path: docs/ai/langchain.md
content: ---
title: LangChain
subtitle: Build AI applications faster with LangChain and Postgres
summary: >-
  Covers the setup of LangChain with Neon as a vector store, detailing how to
  initialize Postgres, generate embeddings, and implement chat completions using
  OpenAI's API.
enableTableOfContents: true
updatedOn: '2026-02-06T22:07:32.732Z'
---

LangChain is a popular framework for working with AI, Vectors, and embeddings. LangChain supports using Neon as a vector store, using the `pgvector` extension.

## Initialize Postgres Vector Store

LangChain simplifies the complexity of managing document insertion and embeddings generation using vector stores by providing streamlined methods for these tasks.

Here's how you can initialize Postgres Vector with LangChain:

```tsx
// File: vectorStore.ts

import { NeonPostgres } from '@langchain/community/vectorstores/neon';
import { OpenAIEmbeddings } from '@langchain/openai';

const embeddings = new OpenAIEmbeddings({
  dimensions: 512,
  model: 'text-embedding-3-small',
});

export async function loadVectorStore() {
  return await NeonPostgres.initialize(embeddings, {
    connectionString: process.env.POSTGRES_URL as string,
  });
}

// Use in your code (say, in API routes)
const vectorStore = await loadVectorStore();
```

## Generate Embeddings with OpenAI

LangChain handles embedding generation internally while adding vectors to the Postgres database, simplifying the process for users. For more detailed control over embeddings, refer to the respective [JavaScript](https://js.langchain.com/v0.2/docs/integrations/text_embedding/openai#specifying-dimensions) and [Python](https://python.langchain.com/v0.2/docs/how_to/embed_text/#embed_query) documentation.

## Stream Chat Completions with OpenAI

LangChain can find similar documents to the user's latest query and invoke the OpenAI API to power [chat completion](https://platform.openai.com/docs/guides/text-generation/chat-completions-api) responses, providing a seamless integration for creating dynamic interactions.

Here's how you can power chat completions in an API route:

```tsx
import { loadVectorStore } from './vectorStore';

import { pull } from 'langchain/hub';
import { ChatOpenAI } from '@langchain/openai';
import { createRetrievalChain } from 'langchain/chains/retrieval';
import type { ChatPromptTemplate } from '@langchain/core/prompts';
import { AIMessage, HumanMessage } from '@langchain/core/messages';
import { createStuffDocumentsChain } from 'langchain/chains/combine_documents';

const topK = 3;

export async function POST(request: Request) {
  const llm = new ChatOpenAI();
  const encoder = new TextEncoder();
  const vectorStore = await loadVectorStore();
  const { messages = [] } = await request.json();
  const userMessages = messages.filter((i) => i.role === 'user');
  const input = userMessages[userMessages.length - 1].content;
  const retrievalQAChatPrompt = await pull<ChatPromptTemplate>('langchain-ai/retrieval-qa-chat');
  const retriever = vectorStore.asRetriever({ k: topK, searchType: 'similarity' });
  const combineDocsChain = await createStuffDocumentsChain({
    llm,
    prompt: retrievalQAChatPrompt,
  });
  const retrievalChain = await createRetrievalChain({
    retriever,
    combineDocsChain,
  });
  const customReadable = new ReadableStream({
    async start(controller) {
      const stream = await retrievalChain.stream({
        input,
        chat_history: messages.map((i) =>
          i.role === 'user' ? new HumanMessage(i.content) : new AIMessage(i.content)
        ),
      });
      for await (const chunk of stream) {
        controller.enqueue(encoder.encode(chunk.answer));
      }
      controller.close();
    },
  });
  return new Response(customReadable, {
    headers: {
      Connection: 'keep-alive',
      'Content-Encoding': 'none',
      'Cache-Control': 'no-cache, no-transform',
      'Content-Type': 'text/plain; charset=utf-8',
    },
  });
}
```

## Starter apps

Hackable, fully-featured, pre-built [starter apps](https://github.com/neondatabase/examples/tree/main/ai/llamaindex) to get you up and running with LlamaIndex and Postgres.

<DetailIconCards>

<a href="https://github.com/neondatabase/examples/tree/main/ai/langchain/chatbot-nextjs" description="A Next.js AI chatbot starter app built with OpenAI and LangChain" icon="github">AI chatbot (OpenAI + LangChain)</a>

<a href="https://github.com/neondatabase/examples/tree/main/ai/langchain/rag-nextjs" description="A Next.js RAG chatbot starter app built with OpenAI and LangChain" icon="github">RAG chatbot (OpenAI + LangChain)</a>

<a href="https://github.com/neondatabase/examples/tree/main/ai/langchain/semantic-search-nextjs" description="A Next.js Semantic Search chatbot starter app built with OpenAI and LangChain" icon="github">Semantic search chatbot (OpenAI + LangChain)</a>

<a href="https://github.com/neondatabase/examples/tree/main/ai/langchain/chat-with-pdf-nextjs" description="A Next.js Chat with PDF chatbot starter app built with OpenAI and LangChain" icon="github">Chat with PDF (OpenAI + LangChain)</a>

</DetailIconCards>


path: docs/ai/llamaindex.md
content: ---
title: LlamaIndex
subtitle: Build AI applications faster with LlamaIndex and Postgres
summary: >-
  Covers the setup of LlamaIndex with Postgres as a vector store, detailing how
  to initialize the vector store, generate embeddings, and integrate chat
  completions using OpenAI's API.
enableTableOfContents: true
updatedOn: '2026-02-06T22:07:32.732Z'
---

LlamaIndex is a popular framework for working with AI, Vectors, and embeddings. LlamaIndex supports using Neon as a vector store, using the `pgvector` extension.

## Initialize Postgres Vector Store

LlamaIndex simplifies the complexity of managing document insertion and embeddings generation using vector stores by providing streamlined methods for these tasks.

Here's how you can initialize Postgres Vector with LlamaIndex:

```tsx
// File: vectorStore.ts

import { OpenAIEmbedding, Settings } from 'llamaindex';
import { PGVectorStore } from 'llamaindex/storage/vectorStore/PGVectorStore';

Settings.embedModel = new OpenAIEmbedding({
  dimensions: 512,
  model: 'text-embedding-3-small',
});

const vectorStore = new PGVectorStore({
  dimensions: 512,
  connectionString: process.env.POSTGRES_URL,
});

export default vectorStore;

// Use in your code (say, in API routes)
const index = await VectorStoreIndex.fromVectorStore(vectorStore);
```

## Generate Embeddings with OpenAI

LlamaIndex handles embedding generation internally while adding vectors to the Postgres database, simplifying the process for users. For more detailed control over embeddings, refer to the respective [JavaScript](https://ts.llamaindex.ai/docs/llamaindex/modules/models/embeddings/openai) and [Python](https://docs.llamaindex.ai/en/stable/examples/embeddings/OpenAI) documentation.

## Stream Chat Completions with OpenAI

LlamaIndex can find similar documents to the user's latest query and invoke the OpenAI API to power [chat completion](https://platform.openai.com/docs/guides/text-generation/chat-completions-api) responses, providing a seamless integration for creating dynamic interactions.

Here's how you can power chat completions in an API route:

```tsx
import vectorStore from './vectorStore';

import { ContextChatEngine, VectorStoreIndex } from 'llamaindex';

interface Message {
  role: 'user' | 'assistant' | 'system' | 'memory';
  content: string;
}

export async function POST(request: Request) {
  const encoder = new TextEncoder();
  const { messages = [] } = (await request.json()) as { messages: Message[] };
  const userMessages = messages.filter((i) => i.role === 'user');
  const query = userMessages[userMessages.length - 1].content;
  const index = await VectorStoreIndex.fromVectorStore(vectorStore);
  const retriever = index.asRetriever();
  const chatEngine = new ContextChatEngine({ retriever });
  const customReadable = new ReadableStream({
    async start(controller) {
      const stream = await chatEngine.chat({ message: query, chatHistory: messages, stream: true });
      for await (const chunk of stream) {
        controller.enqueue(encoder.encode(chunk.response));
      }
      controller.close();
    },
  });
  return new Response(customReadable, {
    headers: {
      Connection: 'keep-alive',
      'Content-Encoding': 'none',
      'Cache-Control': 'no-cache, no-transform',
      'Content-Type': 'text/plain; charset=utf-8',
    },
  });
}
```

## Starter apps

Hackable, fully-featured, pre-built [starter apps](https://github.com/neondatabase/examples/tree/main/ai/llamaindex) to get you up and running with LlamaIndex and Postgres.

<DetailIconCards>

<a href="https://github.com/neondatabase/examples/tree/main/ai/llamaindex/chatbot-nextjs" description="A Next.js AI chatbot starter app built with OpenAI and LlamaIndex" icon="github">AI chatbot (OpenAI + LllamIndex)</a>

<a href="https://github.com/neondatabase/examples/tree/main/ai/llamaindex/rag-nextjs" description="A Next.js RAG chatbot starter app built with OpenAI and LlamaIndex" icon="github">RAG chatbot (OpenAI + LlamaIndex)</a>

<a href="https://github.com/neondatabase/examples/tree/main/ai/llamaindex/semantic-search-nextjs" description="A Next.js Semantic Search chatbot starter app built with OpenAI and LlamaIndex" icon="github">Semantic search chatbot (OpenAI + LlamaIndex)</a>

<a href="https://github.com/neondatabase/examples/tree/main/ai/llamaindex/reverse-image-search-nextjs" description="A Next.js Reverse Image Search Engine starter app built with OpenAI and LlamaIndex" icon="github">Reverse image search (OpenAI + LlamaIndex)</a>

<a href="https://github.com/neondatabase/examples/tree/main/ai/llamaindex/chat-with-pdf-nextjs" description="A Next.js Chat with PDF chatbot starter app built with OpenAI and LlamaIndex" icon="github">Chat with PDF (OpenAI + LlamaIndex)</a>

</DetailIconCards>


path: docs/ai/neon-mcp-server.md
content: ---
title: Neon MCP Server overview
subtitle: Learn about managing your Neon projects using natural language with Neon MCP
  Server
summary: >-
  Covers the setup and management of Neon Postgres databases using the Neon MCP
  Server, enabling users to execute commands and make schema changes through
  natural language without coding.
enableTableOfContents: true
updatedOn: '2026-02-06T22:07:32.733Z'
---

The **Neon MCP Server** is an open-source tool that lets you interact with your Neon Postgres databases in **natural language**:

- Manage projects, branches, and databases with conversational commands
- Run SQL queries and make schema changes without writing code
- Use branch-based migrations for safer schema modifications

## Quick setup

The fastest way to set up Neon's MCP Server is with one command:

```bash
npx neonctl@latest init
```

This configures the Neon MCP Server for compatible MCP clients in your workspace (Cursor, VS Code, Claude Code, and others) using API key authentication. See the [neonctl init documentation](/docs/reference/cli-init).

**If you only want the MCP server and nothing else**, use:

```bash
npx add-mcp https://mcp.neon.tech/mcp
```

This command adds the required configuration to your editor's MCP config files; it does not open a browser by itself. Add `-g` for global (user-level) setup instead of project-level. Restart your editor (or enable the MCP server in your editor's settings). When you use the MCP connection, an OAuth window will open in your browser to authorize access to your Neon account. For more options (e.g., global vs project-level), see the [add-mcp repository](https://github.com/neondatabase/add-mcp).

**Other setup options:**

- **API key authentication (remote agents):** For remote agents or when OAuth isn't available:
  ```bash
  npx add-mcp https://mcp.neon.tech/mcp --header "Authorization: Bearer $NEON_API_KEY"
  ```
- **Manual configuration:** See [Connect MCP clients](/docs/ai/connect-mcp-clients-to-neon) for step-by-step instructions for any editor, including Windsurf, ChatGPT, Zed, and others.

After setup, restart your editor and ask your AI assistant to **"Get started with Neon"** to launch the interactive onboarding guide.

---

Imagine you want to create a new database. Instead of using the Neon Console or API, you could just type a request like, "Create a database named 'my-new-database'". Or, to see your projects, you might ask, "List all my Neon projects". The Neon MCP Server makes this possible.

It works by acting as a bridge between natural language requests and the [Neon API](https://api-docs.neon.tech/reference/getting-started-with-neon-api). Built upon the [Model Context Protocol (MCP)](https://modelcontextprotocol.org), it translates your requests into the necessary Neon API calls, allowing you to manage everything from creating projects and branches to running queries and performing database migrations.

<Admonition type="important" title="Neon MCP Server Security Considerations">
The Neon MCP Server grants powerful database management capabilities through natural language requests. **Always review and authorize actions requested by the LLM before execution.** Ensure that only authorized users and applications have access to the Neon MCP Server.
</Admonition>

## Other setup options

<Tabs labels={["Remote (OAuth)", "Remote (API Key)", "Local"]}>

<TabItem>

Connect to Neon's managed MCP server using OAuth. No API key configuration needed.

```bash
npx add-mcp https://mcp.neon.tech/mcp
```

Or add this to your MCP config file:

```json
{
  "mcpServers": {
    "neon": {
      "type": "http",
      "url": "https://mcp.neon.tech/mcp"
    }
  }
}
```

<Admonition type="tip" title="One-click install for Cursor">
<a href="cursor://anysphere.cursor-deeplink/mcp/install?name=Neon&config=eyJ1cmwiOiJodHRwczovL21jcC5uZW9uLnRlY2gvbWNwIn0%3D"><img src="https://cursor.com/deeplink/mcp-install-dark.svg" alt="Add Neon MCP server to Cursor" height="32" /></a>
</Admonition>

After saving, restart your MCP client. When the OAuth window opens in your browser, review the requested permissions and click **Authorize** to complete the connection.

</TabItem>

<TabItem>

Connect using API key authentication. Useful for remote agents where OAuth isn't available.

**Requires:** [Neon API key](/docs/manage/api-keys)

```bash
npx add-mcp https://mcp.neon.tech/mcp --header "Authorization: Bearer <NEON_API_KEY>"
```

#### MCP-only setup (OAuth):

If you only want the MCP server and prefer OAuth, run:

```bash
npx add-mcp https://mcp.neon.tech/mcp
```

The command adds the config to your editor; restart your editor (or enable the MCP server) for it to take effect. When you use the MCP connection, an OAuth window will open in your browser—follow the prompts to authorize. For the recommended quick setup (API key + agent skills), use `npx neonctl@latest init` instead.

<Admonition type="tip" title="Install in a single click for Cursor users">
Click the button below to install the Neon MCP server in Cursor. When prompted, click **Install** within Cursor.

```json
{
  "mcpServers": {
    "neon": {
      "type": "http",
      "url": "https://mcp.neon.tech/mcp",
      "headers": {
        "Authorization": "Bearer <$NEON_API_KEY>"
      }
    }
  }
}
```

</Admonition>

<Admonition type="note">
Use an organization API key to limit access to organization projects only.
</Admonition>

#### Manual setup:

1.  Go to your MCP Client's settings where you configure MCP Servers (this varies by client)
2.  Register a new MCP Server. When prompted for the configuration, name the server "Neon" and add the following configuration:

    ```json
    {
      "mcpServers": {
        "Neon": {
          "type": "http",
          "url": "https://mcp.neon.tech/mcp"
        }
      }
    }
    ```

    > MCP supports two remote server transports: the deprecated Server-Sent Events (SSE) and the newer, recommended Streamable HTTP. If your LLM client doesn't support Streamable HTTP yet, you can switch the endpoint from `https://mcp.neon.tech/mcp` to `https://mcp.neon.tech/sse` to use SSE instead.

</TabItem>

<TabItem>

Run the MCP server locally on your machine.

**Requires:** Node.js >= v18, [Neon API key](/docs/manage/api-keys)

```bash
npx add-mcp "npx -y @neondatabase/mcp-server-neon start <YOUR_NEON_API_KEY>" --name neon
```

Or add this to your MCP config file:

```json
{
  "mcpServers": {
    "neon": {
      "command": "npx",
      "args": ["-y", "@neondatabase/mcp-server-neon", "start", "<YOUR_NEON_API_KEY>"]
    }
  }
}
```

<Admonition type="note" title="Windows users">

Use `cmd` or `wsl` if you encounter issues:

<CodeTabs labels={["Windows", "Windows (WSL)"]}>

```json
{
  "mcpServers": {
    "neon": {
      "command": "cmd",
      "args": ["/c", "npx", "-y", "@neondatabase/mcp-server-neon", "start", "<YOUR_NEON_API_KEY>"]
    }
  }
}
```

```json
{
  "mcpServers": {
    "neon": {
      "command": "wsl",
      "args": ["npx", "-y", "@neondatabase/mcp-server-neon", "start", "<YOUR_NEON_API_KEY>"]
    }
  }
}
```

</CodeTabs>

</Admonition>

</TabItem>

</Tabs>

### Read-only mode

The Neon MCP Server supports read-only mode for safe operation. Enable it by adding the `x-read-only: true` header:

```json
{
  "mcpServers": {
    "neon": {
      "type": "http",
      "url": "https://mcp.neon.tech/mcp",
      "headers": {
        "x-read-only": "true"
      }
    }
  }
}
```

When enabled, the server restricts all operations to read-only tools and SQL queries automatically run in read-only transactions. This provides a safe method for querying and analyzing databases without risk of accidental modifications.

### Troubleshooting

If your client does not use JSON for configuration of MCP servers (such as older versions of Cursor), use this command when prompted:

```bash
npx -y @neondatabase/mcp-server-neon start <YOUR_NEON_API_KEY>
```

<Admonition type="note">
For clients that don't support Streamable HTTP, you can use the deprecated SSE endpoint: `https://mcp.neon.tech/sse`. SSE is not supported with API key authentication.
</Admonition>

<Admonition type="important" title="Security Considerations">
The Neon MCP Server grants powerful database management capabilities through natural language requests. **Always review and authorize actions requested by the LLM before execution.** The Neon MCP Server is intended for local development and IDE integrations only. For more information, see [MCP security guidance](#mcp-security-guidance).
</Admonition>

<MCPTools />

## Usage examples

After setup, interact with your Neon databases using natural language:

- `"Get started with Neon"` — Launch the interactive onboarding guide
- `"List my Neon projects"`
- `"Create a project named 'my-app'"`
- `"Show tables in database 'main'"`
- `"Search for 'production' across my Neon resources"`
- `"SELECT * FROM users LIMIT 10"`

<Video  
sources={[{src: "/videos/pages/doc/neon-mcp.mp4",type: "video/mp4",}]}
width={960}
height={1080}
/>

## MCP security guidance

The Neon MCP server provides powerful database tools. We recommend MCP for **development and testing only**, not production environments.

- Use MCP only for local development or IDE-based workflows
- Never connect MCP agents to production databases
- Avoid exposing production or PII data—use anonymized data only
- Always review and authorize LLM-requested actions before execution
- Restrict MCP access to trusted users and regularly audit access

## Resources

- [MCP Protocol](https://modelcontextprotocol.org)
- [Neon API Reference](https://api-docs.neon.tech/reference/getting-started-with-neon-api)
- [Neon API Keys](/docs/manage/api-keys#creating-api-keys)
- [Neon MCP server GitHub](https://github.com/neondatabase/mcp-server-neon)

<NeedHelp/>


path: docs/ai/semantic-kernel.md
content: ---
title: Semantic Kernel
subtitle: Quickly build AI RAG and Agentic workflows with Semantic Kernel and Neon
summary: >-
  Step-by-step guide for initializing a Postgres Vector Store with Semantic
  Kernel in Neon, utilizing the `pgvector` extension for AI-driven search and
  retrieval tasks.
enableTableOfContents: true
updatedOn: '2026-02-06T22:07:32.734Z'
---

[Semantic Kernel](https://learn.microsoft.com/en-us/semantic-kernel/overview/) is an open-source SDK developed by Microsoft that enables the integration of large language models (LLMs) with traditional programming constructs. It allows developers to build AI-powered applications by combining natural language processing, planning, and memory capabilities. Semantic Kernel supports orchestration of AI workflows, plugin-based extensibility, and vector-based memory storage for retrieval-augmented generation (RAG) use cases. It is commonly used to create intelligent agents, chatbots, and automation tools that leverage LLMs like OpenAI’s GPT models.

## Initialize Postgres Vector Store

Semantic Kernel supports using Neon as a vector store, using its the `pgvector` extension and existing [Postgres Vector Store connector](https://learn.microsoft.com/en-us/semantic-kernel/concepts/vector-store-connectors/out-of-the-box-connectors/postgres-connector?pivots=programming-language-csharp) to access and manage data in Neon. It establishes a Neon connection, enables vector support, and initializes a vector store for AI-driven search and retrieval tasks

Here's how you can initialize Postgres Vector Store with Semantic Kernel in .NET using `Microsoft.SemanticKernel.Connectors.Postgres` NuGet package:

```csharp
// File: Program.cs

using Microsoft.SemanticKernel.Connectors.Postgres;
using Npgsql;

class Program
{
    static void Main()
    {
        var connectionString = "Host=myhost;Username=myuser;[REDACTED_SECRET];Database=mydb";
        var dataSourceBuilder = new NpgsqlDataSourceBuilder(connectionString);
        dataSourceBuilder.UseVector();
        using var dataSource = dataSourceBuilder.Build();

        var vectorStore = new PostgresVectorStore(dataSource);
        Console.WriteLine("Vector store created successfully.");
    }
}

```

## Generate Embeddings with Azure OpenAI

You can generate text embeddings using Azure OpenAI in the same .NET application.

```csharp
// File: Program.cs

using Microsoft.SemanticKernel.Connectors.Postgres;
using Microsoft.SemanticKernel.Connectors.AzureOpenAI;
using Npgsql;
using System;
using System.Threading.Tasks;

class Program
{
    static async Task Main()
    {
        string connectionString = "Host=myhost;Username=myuser;[REDACTED_SECRET];Database=mydb";

        // Create and configure the vector store
        var dataSourceBuilder = new NpgsqlDataSourceBuilder(connectionString);
        dataSourceBuilder.UseVector();
        using var dataSource = dataSourceBuilder.Build();
        var vectorStore = new PostgresVectorStore(dataSource);
        Console.WriteLine("Vector store created successfully.");

        // Generate embeddings using Azure OpenAI
        var embeddingService = new AzureOpenAITextEmbeddingGenerationService(
            deploymentName: "your-deployment-name",
            endpoint: "https://api.openai.com",
            [REDACTED_SECRET]"
        );

        string text = "This is an example sentence for embedding.";
        var embedding = await embeddingService.GenerateEmbeddingsAsync(new[] { text });

        Console.WriteLine($"Generated Embedding: [{string.Join(", ", embedding[0].AsReadOnlySpan().Slice(0, 5))}...]");
    }
}
```

## Chat Completions with Azure OpenAI

Here is how you can run a chat completion query with Azure OpenAI and Semantic Kernel

```csharp
// File: Program.cs

using Microsoft.SemanticKernel;
using Microsoft.SemanticKernel.Connectors.Postgres;
using Microsoft.SemanticKernel.Connectors.AzureOpenAI;
using Npgsql;
using System;
using System.Threading.Tasks;

class Program
{
    static async Task Main()
    {
        string connectionString = "Host=myhost;Username=myuser;[REDACTED_SECRET];Database=mydb";

        // Step 1: Create and configure the vector store
        var dataSourceBuilder = new NpgsqlDataSourceBuilder(connectionString);
        dataSourceBuilder.UseVector();
        using var dataSource = dataSourceBuilder.Build();
        var vectorStore = new PostgresVectorStore(dataSource);
        Console.WriteLine("✅ Vector store created successfully.");

        // Step 2: Generate embeddings using Azure OpenAI
        var embeddingService = new AzureOpenAITextEmbeddingGenerationService(
            deploymentName: "your-deployment-name",
            endpoint: "https://api.openai.com",
            [REDACTED_SECRET]"
        );

        string text = "This is an example sentence for embedding.";
        var embedding = await embeddingService.GenerateEmbeddingsAsync(new[] { text });

        Console.WriteLine($"✅ Generated Embedding: [{string.Join(", ", embedding[0].AsReadOnlySpan().Slice(0, 5))}...]");

        // Step 3: Perform chat completion using Azure OpenAI
        var kernel = Kernel.CreateBuilder()
            .AddAzureOpenAIChatCompletion(
                deploymentName: "your-chat-deployment-name",
                endpoint: "https://api.openai.com",
                [REDACTED_SECRET]"
            ).Build();

        string userPrompt = "Explain Retrieval-Augmented Generation (RAG) in simple terms.";
        var response = await kernel.InvokePromptAsync(userPrompt);

        Console.WriteLine("✅ Chat Completion Response:");
        Console.WriteLine(response);
    }
}
```

## Examples

Explore examples and sample code for using SemanticKernel with Neon Serverless Postgres.

<DetailIconCards>

<a href="https://github.com/neondatabase-labs/neon-semantic-kernel-examples" description="A .NET RAG example app built with Azure OpenAI and Semantic Kernel" icon="github">RAG .NET console app (Azure OpenAI + Semantic Kernel)</a>

</DetailIconCards>


path: docs/auth/authentication-flow.md
content: ---
title: Authentication flow
subtitle: Understanding the complete sign-in and sign-up process
summary: >-
  Covers the authentication flow for sign-in and sign-up processes using Neon
  Auth, detailing the SDK integration, session creation, and database
  interactions.
enableTableOfContents: true
updatedOn: '2026-02-06T22:07:32.735Z'
---

<FeatureBetaProps feature_name="Neon Auth with Better Auth" />

This guide explains the authentication flow: how sign-in works from SDK call to session creation.

<Admonition type="note">
Anyone can sign up for your application by default. Support for restricted signups is coming soon. Until then, consider adding a verification step by enabling [email verification](/docs/auth/guides/email-verification) via verification link or verification code.
</Admonition>

## Architecture overview

Neon Auth is a managed REST API service built on Better Auth that connects directly to your Neon database. You use the SDK in your application and configure settings in the Console—no servers to manage.

```
Your App (SDK)
    ↓ HTTP requests
Neon Auth Service (REST API)
    ↓ connects to database
Your Neon Database (neon_auth schema)
```

All authentication data—users, sessions, OAuth configurations—lives in your database's `neon_auth` schema. You can query these tables directly with SQL for debugging, analytics, or custom logic.

## Complete sign-in flow

Here's what happens when a user signs in, from your code to the database:

<Steps>

## User signs in

Your application calls the SDK's sign-in method:

```typescript
const { data, error } = await client.auth.signIn.email({
  email: '[REDACTED_SECRET]',
  [REDACTED_SECRET]',
});
```

The SDK posts to `{NEON_AUTH_URL}/auth/sign-in/email`. The Auth service validates credentials against `neon_auth.account`, creates a session in `neon_auth.session`, and returns the session cookie with user data.

**Response you receive:**

```typescript
{
  data: {
    session: {
      access_token: "eyJhbGc...",  // JWT token
      expires_at: 1763848395,
      // ... other session fields
    },
    user: {
      id: "dc42fa70-09a7-4038-a3bb-f61dda854910",
      email: "[REDACTED_SECRET]",
      emailVerified: true,
      // ... other user fields
    }
  }
}
```

## Session cookie is set

The Auth service sets an HTTP-only cookie (`__Secure-neonauth.session_token`) in your browser. This cookie:

- Contains an opaque session token (not a JWT)
- Is automatically sent with every request to the Auth API
- Is secure (HTTPS only, HttpOnly, SameSite=None)
- Is managed entirely by the SDK—you never touch it

**Where to see it:** Open DevTools → Application → Cookies → look for `__Secure-neonauth.session_token`

## JWT token is retrieved

The SDK automatically retrieves a JWT token and stores it in `session.access_token`. You don't need to call `/auth/token` separately—the SDK handles this behind the scenes.

**What's in the JWT:**

```json
{
  "sub": [REDACTED_SECRET], // User ID
  "email": "[REDACTED_SECRET]",
  "role": "authenticated",
  "exp": 1763848395, // Expiration timestamp
  "iat": 1763847495 // Issued at timestamp
}
```

The `sub` claim contains the user ID from `neon_auth.user.id`. This is what Row Level Security policies use to identify the current user.

## JWT is used for database queries

When you query your database via Data API, the SDK automatically includes the JWT in the `Authorization` header:

```typescript
// JWT is automatically included in Authorization header
const { data } = await client.from('posts').select('*');
```

**What happens:**

1. SDK gets JWT from `session.access_token`
2. Adds `Authorization: Bearer <jwt-token>` header
3. Data API validates JWT signature using JWKS public keys
4. Data API extracts user ID from JWT and makes it available to RLS policies
5. Your query runs with the authenticated user context

</Steps>

## Sign-up flow

The sign-up flow creates a new user:

```typescript
const { data, error } = await client.auth.signUp.email({
  email: '[REDACTED_SECRET]',
  [REDACTED_SECRET]',
  name: 'New User',
});
```

The SDK posts to `{NEON_AUTH_URL}/auth/sign-up/email`. The Auth service creates a new row in `neon_auth.user`, stores hashed credentials in `neon_auth.account`, and returns user data. If email verification is required, it creates a verification token in `neon_auth.verification` and may delay session creation until verification.

<Admonition type="note">
By default, anyone can sign up for your application. To add an additional verification layer, enable email verification (see [Email Verification](/docs/auth/guides/email-verification)). Built-in signup restrictions are coming soon.
</Admonition>

## OAuth flow

OAuth authentication (Google, GitHub, Vercel, etc.):

```typescript
await client.auth.signIn.social({
  provider: 'google',
  callbackURL: 'http://localhost:3000/auth/callback',
});
```

The SDK redirects to the OAuth provider. After the user authenticates, the provider redirects back with an authorization code. The SDK exchanges the code for an access token, then the Auth service creates or updates the user in `neon_auth.user`, stores OAuth tokens in `neon_auth.account`, and creates a session.

## Database as source of truth

Neon Auth stores all data in your database's `neon_auth` schema:

- Changes are immediate (no sync delays)
- Query auth data directly with SQL
- Each branch has isolated auth data
- You own your data

```sql
SELECT id, email, "emailVerified", "createdAt"
FROM neon_auth.user
ORDER BY "createdAt" DESC;
```

## Data API integration

When you enable the [Data API](/docs/data-api/get-started), JWT tokens from Neon Auth are validated automatically. The user ID is available via the `auth.uid()` function, enabling Row-Level Security policies to grant data access based on the authenticated user.

**Example RLS policy:**

```sql
CREATE POLICY "Users can view own posts"
ON posts FOR SELECT TO authenticated
USING (user_id = auth.uid());
```

**Learn more about securing your data:**

- [Row-Level Security with Neon](/docs/guides/row-level-security)
- [Simplify RLS with Drizzle](/docs/guides/rls-drizzle)

## What's next

<DetailIconCards>

<a href="/docs/auth/branching-authentication" description="How auth works with database branches" icon="split-branch">Branching Authentication</a>

<a href="/docs/guides/row-level-security" description="Secure your data with RLS policies" icon="check">Row Level Security</a>

</DetailIconCards>

<NeedHelp/>


path: docs/auth/branching-authentication.md
content: ---
title: Branching authentication
subtitle: How authentication works with Neon database branches
summary: >-
  Covers the setup of Neon Auth's branching feature, enabling isolated
  authentication environments for testing changes to permissions and
  configurations without impacting production data.
enableTableOfContents: true
updatedOn: '2026-02-06T22:07:32.737Z'
---

<FeatureBetaProps feature_name="Neon Auth with Better Auth" />

Authentication is often one of the hardest parts of the application stack to test. In traditional architectures, identity data lives in a separate third-party service, while your business data lives in your database. This separation makes it difficult to create realistic staging environments or test changes to permissions without affecting production users.

One of Neon Auth's unique features is native support for [database branching](/docs/introduction/branching). Because authentication data (users, sessions, and configuration) lives directly in your database's `neon_auth` schema, it is cloned along with your business data when you create a branch.

This gives each branch its own isolated authentication environment, enabling safe testing of permission changes, new OAuth providers, or full application refactors.

<Admonition type="info">
Neon Auth branching is also supported via API. See the [Neon Auth API reference](https://api-docs.neon.tech/reference/getneonauth) for a full set of REST API endpoints.
</Admonition>

## How it works

When you create a [database branch](/docs/introduction/branching), you get an exact copy of all authentication data from the parent branch at that point in time:

```
Production (main)                Preview Branch (preview-pr-123)
├── Users                   →    ├── Users (copied at branch time)
├── Sessions                →    ├── Sessions (copied, but will expire)
├── Configuration           →    ├── Configuration (independent copy)
├── OAuth providers         →    ├── OAuth providers (same credentials)
├── JWKS keys               →    ├── JWKS keys (copied)
└── Organizations           →    └── Organizations (copied)
```

After branching, the environments operate independently:

1.  **Data Isolation:** Changes in one branch don't affect others. Creating a user in a preview branch does not create them in production.
2.  **Config Isolation:** You can modify auth settings (e.g., email templates, token settings) in the branch without affecting the parent.
3.  **Endpoint Isolation:** Each branch gets a unique Auth API URL. Tokens issued in one branch are not valid in another.

```
Production Branch              Preview Branch
├── New user: [REDACTED_SECRET]     ├── New user: [REDACTED_SECRET]
├── Alice's sessions           ├── Test user's sessions
├── Config: email with links   ├── Config: testing email codes
└── ep-abc123.neonauth...      └── ep-xyz789.neonauth...
    (production endpoint)          (preview endpoint)
```

<Admonition type="note">
Neon Auth works with your branch's **default** database (typically `neondb`) and read-write endpoint only. You cannot use Neon Auth with other databases in the same branch. This aligns with our recommended pattern of one database per branch.
</Admonition>

## Session management details

Sessions do not transfer between branches. If you sign in to your production app and then visit your staging environment:

1.  The session _record_ exists in the staging database (if it was created before the branch happened).
2.  However, your browser's _cookie_ is scoped to the production domain.
3.  Therefore, you will need to sign in again on the staging environment.

This isolation is intentional and prevents security issues like sessions accidentally working across environments or test actions affecting production users.

## Common Use Cases

This branch isolation enables several powerful workflows for developers, QA teams, and product managers.

### 1. Developer isolation

In a team environment, developers often step on each other's toes when sharing a single development database. With branching, each developer can have their own instance:

```bash filename="Terminal"
# Alice and Bob create their own branches
neon branches create --name dev-alice
neon branches create --name dev-bob
```

- **Alice** works on a "Delete Account" flow. She can delete users and test the full flow without worrying about affecting others.
- **Bob** works on the "User Dashboard". His user list remains intact, even though Alice is deleting users in her environment.

Because Neon Auth is part of the database, Alice and Bob don't need to set up separate auth providers or mock data. They can work in parallel without conflicts.

### 2. Testing auth configuration safely

Say you want to add Google OAuth to your production app, but you're not sure if your configuration will work. Instead of testing directly in production, create a branch:

```bash filename="Terminal"
# Create test branch from production
neon branches create --name test-google-oauth
```

```env filename=".env.local"
# Point your local app to the test branch's Auth URL
VITE_NEON_AUTH_URL=https://ep-test-google-oauth.neonauth.region.aws.neon.tech/neondb/auth
```

Now configure Google OAuth in the test branch's Console and verify the sign-in flow works locally. Your production app and users are completely unaffected. Once you confirm it works, apply the same OAuth settings to your production branch.

The same approach works for any auth changes: password reset flows, email verification settings, or testing with anonymized production data.

### 3. Preview environments for pull requests

When building full-stack applications, you often deploy "Preview Deployments" (using Vercel, Netlify, etc.) for every Pull Request. Without Auth Branching, these previews usually share a single "Staging" auth tenant. This leads to data conflicts where one developer deletes a user that another developer was testing with.

**The workflow:**

You can automate this using GitHub Actions. When a PR is opened:

1.  Create a Neon branch.
2.  Deploy your frontend/backend to a preview URL.
3.  Inject the **Branch Auth URL** into the preview deployment's environment variables.
4.  Set the Redirect URLs in the branch's Auth configuration to point to the preview URL using the [Neon API](https://api-docs.neon.tech/reference/addbranchneonauthtrusteddomain).

Because the branch contains a snapshot of production data, the preview environment is fully functional immediately. You can log in with real test accounts that exist in production, but any actions taken (changing passwords, updating profiles) happen in isolation.

<Admonition type="tip">
See the [GitHub Actions guide](/docs/guides/branching-github-actions) for instructions on how to automate branch creation for preview environments.
</Admonition>

### 4. Testing multi-tenant & RBAC hierarchies

For applications with complex Role-Based Access Control (RBAC) or multi-tenant architectures, testing permission changes can be risky. A misconfiguration could lock out users or expose sensitive data.

**The scenario:** You are refactoring your RLS policies to allow "Managers" to view "Department" data, but not modify it.

**The workflow:**

1.  Create a branch `refactor-rbac`.
2.  This branch contains your real production users and their existing role assignments.
3.  Modify your RLS policies in the branch.
4.  You can log in as a "Manager" user and verify they can only view the appropriate data.
5.  If the policy is incorrect and you accidentally expose data or lock a user out, **it only affects the branch**. Production users are never impacted.

### 5. Major refactors and "v2" betas

When rebuilding your application from scratch or launching a major "v2" update, you often need to validate the new system with real user data before the official switch-over. Traditionally, this required complex data dumps or asking users to re-register on a beta site.

With Neon Auth, you can spin up a complete parallel environment for your new version instantly.

**The workflow:**

1.  **Branch production:** Create a branch named `v2-beta` from your main production database. This clones your entire application state, including the `neon_auth` schema containing all user identities and hashed passwords.
2.  **Deploy v2:** Deploy your new application code (e.g., to `beta.myapp.com`) and point it to the `v2-beta` branch's Auth URL.
3.  **Seamless login:** Existing users can visit your new v2 site and **log in immediately using their existing credentials**. They do not need to sign up again or reset their passwords.

This allows you to test radical architectural changes such as renaming database columns, changing table structures, or modifying authentication flows in a live environment. Your v1 application remains completely unaffected, while your v2 beta feels like a production-ready extension of your platform.

<Admonition type="note" title="Data separation">
Remember that once branched, the environments are separate. If a user changes their password on the v2 site, it will not change on the v1 site, and vice versa. This makes this workflow ideal for "Public Betas" or staging environments prior to a final cutover.
</Admonition>

### 6. AI agents and ephemeral sandboxes

AI Agents, particularly those designed for coding or QA, require safe, isolated environments to generate code, run migrations, and validate features. Traditionally, giving an agent access to a full authentication stack was complex - you had to mock auth tokens or risk exposing production user pools.

With Neon, an agent can programmatically provision its own "sandbox." Because Neon Auth moves with the data, this branch instantly creates a working Authentication service isolated from production, complete with its own user tables, sessions, and configuration. **This ensures your entire application stack mimics production behavior without risking real user data.**

**The workflow:**

1.  **Provision:** The Agent uses the Neon API to create a new database branch. It instantly receives a dedicated Auth URL for that specific environment.
2.  **Interact:** The Agent uses tools like Playwright or Puppeteer to interact with the application, registering new users and performing real login flows against the branch's auth service.
3.  **Validate:** The Agent runs a test suite to verify that the code it generated works correctly with the database schema, RLS policies, and authentication rules.
4.  **Teardown:** Once the task is complete, the Agent deletes the branch, cleaning up all data and auth state.

This capability allows agents to spin up "full stack" environments (Database + Auth + Compute) in seconds, enabling autonomous testing loops that rigorously test user-facing security without manual setup.

<Admonition type="important">
An AI agent cannot log in as a real production user in a branch. Although user records are copied, valid session cookies are domain-scoped and remain with the user's browser; they are not sent to the branch URL. Unless the agent explicitly knows a user's password, it must either perform a sign-up flow or use existing test credentials to log in.

To streamline this, consider maintaining specific test users with known credentials in your production database; these records are automatically cloned to child branches during creation, allowing agents to log in immediately without needing to perform a sign-up step.
</Admonition>

## What's Next

<DetailIconCards>

<a href="/docs/introduction/branching" description="Learn about database branching fundamentals" icon="split-branch">Database Branching</a>

<a href="/docs/guides/branching-neon-cli" description="Create and manage branches with CLI" icon="cli">Branching with CLI</a>

<a href="/docs/guides/branching-github-actions" description="Automate branching in CI/CD" icon="split-branch">Branching with GitHub Actions</a>

<a href="/docs/guides/row-level-security" description="Secure data with RLS" icon="lock-landscape">Row-Level Security</a>

</DetailIconCards>

<NeedHelp/>


path: docs/auth/guides/configure-domains.md
content: ---
title: Configure trusted domains
subtitle: Add your application domains to enable secure authentication redirects
summary: >-
  Covers the setup of application domains in Neon Auth's allowlist to enable
  secure OAuth and email verification redirects, preventing unauthorized access
  and ensuring proper functionality in production environments.
enableTableOfContents: true
updatedOn: '2026-02-06T22:07:32.738Z'
---

<FeatureBetaProps feature_name="Neon Auth with Better Auth" />

Add your application domains to Neon Auth's allowlist to enable OAuth and email verification redirects in production.

## Why domains are required

Neon Auth only redirects to domains in your allowlist. This prevents phishing attacks and unauthorized redirects by ensuring users are only sent to your legitimate application URLs.

Without adding your production domain, OAuth sign-in and verification links will fail when users try to access your application.

## Add a domain

1. Go to **Console → Auth → Configuration → Domains**
2. Enter your domain with protocol: `https://myapp.com`
3. Click **Add domain**

Repeat for each domain where your app runs.

<Admonition type="note">
Include the protocol (`https://`) and omit trailing slashes. For example: `https://myapp.com` not `https://myapp.com/`
</Admonition>

## Localhost is pre-configured

Development domains are automatically allowed, so you don't need to add them:

- `http://localhost:3000`
- `http://localhost:5173`
- Any `localhost` port

## Production domains

Add all domains where users access your application:

- `https://myapp.com`
- `https://www.myapp.com` (if you support www subdomain)
- `https://app.myapp.com` (if using a subdomain)

<Admonition type="important">
Add each subdomain explicitly. Wildcards like `*.myapp.com` are not supported.
</Admonition>

## Common issues

**Redirect blocked after OAuth sign-in:**

- Verify the domain is in your allowlist
- Ensure you included `https://` (not `http://` for production)
- Check spelling matches exactly (including www vs non-www)

**Verification link doesn't redirect:**

- Verification links use the same domain allowlist
- Add the domain where users should land after clicking the verification link

## Next steps

- [Production checklist](/docs/auth/production-checklist) - Complete setup for launch

<NeedHelp/>


path: docs/auth/guides/email-verification.md
content: ---
title: Email verification
subtitle: Verify user email addresses during sign-up or account creation
summary: >-
  Covers the setup of email verification in Neon Auth, detailing methods for
  verifying user email addresses during sign-up, including verification codes
  and links, along with configuration steps for each method.
enableTableOfContents: true
updatedOn: '2026-02-06T22:07:32.739Z'
---

<FeatureBetaProps feature_name="Neon Auth with Better Auth" />

Email verification ensures users own the email addresses they register with. Neon Auth supports two verification methods:

- **Verification codes** (users enter a numeric code from their email) - works with shared or custom email providers
- **Verification links** (users click a link in their email) - requires a custom email provider

<Admonition type="note">
Verification links require a [custom email provider](/docs/auth/production-checklist#email-provider). If you're using the shared email provider, use verification codes instead.
</Admonition>

## Enable email verification

In your project's **Settings** → **Auth** page, enable **Sign-up with Email** and **Verify at Sign-up**. Choose your verification method.

![Email verification settings in Neon Console](/docs/auth/email-verification-settings.png)

## Verification links

Verification links require a custom email provider. See [Email provider configuration](/docs/auth/production-checklist#email-provider) to set this up.

When a user clicks the verification link in their email, the Neon Auth server handles verification and redirects them back to your application. Your app checks for the new session and shows the appropriate UI.

### 1. Check session on mount (#check-session-on-mount)

Add a session check when your component mounts to detect when a user returns from clicking the verification link:

```jsx filename="src/App.jsx" {9-14}
import { useEffect, useState } from 'react';
import { authClient } from './auth';

export default function App() {
  const [user, setUser] = useState(null);
  const [loading, setLoading] = useState(true);

  useEffect(() => {
    authClient.getSession().then(({ data }) => {
      if (data?.session) {
        setUser(data.session.user);
      }
      setLoading(false);
    });
  }, []);
}
```

### 2. Handle sign-up with verification (#handle-signup-with-verification)

After calling `signUp.email()`, check if verification is required and show a message:

```jsx {16-18} filename="src/App.jsx"
const handleSignUp = async (e) => {
  e.preventDefault();
  setMessage('');

  try {
    const { data, error } = await authClient.signUp.email({
      email,
      password,
      name: name || email.split('@')[0] || 'User',
    });

    if (error) throw error;

    // Check if email verification is required
    if (data?.user && !data.user.emailVerified) {
      setMessage('Check your email for a verification link!');
    } else {
      setMessage('Account created! Please sign in.');
    }
  } catch (error) {
    setMessage(error?.message || 'An error occurred');
  }
};
```

### 3. Check verification status (#check-verification-status)

Access the `emailVerified` field from the user object:

```jsx {3} filename="src/App.jsx"
const { data } = await authClient.getSession();

if (data?.session?.user && !data.session.user.emailVerified) {
  // Show verification prompt or restrict features
  console.log('Please verify your email to continue');
}
```

## Verification codes

If you prefer verification codes, users receive a numeric code via email and enter it in your application. Your app switches between the auth form and a verification form.

### 1. Add verification state (#add-verification-state)

Add state to track which form to show:

```jsx filename="src/App.jsx"
const [step, setStep] = useState('auth'); // 'auth' or 'verify'
const [code, setCode] = useState('');
```

### 2. Handle code verification (#handle-code-verification)

Create a handler for code verification:

```jsx {6-9} filename="src/App.jsx"
const handleVerify = async (e) => {
  e.preventDefault();
  setMessage('');

  try {
    const { data, error } = await authClient.emailOtp.verifyEmail({
      email,
      otp: code,
    });

    if (error) throw error;

    // Check if auto-sign-in is enabled (default behavior)
    if (data?.session) {
      setUser(data.session.user);
      setStep('auth');
    } else {
      setMessage('Email verified! You can now sign in.');
      setStep('auth');
      setIsSignUp(false);
      setCode('');
    }
  } catch (error) {
    setMessage(error?.message || 'An error occurred');
  }
};
```

### 3. Show verification form (#show-verification-form)

When `step` is `'verify'`, show the verification form:

```jsx filename="src/App.jsx"
if (step === 'verify') {
  return (
    <div>
      <h1>Verify Your Email</h1>
      <p>Enter the code sent to {email}</p>
      <form onSubmit={handleVerify}>
        <input
          type="text"
          placeholder="Verification code"
          value={code}
          onChange={(e) => setCode(e.target.value)}
          required
        />
        <button type="submit">Verify</button>
      </form>
      {message && <p>{message}</p>}
    </div>
  );
}
```

### 4. Switch to verification after sign-up (#switch-to-verification)

After calling `signUp.email()`, switch to the verification step:

```jsx {3} filename="src/App.jsx"
if (data?.user && !data.user.emailVerified) {
  setMessage('Check your email for a verification code');
  setStep('verify'); // Switch to verification form
}
```

<details>
<summary>Complete example: App.jsx with verification codes</summary>

Here's a complete, minimal `App.jsx` file that includes sign-up, sign-in, and verification code functionality:

```jsx filename="src/App.jsx"
import { useState, useEffect } from 'react';
import { authClient } from './auth';
import './App.css';

export default function App() {
  const [session, setSession] = useState(null);
  const [user, setUser] = useState(null);
  const [email, setEmail] = useState('');
  const [password, setPassword] = useState('');
  const [loading, setLoading] = useState(true);
  const [message, setMessage] = useState('');
  // [!code ++]
  const [step, setStep] = useState('auth'); // 'auth' or 'verify' // [!code ++]
  const [code, setCode] = useState(''); // [!code ++]
  const [isSignUp, setIsSignUp] = useState(true); // [!code ++]

  useEffect(() => {
    authClient.getSession().then((result) => {
      if (result.data?.session && result.data?.user) {
        setSession(result.data.session);
        setUser(result.data.user);
      }
      setLoading(false);
    });
  }, []);

  const handleSignUp = async (e) => {
    e.preventDefault();
    setMessage('');
    const { data, error } = await authClient.signUp.email({
      email,
      password,
      name: email.split('@')[0] || 'User',
    });
    if (error) {
      setMessage(error.message);
      return;
    }
    // [!code ++]
    if (data?.user && !data.user.emailVerified) {
      // [!code ++]
      setMessage('Check your email for a verification code'); // [!code ++]
      setStep('verify'); // Switch to verification form // [!code ++]
    } else {
      // [!code ++]
      const sessionResult = await authClient.getSession(); // [!code ++]
      if (sessionResult.data?.session && sessionResult.data?.user) {
        // [!code ++]
        setSession(sessionResult.data.session); // [!code ++]
        setUser(sessionResult.data.user); // [!code ++]
      } // [!code ++]
    } // [!code ++]
  };

  const handleSignIn = async (e) => {
    e.preventDefault();
    setMessage('');
    const { data, error } = await authClient.signIn.email({ email, password });
    if (error) {
      setMessage(error.message);
      return;
    }
    if (data?.session && data?.user) {
      setSession(data.session);
      setUser(data.user);
    }
  };

  // [!code ++]
  const handleVerify = async (e) => {
    // [!code ++]
    e.preventDefault(); // [!code ++]
    setMessage(''); // [!code ++]
    // [!code ++]
    try {
      // [!code ++]
      const { data, error } = await authClient.emailOtp.verifyEmail({
        // [!code ++]
        email, // [!code ++]
        otp: code, // [!code ++]
      }); // [!code ++]
      // [!code ++]
      if (error) throw error; // [!code ++]
      // [!code ++]
      if (data?.session) {
        // [!code ++]
        setSession(data.session); // [!code ++]
        setUser(data.session.user); // [!code ++]
        setStep('auth'); // [!code ++]
      } else {
        // [!code ++]
        setMessage('Email verified! You can now sign in.'); // [!code ++]
        setStep('auth'); // [!code ++]
        setIsSignUp(false); // [!code ++]
        setCode(''); // [!code ++]
      } // [!code ++]
    } catch (error) {
      // [!code ++]
      setMessage(error?.message || 'An error occurred'); // [!code ++]
    } // [!code ++]
  }; // [!code ++]

  const handleSignOut = async () => {
    await authClient.signOut();
    setSession(null);
    setUser(null);
  };

  if (loading) return <div>Loading...</div>;

  if (session && user) {
    return (
      <div>
        <h1>Logged in as {user.email}</h1>
        <button onClick={handleSignOut}>Sign Out</button>
      </div>
    );
  }

  // [!code ++]
  if (step === 'verify') {
    // [!code ++]
    return (
      // [!code ++]
      <div>
        {' '}
        // [!code ++]
        <h1>Verify Your Email</h1> // [!code ++]
        <p>Enter the code sent to {email}</p> // [!code ++]
        <form onSubmit={handleVerify}>
          {' '}
          // [!code ++]
          <input // [!code ++]
            type="text" // [!code ++]
            placeholder="Verification code" // [!code ++]
            value={code} // [!code ++]
            onChange={(e) => setCode(e.target.value)} // [!code ++]
            required // [!code ++]
          />{' '}
          // [!code ++]
          <button type="submit">Verify</button> // [!code ++]
        </form>{' '}
        // [!code ++]
        {message && <p>{message}</p>} // [!code ++]
      </div> // [!code ++]
    ); // [!code ++]
  } // [!code ++]

  return (
    <div>
      <h1>{isSignUp ? 'Sign Up' : 'Sign In'}</h1>
      {message && <p>{message}</p>}
      <form onSubmit={isSignUp ? handleSignUp : handleSignIn}>
        <input
          type="email"
          placeholder="Email"
          value={email}
          onChange={(e) => setEmail(e.target.value)}
          required
        />
        <input
          type="password"
          placeholder="Password"
          value={password}
          onChange={(e) => setPassword(e.target.value)}
          required
        />
        <button type="submit">{isSignUp ? 'Sign Up' : 'Sign In'}</button>
      </form>
      <p>
        <button onClick={() => setIsSignUp(!isSignUp)}>
          {isSignUp ? 'Already have an account? Sign in' : "Don't have an account? Sign up"}
        </button>
      </p>
    </div>
  );
}
```

</details>

## Resending verification emails

Both verification links and verification codes expire after **15 minutes**. Allow users to request a new one:

```jsx {3-6} filename="src/App.jsx"
const handleResend = async () => {
  try {
    const { error } = await authClient.sendVerificationEmail({
      email,
      callbackURL: window.location.origin + '/',
    });

    if (error) throw error;
    setMessage('Verification email sent! Check your inbox.');
  } catch (error) {
    setMessage(error?.message || 'An error occurred');
  }
};
```

The server sends whichever type (verification link or verification code) you configured in the Console.

## Required vs optional verification

When email verification is **required** in your Console settings, users cannot sign in until they verify. When verification is **optional**, users can sign in immediately but their `emailVerified` field remains `false` until verified.


path: docs/auth/guides/password-reset.md
content: ---
title: Password reset
subtitle: Allow users to reset forgotten passwords
summary: >-
  Covers the setup of password reset functionality in Neon Auth, including
  enabling email authentication and using pre-built UI components for user
  password recovery.
enableTableOfContents: true
updatedOn: '2026-02-06T22:07:32.740Z'
---

<FeatureBetaProps feature_name="Neon Auth with Better Auth" />

Password reset allows users to securely reset forgotten passwords. Neon Auth supports password reset via verification links sent to the user's email address.

## Enable password reset

In your project's **Settings** → **Auth** page, ensure **Sign-up with Email** is enabled. Password reset is automatically available when email authentication is enabled.

## Using UI components

The easiest way to add password reset is using the pre-built UI components `<ForgotPasswordForm>` and `<ResetPasswordForm>`.

### 1. Enable forgot password in AuthView (#enable-forgot-password-authview)

If you're using `<AuthView>`, enable the forgot password flow:

```tsx filename="src/App.tsx"
import { NeonAuthUIProvider } from '@neondatabase/neon-js/auth/react';
import { AuthView } from '@neondatabase/neon-js/auth/react/ui';
import { authClient } from './auth';

export default function App() {
  return (
    <NeonAuthUIProvider authClient={authClient}>
      <AuthView pathname="sign-in" credentials={{ forgotPassword: true }} />
    </NeonAuthUIProvider>
  );
}
```

The `<AuthView>` component automatically includes a "Forgot password?" link when `forgotPassword` is enabled.

### 2. Use standalone form components (#use-standalone-forms)

For more control, use `<ForgotPasswordForm>` and `<ResetPasswordForm>` separately:

```tsx filename="src/App.tsx"
import { useState } from 'react';
import { ForgotPasswordForm, ResetPasswordForm } from '@neondatabase/neon-js/auth/react/ui';
import { authClient } from './auth';

export default function App() {
  const [step, setStep] = useState<'forgot' | 'reset'>('forgot');
  const [email, setEmail] = useState('');

  if (step === 'forgot') {
    return (
      <ForgotPasswordForm
        authClient={authClient}
        redirectTo={`${window.location.origin}/reset-password`}
        onSuccess={(data) => {
          setEmail(data.email);
          setStep('reset');
        }}
      />
    );
  }

  return (
    <ResetPasswordForm
      authClient={authClient}
      email={email}
      onSuccess={() => {
        setStep('forgot');
        // Redirect to sign-in or show success message
      }}
    />
  );
}
```

<Admonition type="note">
SDK methods for password reset (`resetPasswordForEmail`) are not fully supported yet. Use the UI components (`<ForgotPasswordForm>` and `<ResetPasswordForm>`) for password reset functionality.
</Admonition>

## Password reset flow

The complete password reset flow works as follows:

1. **User requests reset**: User enters their email and clicks "Send reset link"
2. **Email sent**: User receives a verification link with a reset token
3. **User clicks link**: User is redirected to your app's reset password page
4. **User enters new password**: User submits the new password
5. **Password reset**: Password is updated and user is signed in (if auto-sign-in is enabled)

## Reset link expiration

Password reset links expire after **15 minutes**. If a link expires, users need to request a new one.

## Next steps

- [Add email verification](/docs/auth/guides/email-verification) to ensure users own their email addresses
- [Learn how to branch your auth](/docs/auth/branching-authentication) to use database branches with isolated auth environments


path: docs/auth/guides/plugins.md
content: ---
title: Plugins
subtitle: Supported Better Auth plugins in Neon Auth
summary: >-
  Covers the supported Better Auth plugins in Neon Auth, detailing their status
  and management through the Neon SDK without direct installation or
  configuration by users.
enableTableOfContents: true
updatedOn: '2026-02-06T22:07:32.743Z'
---

<FeatureBetaProps feature_name="Neon Auth with Better Auth" />

Neon Auth is built on [Better Auth](https://www.better-auth.com/), which supports a variety of plugins to extend authentication functionality.

<Admonition type="info" title="Plugins are managed by Neon Auth">
Neon Auth is a **managed** Better Auth service. You **don’t install or configure Better Auth plugins directly** - instead, Neon Auth exposes a supported subset of plugins through the Neon SDK.

More granular controls like enabling/disabling specific plugins and customizing plugin behavior are on the roadmap.
</Admonition>

The following Better Auth plugins are currently supported in Neon Auth:

## Supported plugins

| Plugin                                                 | Status                                                       |
| ------------------------------------------------------ | ------------------------------------------------------------ |
| [Admin](/docs/auth/guides/plugins/admin)               | ✅ Supported                                                 |
| [Email OTP](/docs/auth/guides/plugins/email-otp)       | ✅ Supported                                                 |
| [JWT](/docs/auth/guides/plugins/jwt)                   | ✅ Supported                                                 |
| [Organization](/docs/auth/guides/plugins/organization) | ⚠️ Partial (invitation emails, JWT token claims in progress) |
| [Open API](/docs/auth/guides/plugins/openapi)          | ✅ Supported                                                 |

For the latest status (including what’s coming next), see the [Neon Auth roadmap](/docs/auth/roadmap).

<NeedHelp/>


path: docs/auth/guides/plugins/admin.md
content: ---
title: Admin
subtitle: 'Manage users, roles, bans, sessions, and impersonation'
summary: >-
  Covers the management of users, roles, bans, sessions, and impersonation
  through the Admin plugin APIs in Neon, enabling the creation and updating of
  user accounts and their authentication states.
enableTableOfContents: true
updatedOn: '2026-02-06T22:07:32.744Z'
---

<FeatureBetaProps feature_name="Neon Auth with Better Auth" />

Neon Auth is built on [Better Auth](https://www.better-auth.com/) and provides support for Admin plugin APIs through the Neon SDK. You do not need to manually install or configure the Better Auth Admin plugin.

The Admin plugin provides APIs to manage your users and their authentication state. It’s commonly used to build internal tooling (admin dashboards, support tools) that can:

- Create and update users
- Assign roles
- Ban and unban users
- List and revoke sessions
- Impersonate a user for support/debugging

## Prerequisites

- A Neon project with **Auth enabled**
- An existing user with an **admin** role to call Admin APIs.

  You can assign the **admin** role to a user through the Neon Console. Navigate to **Auth** → **Users**, open the three‑dot menu next to the user, and select **Make admin**.

  ![Assign admin role in Neon Console](/docs/auth/make-admin.png)

## Use Admin with SDK methods

You can call Admin plugin methods using the Neon SDK auth client.

> If you haven’t set up Neon Auth yet, follow our [Quick start guides](/docs/auth/overview#quick-start-guides) to get started and create an `authClient`.

### Create a user

Use the Admin APIs to create users on behalf of others (for example, back-office onboarding).

#### Parameters

<details>
<summary>View parameters</summary>

| Parameter         | Type                                   | Required | Notes                                                                      |
| ----------------- | -------------------------------------- | :------: | -------------------------------------------------------------------------- |
| <tt>email</tt>    | string                                 |    ✓     | Email address for the new user                                             |
| <tt>password</tt> | string                                 |    ✓     | Password for the new user                                                  |
| <tt>name</tt>     | string                                 |    ✓     | Display name                                                               |
| <tt>role</tt>     | string \| string[] \| undefined        |          | Optional role(s) for the user (for example: <tt>user</tt>, <tt>admin</tt>) |
| <tt>data</tt>     | Record&lt;string, any&gt; \| undefined |          | Optional custom fields                                                     |

</details>

```ts shouldWrap
const { data, error } = await authClient.admin.createUser({
  email: '[REDACTED_SECRET]',
  [REDACTED_SECRET]',
  name: 'User Name',
  role: 'user',
  data: { customUserField: 'value' },
});
```

### List users

List users with optional search, filtering, sorting, and pagination.

#### Parameters

<details>
<summary>View parameters</summary>

| Parameter               | Type                                                                                                              | Required | Notes                                |
| ----------------------- | ----------------------------------------------------------------------------------------------------------------- | :------: | ------------------------------------ |
| <tt>searchValue</tt>    | string \| undefined                                                                                               |          | Value to search for                  |
| <tt>searchField</tt>    | <tt>'email'</tt> \| <tt>'name'</tt> \| undefined                                                                  |          | Field to search in                   |
| <tt>searchOperator</tt> | <tt>'contains'</tt> \| <tt>'starts_with'</tt> \| <tt>'ends_with'</tt> \| undefined                                |          | Search operator                      |
| <tt>limit</tt>          | number \| string \| undefined                                                                                     |          | Max users to return (page size)      |
| <tt>offset</tt>         | number \| string \| undefined                                                                                     |          | Number of users to skip (pagination) |
| <tt>sortBy</tt>         | string \| undefined                                                                                               |          | Field to sort by                     |
| <tt>sortDirection</tt>  | <tt>'asc'</tt> \| <tt>'desc'</tt> \| undefined                                                                    |          | Sort direction                       |
| <tt>filterField</tt>    | string \| undefined                                                                                               |          | Field to filter by                   |
| <tt>filterValue</tt>    | string \| number \| boolean \| undefined                                                                          |          | Filter value                         |
| <tt>filterOperator</tt> | <tt>'eq'</tt> \| <tt>'ne'</tt> \| <tt>'lt'</tt> \| <tt>'lte'</tt> \| <tt>'gt'</tt> \| <tt>'gte'</tt> \| undefined |          | Filter operator                      |

</details>

```ts shouldWrap
const { data, error } = await authClient.admin.listUsers({
  query: {
    // Following parameters are optional
    searchValue: 'text to search',
    searchField: 'email',
    searchOperator: 'contains',
    limit: 10,
    offset: 0,
    sortBy: 'name',
    sortDirection: 'asc',
  },
});
```

> Use `filterField`, `filterValue`, and `filterOperator` to further filter results (for example, by role etc)

The `data` object contains a list of users and pagination metadata:

```ts
{
  users: [/* array of user objects */],
  total: 100, // total number of users matching the query
  limit: 10,  // limit used in the query
  offset: 0   // offset used in the query
}
```

Use the `total`, `limit`, and `offset` values to implement pagination in your admin tooling.

### Set a user role

Assign roles to control who can call admin operations.

#### Parameters

<details>
<summary>View parameters</summary>

| Parameter       | Type               | Required | Notes                                          |
| --------------- | ------------------ | :------: | ---------------------------------------------- |
| <tt>userId</tt> | string             |    ✓     | The user ID to update                          |
| <tt>role</tt>   | string \| string[] |    ✓     | Role(s) to apply (for example, <tt>admin</tt>) |

</details>

```ts shouldWrap
const { error } = await authClient.admin.setRole({ userId: 'user-id', role: 'admin' });
```

### Set a user password

Set or reset a user’s password.

<details>
<summary>View parameters</summary>
| Parameter         | Type   | Required | Notes                 |
| ----------------- | ------ | :------: | --------------------- |
| <tt>userId</tt>   | string |    ✓     | The user ID to update |
| <tt>newPassword</tt> | string |    ✓     | The new password      |
</details>

```ts shouldWrap
const { error } = await authClient.admin.setUserPassword({
  userId: 'user-id',
  newPassword: 'new-secure-password',
});
```

### Update user details

Update user information such as email, name, and custom fields.

<details>
<summary>View parameters</summary>
| Parameter       | Type                                   | Required | Notes                              |
| --------------- | -------------------------------------- | :------: | ---------------------------------- |
| <tt>userId</tt> | string                                 |    ✓     | The user ID to update                |
| <tt>data</tt>   | Record&lt;string, any&gt; |    ✓     | Fields to update (email, name, custom fields) |
</details>

```ts shouldWrap
const { error } = await authClient.admin.updateUser({
  userId: 'user-id',
  data: { name: 'New Name' },
});
```

### Ban user

Banning prevents sign-in for a user. You can optionally provide a reason and expiration for the ban.

<details>
<summary>View parameters</summary>

| Parameter             | Type                | Required | Notes                                                                               |
| --------------------- | ------------------- | :------: | ----------------------------------------------------------------------------------- |
| <tt>userId</tt>       | string              |    ✓     | The user ID to ban                                                                  |
| <tt>banReason</tt>    | string \| undefined |          | Reason for the ban                                                                  |
| <tt>banExpiresIn</tt> | number \| undefined |          | Duration in seconds until the ban expires. If not provided, the ban does not expire |

</details>

```ts shouldWrap
const { error } = await authClient.admin.banUser({
  userId: 'user-id',
  banReason: 'Policy violation',
  // banExpiresIn: 60 * 60 * 24, // optional (seconds)
});
```

### Unban user

Unban a previously banned user.

<details>
<summary>View parameters</summary>

| Parameter       | Type   | Required | Notes                |
| --------------- | ------ | :------: | -------------------- |
| <tt>userId</tt> | string |    ✓     | The user ID to unban |

</details>

```ts shouldWrap
const { error } = await authClient.admin.unbanUser({ userId: 'user-id' });
```

### Manage sessions

Use session APIs to view active sessions and revoke them.

#### List sessions

<details>
<summary>View parameters</summary>

| Parameter       | Type   | Required | Notes                                       |
| --------------- | ------ | :------: | ------------------------------------------- |
| <tt>userId</tt> | string |    ✓     | The user ID whose sessions you want to list |

</details>

```ts shouldWrap
const { data, error } = await authClient.admin.listUserSessions({ userId: 'user-id' });
```

#### Revoke a session

<details>
<summary>View parameters</summary>

| Parameter             | Type   | Required | Notes                       |
| --------------------- | ------ | :------: | --------------------------- |
| <tt>sessionToken</tt> | string |    ✓     | The session token to revoke |

</details>

```ts shouldWrap
const { error } = await authClient.admin.revokeUserSession({ sessionToken: 'session-token' });
```

#### Revoke all sessions

<details>
<summary>View parameters</summary>

| Parameter       | Type   | Required | Notes                                         |
| --------------- | ------ | :------: | --------------------------------------------- |
| <tt>userId</tt> | string |    ✓     | The user ID whose sessions you want to revoke |

</details>

```ts shouldWrap
const { error } = await authClient.admin.revokeUserSessions({ userId: 'user-id' });
```

### Impersonate a user

Impersonation creates a session that behaves like the target user (useful for support and debugging).

<details>
<summary>View parameters</summary>

| Parameter       | Type   | Required | Notes                      |
| --------------- | ------ | :------: | -------------------------- |
| <tt>userId</tt> | string |    ✓     | The user ID to impersonate |

</details>

```ts shouldWrap
const { data, error } = await authClient.admin.impersonateUser({ userId: 'user-id' });
```

### Stop impersonation

Stop an active impersonation session.

<details>
<summary>View parameters</summary>

This method does not take any parameters.

</details>

```ts shouldWrap
const { error } = await authClient.admin.stopImpersonating();
```

## Limitations

- Admin operations require an authenticated session (HTTP-only cookies). This means your admin tooling must run on the same site that can send those cookies to the Neon Auth API.
- Impersonation sessions are intentionally time‑limited, lasting for the duration of the active browser session or up to 1 hour. This design helps minimize security risks associated with long‑lived impersonation.

<NeedHelp/>


path: docs/auth/guides/plugins/email-otp.md
content: ---
title: Email OTP
subtitle: Sign in and verify email addresses with one-time passwords
summary: >-
  Covers the setup of Email OTP functionality in Neon Auth, enabling users to
  sign in, reset passwords, and verify email addresses using one-time passwords
  sent via email, with automatic handling of OTP generation and delivery.
enableTableOfContents: true
updatedOn: '2026-02-06T22:07:32.745Z'
---

<FeatureBetaProps feature_name="Neon Auth with Better Auth" />

Neon Auth is built on [Better Auth](https://www.better-auth.com/) and provides full support for Email OTP plugin APIs through the Neon SDK. You do not need to manually install or configure the Better Auth Email OTP plugin.

Email OTP lets users receive a one-time password (OTP) by email and use it to:

- Sign in without a password
- Perform password resets
- Verify their email address (verification codes)

Neon Auth UI and Neon SDK are client-side SDKs, so you only invoke their methods. OTP generation and delivery are handled automatically - you do not have direct control over the codes sent to users.

## Prerequisites

- A Neon project with **Auth enabled**
- **Sign-up and Sign-in with Email** enabled in your project's **Settings** → **Auth**.

  <Admonition type="note" title="Email verification during sign-up">
  To use Email OTP for sign-up verification, enable **Verify at Sign-up** and select **Verification code** under **Verification method**.
  ![Email OTP verification code setting](/docs/auth/email-otp.png)
  </Admonition>

## Use Email OTP with UI components

If you're using Neon Auth UI components, enable Email OTP by passing the `emailOTP` prop to `NeonAuthUIProvider`. This enables OTP flows in the pre-built auth UI.

```tsx shouldWrap filename="app/layout.tsx"
import { authClient } from '@/lib/auth/client';
import { NeonAuthUIProvider } from '@neondatabase/neon-js/auth/react/ui';
import './globals.css';

export default function RootLayout({ children }: Readonly<{ children: React.ReactNode }>) {
  return (
    <html lang="en">
      <body className={'antialiased'}>
        <NeonAuthUIProvider
          authClient={authClient}
          emailOTP // [!code ++]
        >
          {children}
        </NeonAuthUIProvider>
      </body>
    </html>
  );
}
```

Users can now sign in with Email OTP by selecting the option on the sign-in screen and entering the one-time code sent to their email.

![Email OTP verification](/docs/auth/email-otp-verification.png)

> If you haven't set up Neon Auth UI components yet, see our [Quick start guides](/docs/auth/overview#quick-start-guides).

## Use Email OTP with SDK methods

You can also implement OTP flows directly using the [Neon SDK](/docs/reference/javascript-sdk).

### Send an OTP

To send an OTP, call `emailOtp.sendVerificationOtp()` and specify a `type`:

- `sign-in` - passwordless sign-in
- `email-verification` - verify an email address

```ts shouldWrap filename="src/send-otp.ts"
import { authClient } from './auth';

export async function sendSignInOtp(email: string) {
  const { error } = await authClient.emailOtp.sendVerificationOtp({ email, type: 'sign-in' });

  if (error) throw error;
}
```

> For more details, see the [Send verification OTP code](/docs/reference/javascript-sdk#auth-sendverificationotp) in Neon SDK.

### Sign in with OTP

After the user receives the code, sign them in using `signIn.emailOtp()`:

```ts shouldWrap filename="src/sign-in-with-otp.ts"
import { authClient } from './auth';

export async function signInWithOtp(email: string, otp: string) {
  const { data, error } = await authClient.signIn.emailOtp({ email, otp });

  if (error) throw error;
  return data;
}
```

> For more details, see the [Sign in with OTP code](/docs/reference/javascript-sdk#auth-signinwithemailotp) in Neon SDK.

### Verify email with OTP

If your project has email verification enabled with **verification codes**, Neon Auth sends an OTP during sign-up.

Once the user enters the code, verify the email address using `emailOtp.verifyEmail()`:

```ts shouldWrap filename="src/verify-email.ts"
import { authClient } from './auth';

export async function verifyEmail(email: string, otp: string) {
  const { data, error } = await authClient.emailOtp.verifyEmail({ email, otp });

  if (error) throw error;
  return data;
}
```

> For more details, see the [Verify email with OTP code](/docs/reference/javascript-sdk#auth-verifyemail) in Neon SDK.

Checkout our [Email verification guide](/docs/auth/guides/email-verification) for a complete walkthrough.

### Check an OTP (optional)

If you want to validate an OTP without completing the flow (for example, to check the code before enabling a sensitive UI), you can use `emailOtp.checkVerificationOtp()`:

```ts shouldWrap filename="src/otp.ts"
import { authClient } from './auth';

export async function isOtpValid(email: string, otp: string) {
  const { data, error } = await authClient.emailOtp.checkVerificationOtp({
    email,
    otp,
    type: 'sign-in',
  });

  if (error) throw error;
  return Boolean(data?.success);
}
```

> For more details, see the [Check verification OTP code](/docs/reference/javascript-sdk#auth-checkverificationotp) in Neon SDK.

## Reset Password with OTP

You can also use Email OTP to implement password reset flows. To do this use the `authClient.forgetPassword.emailOtp` method to send a password reset OTP to the user's email address.

```ts shouldWrap filename="src/send-reset-otp.ts"
import { authClient } from './auth';

export async function sendPasswordResetOtp(email: string) {
  const { error } = await authClient.forgetPassword.emailOtp({ email });
  if (error) throw error;
}
```

Once the user receives the OTP, verify it using `authClient.emailOtp.checkVerificationOtp()` with the `type` set to `forget-password`.

```ts shouldWrap filename="src/verify-reset-otp.ts"
import { authClient } from './auth';

export async function verifyPasswordResetOtp(email: string, otp: string) {
  const { data, error } = await authClient.emailOtp.checkVerificationOtp({
    email,
    otp,
    type: 'forget-password',
  });

  if (error) throw error;
  return Boolean(data?.success);
}
```

Finally, reset the user's password using `authClient.emailOtp.resetPassword()`:

```ts shouldWrap filename="src/reset-password.ts"
import { authClient } from './auth';

export async function resetPasswordUsingOtp(email: string, otp: string, newPassword: string) {
  const { data, error } = await authClient.emailOtp.resetPassword({
    email,
    otp,
    [REDACTED_SECRET],
  });
}
```

## Limitations

Email OTP codes are time-limited and rate-limited.

If users exceed the allowed verification attempts, the API returns an error code like `TOO_MANY_ATTEMPTS` and the user must request a new code.

## Email provider configuration

For production environments, we strongly recommend using a dedicated email provider. The default shared SMTP should be used only during development. Refer to the [Email provider configuration guide](/docs/auth/production-checklist#email-provider) for setup instructions.

<NeedHelp/>


path: docs/auth/guides/plugins/jwt.md
content: ---
title: JWT
subtitle: Authenticate using JSON Web Tokens (JWT) for external services
summary: >-
  Covers the setup of JWT authentication using the Neon SDK for scenarios
  requiring raw tokens, such as microservices and API requests from different
  domains, while emphasizing that it does not replace session management for
  standard web applications.
enableTableOfContents: true
updatedOn: '2026-02-06T22:07:32.746Z'
---

<FeatureBetaProps feature_name="Neon Auth with Better Auth" />

Neon Auth is built on [Better Auth](https://www.better-auth.com/) and provides support for JWT plugin APIs through the Neon SDK. You do not need to manually install or configure the Better Auth JWT plugin.

While Neon Auth primarily relies on **secure, HTTP‑only cookies** (sessions) for browser‑based authentication, certain scenarios require a raw token. In these cases, the JWT plugin is especially useful:

- **Microservices:** Sharing identity between backend services.
- **Separate frontend and backend domains:** Authenticating API requests from a domain different than your main application.
- **CLI tools:** Enabling authentication from the command‑line interface.

<Admonition type="warning" title="Sessions vs. JWTs">
This plugin is **not** a replacement for session management in web applications. For standard browser-based apps (Next.js, React, Vue, etc.), rely on the default session cookie mechanism provided by `authClient.signIn` and `authClient.getSession`.

Only use JWTs when you specifically need to authorize requests to services that cannot access the browser's cookie jar.
</Admonition>

## Prerequisites

- A Neon project with **Auth enabled**.

## Retrieve a Token

You can retrieve a JWT for the currently signed-in user using the Neon SDK.

### Using the SDK method

To fetch a raw token string, use the `authClient.token()` method. This is the recommended approach for client applications that need to attach a token to an API request header manually.

```ts shouldWrap filename="src/get-token.ts"
import { authClient } from './auth';

export async function getJwtToken() {
  const { data, error } = await authClient.token();

  if (error) throw error;

  // The token string (e.g., "eyJhbGciOiJFZ...")
  return data.token;
}
```

### Using the session header

When you call `authClient.getSession()`, Neon Auth automatically includes a JWT in the response headers. If you are using a custom fetcher or need to intercept the token immediately after a session check:

```ts
await authClient.getSession({
  fetchOptions: {
    onSuccess: (ctx) => {
      const jwt = ctx.response.headers.get('set-auth-jwt');
      console.log('JWT:', jwt);
    },
  },
});
```

### Example decoded JWT payload

A typical decoded JWT payload looks like this:

```json
{
  "iat": 1766320685,
  "name": "User Name",
  "email": "[REDACTED_SECRET]",
  "emailVerified": false,
  "image": null,
  "createdAt": "2025-12-20T11:04:41.437Z",
  "updatedAt": "2025-12-20T11:04:41.437Z",
  "role": "authenticated",
  "banned": false,
  "banReason": null,
  "banExpires": null,
  "id": "860dc360-609f-4b7d-9e70-ec93fe6414d3",
  "sub": "860dc360-609f-4b7d-9e70-ec93fe6414d3",
  "exp": 1766321585,
  "iss": "<YOUR_NEON_AUTH_URL_ORIGIN>",
  "aud": "<YOUR_NEON_AUTH_URL_ORIGIN>"
}
```

## Verify a token

To verify the authenticity of a JWT, you need to validate its signature using the public keys provided by JWKS (JSON Web Key Set).

Neon Auth exposes a public JWKS endpoint that contains the public keys necessary to verify the signature of your JWTs.

### The JWKS endpoint

Your Neon Auth JWKS endpoint is located at:

```
<YOUR_NEON_AUTH_URL>/.well-known/jwks.json
```

### Verification example

The following examples demonstrate how to verify a Neon Auth JWT in several programming languages. No matter which language you use, the process is the same: fetch the JWKS from the provided endpoint and use it to validate the token’s signature and claims. If your preferred language isn’t included here, you can apply these same principles in your own environment.

<Admonition type="info" title="Production Readiness">
The following examples are provided for reference only and are not guaranteed to be production‑ready. Be sure to implement proper caching, error handling, and security best practices as required for your application.
</Admonition>

<Tabs labels={["Node.js", "Python", "Go"]}>

<TabItem>

1. Install the library:

   ```bash
   npm install jose
   ```

2. Use the following example code as a reference to verify a JWT:

   ```ts shouldWrap
   import { jwtVerify, createRemoteJWKSet } from 'jose';

   const NEON_JWKS_URL = `${process.env.NEON_AUTH_BASE_URL}/.well-known/jwks.json`;
   const JWKS = createRemoteJWKSet(new URL(NEON_JWKS_URL));

   export async function validateNeonToken([REDACTED_SECRET]) {
       try {
           const { payload } = await jwtVerify(token, JWKS, {
               issuer: new URL(process.env.NEON_AUTH_BASE_URL!).origin
           });

           return payload;
       } catch (error) {
           console.error('Token validation failed:', error);
           return null;
       }
   }

   validateNeonToken(<YOUR_JWT_TOKEN>).then((payload) => {
       console.log('Token is valid. Payload:', payload);
   }).catch(() => {
       console.log('Token is invalid.');
   });
   ```

   > Replace `<YOUR_JWT_TOKEN>` with the actual JWT token you want to verify.

</TabItem>

<TabItem>

1. Install the library:

   ```bash
   pip install PyJWT requests cryptography
   ```

2. Use the following example code as a reference to verify a JWT:

   ```py
   import base64
   import os
   from urllib.parse import urlparse

   import jwt
   import requests
   from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PublicKey
   from jwt import PyJWTError

   NEON_AUTH_BASE_URL = os.environ.get("NEON_AUTH_BASE_URL", "")
   NEON_JWKS_URL = f"{NEON_AUTH_BASE_URL}/.well-known/jwks.json"
   parsed = urlparse(NEON_AUTH_BASE_URL)
   ORIGIN = f"{parsed.scheme}://{parsed.netloc}"

   def get_jwks():
       response = requests.get(NEON_JWKS_URL)
       response.raise_for_status()
       return response.json()

   def get_signing_key(token, jwks):
       unverified_header = jwt.get_unverified_header(token)
       kid = unverified_header["kid"]

       for jwk in jwks["keys"]:
           if jwk["kid"] == kid:
               x = jwk["x"]
               public_key_bytes = base64.urlsafe_b64decode(x + "==")
               return Ed25519PublicKey.from_public_bytes(public_key_bytes)

       raise ValueError("Matching JWK not found")

   def validate_neon_token(token: str):
       try:
           jwks = get_jwks()
           signing_key = get_signing_key(token, jwks)

           payload = jwt.decode(
               token, key=signing_key, algorithms=["EdDSA"], issuer=ORIGIN, audience=ORIGIN
           )

           return payload

       except PyJWTError as error:
           print("Token validation failed:", error)
           return None
       except Exception as error:
           print("Unexpected error:", error)
           return None


   payload = validate_neon_token("<YOUR_JWT_TOKEN>")

   if payload:
       print("Token is valid. Payload:", payload)
   else:
       print("Token is invalid.")
   ```

   > Replace `<YOUR_JWT_TOKEN>` with the actual JWT token you want to verify.

</TabItem>

<TabItem>

1. Install the library:

   ```bash
   go get github.com/golang-jwt/jwt/v5
   go get github.com/MicahParks/keyfunc/v3
   ```

2. Use the following example code as a reference to verify a JWT:

   ```go
   package main

   import (
       "fmt"
       "log"
       "net/url"
       "os"

       "github.com/MicahParks/keyfunc/v3"
       "github.com/golang-jwt/jwt/v5"
   )

   func ValidateNeonToken(tokenString string) (jwt.MapClaims, error) {
       baseURL := os.Getenv("NEON_AUTH_BASE_URL")
       if baseURL == "" {
           return nil, fmt.Errorf("NEON_AUTH_BASE_URL is not set")
       }

       jwksURL := fmt.Sprintf("%s/.well-known/jwks.json", baseURL)

       u, err := url.Parse(baseURL)
       if err != nil {
           return nil, fmt.Errorf("failed to parse base URL: %w", err)
       }
       expectedIssuer := fmt.Sprintf("%s://%s", u.Scheme, u.Host)

       jwks, err := keyfunc.NewDefault([]string{jwksURL})
       if err != nil {
           return nil, fmt.Errorf("failed to create JWKS from resource at %s: %w", jwksURL, err)
       }

       token, err := jwt.Parse(tokenString, func(token *jwt.Token) (interface{}, error) {
           return jwks.Keyfunc(token)
       },
           jwt.WithIssuer(expectedIssuer),
           jwt.WithValidMethods([]string{"EdDSA"}),
       )

       if err != nil {
           return nil, err
       }

       if claims, ok := token.Claims.(jwt.MapClaims); ok && token.Valid {
           return claims, nil
       }

       return nil, fmt.Errorf("invalid token claims")
   }

   func main() {
       tokenString := "<YOUR_JWT_TOKEN>"

       claims, err := ValidateNeonToken(tokenString)
       if err != nil {
           log.Printf("Token validation failed: %v\n", err)
           return
       }

       fmt.Printf("Token is valid. Payload: %+v\n", claims)
   }
   ```

   > Replace `<YOUR_JWT_TOKEN>` with the actual JWT token you want to verify.

</TabItem>

</Tabs>

## Limitations

Because Neon Auth is a managed service, certain server-side configurations available in the standalone Better Auth library are pre-configured by Neon and cannot be changed:

- **Signing algorithm:** Neon Auth uses **EdDSA (Ed25519)** by default for high security and performance. Ensure your verification libraries support this algorithm.
- **Expiration:** Tokens expire in **15 minutes** (access tokens). You should implement logic to refresh the token using `authClient.token()` when it expires.
- **Custom claims:** Currently, the JWT payload contains the default user information. Custom claims are not supported at this time.

## Troubleshooting

### Token rejection

If a token is rejected during verification, check the following:

1. Verify that you are using the correct JWKS endpoint for your Neon Auth instance. The issuer of the token must match the origin of your Neon Auth URL. (e.g., if your Neon Auth URL is `https://ep-xx.aws.neon.tech/neondb/auth`, the issuer should be `https://ep-xx.aws.neon.tech`).
2. Confirm that your verification library supports **EdDSA** (Ed25519).
3. Make sure the token has not expired.
4. Check that the `kid` in the JWT header matches one of the keys in the JWKS response. If not, fetch the latest keys from the JWKS endpoint.

<NeedHelp />


path: docs/auth/guides/plugins/openapi.md
content: ---
title: Open API
subtitle: Interactive API documentation and client generation
summary: >-
  Covers the setup of the OpenAPI plugin for Neon Auth, providing an interactive
  API reference UI and a JSON Schema endpoint for generating type-safe clients.
enableTableOfContents: true
updatedOn: '2026-02-06T22:07:32.747Z'
---

<FeatureBetaProps feature_name="Neon Auth with Better Auth" />

Neon Auth is built on [Better Auth](https://www.better-auth.com/) and comes with the Open API plugin enabled by default. You do not need to manually install or configure it.

The OpenAPI plugin provides two main features:

1. An interactive **API reference UI** (powered by [Scalar](https://scalar.com/)) to explore and test all available Neon Auth endpoints.
2. A **JSON Schema endpoint** that you can use to generate type-safe clients for your application.

## Prerequisites

- A Neon project with **Auth enabled**.

## Accessing the API reference

You can view the interactive documentation for your specific project by appending `/reference` to your Neon Auth URL.

**URL Format:**

```
<YOUR_NEON_AUTH_URL>/reference
```

**Example:**
`https://ep-xxx.aws.neon.tech/neondb/auth/reference`

This interface allows you to:

- Browse all available endpoints (grouped by Core, Session, User, Plugins, etc).
- View request and response schemas.
- **"Try it out"**: Make real API requests against your database directly from the browser.

![Neon Auth Open API Reference](/docs/auth/openapi-reference.png)

<Admonition type="note" title="Testing endpoints">
When using the "Try it out" feature, you are interacting with your live database. Be careful when testing endpoints that modify or delete data (like `admin.banUser` or `organization.delete`).
</Admonition>

## JSON schema

If you need the raw OpenAPI 3.x specification (for example, to import into Postman or Insomnia), it is available at the `/open-api/generate-schema` endpoint.

**URL format:**

```
<YOUR_NEON_AUTH_URL>/open-api/generate-schema
```

This endpoint returns a standard JSON object describing your authentication API.

## Generating API clients

One of the most powerful use cases for the OpenAPI plugin is generating type-safe API clients for languages that do not yet have a dedicated Neon Auth SDK, or for server-side integration where you prefer raw fetch calls.

### Using Scalar SDK generator

If you're using Next.js, you can access the OpenAPI reference page at `/api/auth/reference` in your application, once Neon Auth is set up according to the [Next.js guide](/docs/auth/quick-start/nextjs). Unlike the default Neon Auth reference page, this version can be fully customized to match your application's theme. It also provides additional options, such as generating SDK clients in multiple languages using Scalar's [built‑in tools](https://guides.scalar.com/scalar/scalar-sdks/getting-started).

## Limitations

Because Neon Auth is a managed service, the OpenAPI configuration is preset:

- **Path:** The reference UI is always served at `/reference`.
- **Theme:** The UI uses the default Scalar theme and cannot be customized.
- **Discovery:** The reference doc automatically reflects the plugins enabled in your Neon Auth instance.

<NeedHelp />


path: docs/auth/guides/setup-oauth.md
content: ---
title: Set up OAuth
subtitle: Add Google or GitHub sign-in to your application
summary: >-
  Step-by-step guide for setting up OAuth sign-in with Google, GitHub, or Vercel
  in your application using Neon Auth, including development and production
  configurations.
enableTableOfContents: true
updatedOn: '2026-02-06T22:07:32.749Z'
---

<FeatureBetaProps feature_name="Neon Auth with Better Auth" />

OAuth lets users sign in with their Google, GitHub, or Vercel account. Neon Auth handles the OAuth flow and creates a session after authorization.

## Development mode

Google OAuth is enabled by default with shared credentials for development and testing. You can start using Google sign-in immediately without any configuration.

<Admonition type="note">
GitHub and Vercel OAuth require custom credentials and is not available with shared credentials. See [Production setup](#production-setup) to configure your own OAuth apps.
</Admonition>

For production, configure your own OAuth app credentials for both providers. See [Production setup](#production-setup) below.

## Sign in with OAuth

Call `signIn.social()` with your provider (`"google"`, `"github"` or `"vercel"`). The SDK redirects the user to the provider's authorization page, then back to your `callbackURL`:

<CodeTabs labels={["Google","GitHub","Vercel"]}>

```jsx {6} filename="src/App.jsx"
import { authClient } from './auth';

const handleGoogleSignIn = async () => {
  try {
    await authClient.signIn.social({
      provider: "google",
      callbackURL: window.location.origin,
    });
  } catch (error) {
    console.error("Google sign-in error:", error);
  }
};
```

```jsx {6} filename="src/App.jsx"
import { authClient } from './auth';

const handleGitHubSignIn = async () => {
  try {
    await authClient.signIn.social({
      provider: "github",
      callbackURL: window.location.origin,
    });
  } catch (error) {
    console.error("GitHub sign-in error:", error);
  }
};
```

```jsx {6} filename="src/App.jsx"
import { authClient } from './auth';

const handleVercelSignIn = async () => {
  try {
    await authClient.signIn.social({
      provider: "vercel",
      callbackURL: window.location.origin,
    });
  } catch (error) {
    console.error("Vercel sign-in error:", error);
  }
};
```

</CodeTabs>

## Handle the callback

After the provider redirects back to your app, check for a session:

```jsx {4-9} filename="src/App.jsx"
import { authClient } from './auth';

useEffect(() => {
  authClient.getSession().then(({ data }) => {
    if (data?.session) {
      setUser(data.session.user);
    }
    setLoading(false);
  });
}, []);
```

## Custom redirect URLs

Specify different URLs for new users or errors:

```jsx {3-5} filename="src/App.jsx"
await authClient.signIn.social({
  provider: "google", // or "github", "vercel"
  callbackURL: "/dashboard",
  newUserCallbackURL: "/welcome",
  errorCallbackURL: "/error",
});
```

## Production setup

For production, configure your own OAuth app credentials. GitHub and Vercel OAuth require custom credentials, while Google OAuth works with shared credentials for development but should use custom credentials in production.

1. Create OAuth apps with your providers:
   - [Google OAuth setup](https://developers.google.com/identity/protocols/oauth2/web-server)
   - [GitHub OAuth setup](https://docs.github.com/en/apps/oauth-apps/building-oauth-apps/creating-an-oauth-app)
   - [Vercel OAuth setup](https://vercel.com/docs/sign-in-with-vercel/manage-from-dashboard#create-an-app)
2. In your project's **Settings** → **Auth** page, configure your Client ID and Client Secret for each provider

Your app will automatically use your configured credentials

<DetailIconCards>

<a href="/docs/auth/guides/email-verification" description="Add email verification" icon="check">Email Verification</a>

</DetailIconCards>

<NeedHelp/>


path: docs/auth/guides/user-management.md
content: ---
title: User management
subtitle: 'Update profiles, change passwords, and manage account settings'
summary: >-
  Covers the management of user profiles, including updating personal
  information, securely changing passwords, verifying email address changes, and
  deleting accounts within the Neon platform.
enableTableOfContents: true
updatedOn: '2026-02-06T22:07:32.752Z'
---

<FeatureBetaProps feature_name="Neon Auth with Better Auth" />

Manage user profiles and account settings after users sign in. This guide covers:

- Updating profile information (name, image, phone number)
- Changing passwords securely
- Changing email addresses with verification
- Deleting user accounts

## Update user profile

Update user profile fields like name, image, or phone number using `updateUser()`:

```jsx filename="src/App.jsx"
import { authClient } from './auth';

const handleUpdateProfile = async (e) => {
  e.preventDefault();
  setMessage('');

  try {
    const { data, error } = await authClient.updateUser({
      name: 'New Name',
    });

    if (error) throw error;

    // Refresh session to get updated user data
    const sessionResult = await authClient.getSession();
    if (sessionResult.data?.session) {
      setUser(sessionResult.data.session.user);
      setMessage('Profile updated successfully!');
    }
  } catch (error) {
    setMessage(error?.message || 'Update failed');
  }
};
```

### Available profile fields

You can update these fields with `updateUser()`:

- `name` (string) - User's display name

<Admonition type="note">
Email address changes are not currently supported. To reset a forgotten password, see [Password Reset](/docs/auth/guides/password-reset).
</Admonition>

## Change password

Change a user's password while they are logged in using `changePassword()`. This requires the current password for security:

```jsx filename="src/App.jsx"
import { authClient } from './auth';

const handleChangePassword = async (e) => {
  e.preventDefault();
  setMessage('');

  try {
    const { data, error } = await authClient.changePassword({
      newPassword: 'new-secure-password',
      currentPassword: 'current-password',
    });

    if (error) throw error;
    setMessage('Password changed successfully!');
  } catch (error) {
    setMessage(error?.message || 'Password change failed');
  }
};
```

### Revoke other sessions

Optionally sign out from all other devices when changing the password:

```jsx filename="src/App.jsx"
const { data, error } = await authClient.changePassword({
  newPassword: 'new-secure-password',
  currentPassword: 'current-password',
  revokeOtherSessions: true, // Signs out all other devices
});
```

<Admonition type="note">
If a user forgot their password, use the password reset flow (`requestPasswordReset()` and `resetPassword()`) instead. See [Password Reset](/docs/auth/guides/password-reset).
</Admonition>

## Refresh user data

After updating profile information, refresh the session to get the latest user data:

```jsx filename="src/App.jsx"
import { authClient } from './auth';

const refreshUser = async () => {
  const { data } = await authClient.getSession();
  if (data?.session) {
    setUser(data.session.user);
  }
};
```

Call `refreshUser()` after successful `updateUser()` calls to ensure your UI displays the latest information.

<DetailIconCards>

<a href="/docs/auth/guides/password-reset" description="Reset forgotten passwords" icon="lock-landscape">Password Reset</a>

<a href="/docs/auth/guides/email-verification" description="Verify email addresses" icon="check">Email Verification</a>

<a href="/docs/auth/authentication-flow" description="Understand the auth flow" icon="unlock">Authentication Flow</a>

</DetailIconCards>

<NeedHelp/>


path: docs/auth/legacy/overview.md
content: ---
title: Legacy Neon Auth with Stack Auth
subtitle: For existing users only (not available for new projects)
summary: >-
  Covers the setup and functionality of the legacy Neon Auth system using Stack
  Auth for existing users, detailing user management and data synchronization
  within a Neon Postgres database.
enableTableOfContents: true
tag: archived
noindex: true
updatedOn: '2026-02-06T22:07:32.754Z'
---

<Admonition type="warning" title="You are viewing legacy documentation">
**This is the documentation for the previous Neon Auth implementation built with Stack Auth.** It is no longer available for new projects but remains supported for existing users.

**For the new Neon Auth built with Better Auth**, see [Neon Auth documentation](/docs/auth/overview). Ready to upgrade? See our [migration guide](/docs/auth/migrate/from-legacy-auth).
</Admonition>

## What is legacy Neon Auth?

Neon Auth brings authentication and user management natively to your Neon Postgres database.

### Why use Neon Auth?

Neon Auth helps you move faster by handling the auth stack for you:

- **Add auth to your app in minutes** — SDKs for Next.js and React
- **No more custom sync code** — user profiles are always up-to-date in your database, ready for SQL joins and analytics.
- **Built-in support for teams, roles, and permissions**.

## How it works

When you set up Neon Auth, we create a `neon_auth` schema in your database. As users authenticate and manage their profiles in Neon Auth, you'll see them appear in your list of users on the **Auth** page.

![Users in Neon Auth](/docs/guides/identity_users.png)

**User data is immediately available in your database**

User data is available in the `neon_auth.users_sync` table shortly after the Neon Auth processes the updates. Here's an example query to inspect the synchronized data:

```sql
SELECT * FROM neon_auth.users_sync;
```

| id          | name          | email             | created_at          | updated_at          | deleted_at | raw_json                         |
| ----------- | ------------- | ----------------- | ------------------- | ------------------- | ---------- | -------------------------------- |
| d37b6a30... | Jordan Rivera | [REDACTED_SECRET] | 2025-05-09 16:15:00 | null                | null       | `{\"id\": \"d37b6a30...\", ...}` |
| 51e491df... | Sam Patel     | [REDACTED_SECRET]   | 2025-02-27 18:36:00 | 2025-02-27 18:36:00 | null       | `{\"id\": \"51e491df...\", ...}` |

The following columns are included in the `neon_auth.users_sync` table:

- `raw_json`: Complete user profile as JSON
- `id`: The unique ID of the user
- `name`: The user's display name
- `email`: The user's primary email
- `created_at`: When the user signed up
- `deleted_at`: When the user was deleted, if applicable (nullable)
- `updated_at`: When the user was last updated, if applicable (nullable)

Updates to user profiles in Neon Auth are automatically reflected in your database.

<Admonition type="note">
Do not try to change the `neon_auth.users_sync` table name. It's needed for the synchronization process to work correctly.
</Admonition>

For detailed integration patterns, foreign key examples, and best practices, see [Database Integration](/docs/auth/legacy/database-integration).

## Environment variables and SDK keys

To use Stack Auth with your Neon project, you need these environment variables:

```env
NEXT_PUBLIC_STACK_PROJECT_ID=your-project-id
NEXT_PUBLIC_STACK_PUBLISHABLE_CLIENT_KEY=your-client-key
STACK_SECRET_SERVER_KEY=your-server-secret
```

### Getting your keys

You can get these keys from the Neon Console **Auth** page, or by using the Neon API.

Generates SDK keys for your auth provider integration. These keys are used to set up your frontend and backend SDKs.

Required parameters:

- `project_id`: Your Neon project ID
- `auth_provider`: The authentication provider (currently `"stack"`)

```bash shouldWrap
curl --request POST \
     --url 'https://console.neon.tech/api/v2/projects/auth/keys' \
     --header 'authorization: Bearer $NEON_API_KEY' \
     --header 'content-type: application/json' \
     --data '{
       "project_id": "project-id",
       "auth_provider": "stack"
     }' | jq
```

Example response:

```json shouldWrap
{
  "auth_provider": "stack",
  "auth_provider_project_id": "project-id-123",
  "pub_client_key": "pck_example...",
  "secret_server_key": "ssk_example...",
  "jwks_url": "https://api.stack-auth.com/api/v1/projects/project-id-123/.well-known/jwks.json",
  "schema_name": "neon_auth",
  "table_name": "users_sync"
}
```

[Try in API Reference ↗](https://api-docs.neon.tech/reference/createneonauthprovidersdkkeys)

## Claiming your Stack Auth project

Neon Auth is powered by Stack Auth under the hood. By default, Neon manages your authentication for you, so you do not typically need to interact with Stack Auth directly. However, there are cases where you may want to take direct control of your authentication project in the Stack Auth dashboard.

### Why claim a project?

Most Neon Auth features can be built using the SDKs, without claiming your project.

Right now, you need to claim your project if you want to:

- Add or manage OAuth providers (register client IDs/secrets, set callback URLs)
- Enable production mode and enforce production security settings
- Manage multiple projects or separate production and development environments directly in Stack Auth

<Steps>

### Claim via the Neon console

1. Go to your project's **Auth** page, **Configuration** tab in the Neon Console.
2. Click **Claim project** in the Claim project section.
3. Follow the prompts to select the Stack Auth account that should receive ownership.

After claiming, you'll have direct access to manage your project in the Stack Auth dashboard, while maintaining the integration with your Neon database.

You can also find your current project ID here, as well as the JWKS URL you need to set up [RLS in your Neon Auth project](/docs/auth/legacy/database-integration#row-level-security-rls).

### Claim via the API

You can also claim your project programmatically:

```bash
curl --request POST \
     --url 'https://console.neon.tech/api/v2/projects/auth/transfer_ownership' \
     --header 'authorization: Bearer $NEON_API_KEY' \
     --data '{
       "project_id": "project-id",
       "auth_provider": "stack"
     }'
```

Open the returned URL in your browser to complete the claim process.
See [Neon Auth API Reference](https://api-docs.neon.tech/reference/transferneonauthownership) for more details.

<Admonition type="note">
After claiming, you'll still be able to access your project from the Neon Console, but you'll also have direct access from the Stack Auth dashboard.
</Admonition>

</Steps>

## Migrating to Neon Auth with Better Auth

Ready to upgrade to Neon Auth with Better Auth? See our comprehensive [migration guide](/docs/auth/migrate/from-legacy-auth).

### Benefits of upgrading

- **Native branching support** - Auth branches automatically with your database
- **Simplified configuration** - One URL instead of four keys
- **Direct database access** - No webhooks, no sync delays
- **Open-source foundation** - Built on Better Auth

### Migration guide includes

- Side-by-side code comparisons
- Package and component replacements
- Environment variable updates
- Step-by-step instructions

[View Migration Guide →](/docs/auth/migrate/from-legacy-auth)

## Additional resources

### Stack Auth documentation

For SDK documentation, components, hooks, and client-side authentication:

- [Stack Auth Official Docs](https://docs.stack-auth.com)
- [Stack Auth Components](https://docs.stack-auth.com/sdk/components)
- [Stack Auth API Reference](https://docs.stack-auth.com/api)

### Neon technical docs

- [Database Integration](/docs/auth/legacy/database-integration) - Technical reference for `users_sync`, backend auth, RLS
- [Migration Guide](/docs/auth/migrate/from-legacy-auth) - Upgrade to Neon Auth with Better Auth
- [Neon Auth](/docs/auth/overview) - Current Neon Auth with Better Auth

<NeedHelp/>


path: docs/changelog.md
content: ---
title: Changelog
summary: >-
  Covers the updates and changes made to Neon's features, functionality, and
  performance, providing a comprehensive history of modifications and
  improvements.
isDraft: false
updatedOn: '2026-02-06T23:35:50.334Z'
---



path: docs/guides/GUIDE_TEMPLATE.md
content: ---
title: 'Connect or Use [Name] with Neon'
subtitle: 'Set up a Neon project in seconds and connect from a [NAME]'
summary: >-
  Template for creating new Neon integration guides, providing a standard
  structure for connecting a Neon project with an external tool or framework.
enableTableOfContents: true
isDraft: true
updatedOn: '2026-02-06T22:07:32.901Z'
---

[Introduction paragraph describing the service, platform, framework, etc. Refer to other guides for examples.]

[Another paragraph describing what the guide covers; for example: "This guide shows how to ..." Refer to other guides for examples.]

## Section 1

[Add content here]

## Section 2

[Add content here]

## Section 3

[Add content here]

<NeedHelp/>


Security scan verdicts — ClawScan: clean | static analysis: suspicious | VirusTotal: suspicious | SkillSpector: suspicious (CRITICAL)