# Neon Postgres Documentation > Neon is a complete set of cloud backend primitives built around Lakebase Postgres, for developers, startups, and agent platforms, from Databricks. Services include Lakebase Postgres, Managed Better Auth, Realtime, Data API, Functions, Object Storage, AI Gateway. Lakebase Postgres on Neon includes autoscaling, instant restore, and scale-to-zero, with native branching, realtime and a fully reactive DX and works with any language, framework, or ORM that supports Postgres. > This file contains the full Neon documentation. For a table of contents, see https://neon.com/docs/llms.txt --- [Document source](https://neon.com/docs/ai-gateway/anthropic-messages.md) --- > Summary: The Anthropic Messages endpoint lets you use the Anthropic SDK with Neon AI Gateway by changing only the base URL. Supports streaming, prompt caching, and extended thinking on Claude models. # Anthropic Messages API Use the Anthropic SDK with Neon AI Gateway Last updated: 2026-10-31 The Anthropic Messages endpoint exposes the [Anthropic Messages API](https://docs.anthropic.com/en/api/messages) through Neon AI Gateway. Use it when you need extended thinking or prompt caching, which require the native Anthropic SDK. For standard completions, the [chat completions](https://neon.com/docs/ai-gateway/chat-completions) endpoint works with all Anthropic models and doesn't require the Anthropic SDK. **Base URL:** `https:///anthropic` **Note:** The Anthropic SDK appends `/v1/messages` to the base URL automatically. Set the base URL to `/anthropic` (without `/v1`). This endpoint is also reachable at the longer `/ai-gateway/anthropic/v1/messages` path. Both behave identically and neither is deprecated. See [Shorter paths](https://neon.com/docs/ai-gateway/models#shorter-paths) for the full list of aliases. ## Setup Set these environment variables. See [Get started](https://neon.com/docs/ai-gateway/get-started) for how to obtain them. ```bash NEON_AI_GATEWAY_TOKEN=nt_live_... NEON_AI_GATEWAY_BASE_URL=https://br-winter-pond-aptw82ef-api.ai.c-2.us-east-2.aws.neon.tech ``` ## Supported models This endpoint accepts Anthropic models only. See the [AI Gateway catalog](https://neon.com/docs/ai-gateway/models) for the full list. Supported models: - `claude-opus-5-5`, `claude-opus-5`, `claude-sonnet-5`, `claude-fable-5`, `claude-fable-5-1` - `claude-opus-4-8`, `claude-opus-4-7`, `claude-opus-4-6`, `claude-opus-4-5`, `claude-opus-4-1` - `claude-sonnet-4-6`, `claude-sonnet-4-5` - `claude-haiku-4-5` Sending a non-Anthropic model ID returns `400 model "" is not available on the anthropic_messages endpoint`, naming whichever model you sent. Use the [chat completions endpoint](https://neon.com/docs/ai-gateway/chat-completions) if you need to call multiple providers from the same code. ## Basic request **TypeScript (Anthropic SDK)** ```typescript import Anthropic from '@anthropic-ai/sdk'; const client = new Anthropic({ authToken: process.env.NEON_AI_GATEWAY_TOKEN, baseURL: `${process.env.NEON_AI_GATEWAY_BASE_URL}/anthropic`, }); const message = await client.messages.create({ model: 'claude-sonnet-4-6', max_tokens: 1024, messages: [{ role: 'user', content: 'What is Neon?' }], }); for (const block of message.content) { if (block.type === 'text') console.log(block.text); } ``` **Python (Anthropic SDK)** ```python import anthropic import os client = anthropic.Anthropic( auth_token=os.environ['NEON_AI_GATEWAY_TOKEN'], base_url=f"{os.environ['NEON_AI_GATEWAY_BASE_URL']}/anthropic", ) message = client.messages.create( model='claude-sonnet-4-6', max_tokens=1024, messages=[{'role': 'user', 'content': 'What is Neon?'}], ) print(message.content[0].text) ``` **cURL** ```bash curl -X POST "$NEON_AI_GATEWAY_BASE_URL/anthropic/v1/messages" \ -H "Authorization: Bearer $NEON_AI_GATEWAY_TOKEN" \ -H "Content-Type: application/json" \ -H "anthropic-version: 2023-06-01" \ -d '{ "model": "claude-sonnet-4-6", "max_tokens": 1024, "messages": [{"role": "user", "content": "What is Neon?"}] }' ``` ## Streaming Streaming works the same as with the Anthropic SDK directly. Use `client.messages.stream()` or pass `"stream": true` in a cURL request. The only change from standard usage is `base_url`. ## Prompt caching The gateway forwards the `cache_control` field to Anthropic unchanged. Prompt caching works exactly as described in the [Anthropic prompt caching docs](https://docs.anthropic.com/en/docs/build-with-claude/prompt-caching). **TypeScript (Anthropic SDK)** ```typescript const message = await client.messages.create({ model: 'claude-sonnet-4-6', max_tokens: 1024, system: [ { type: 'text', text: 'You are a helpful assistant.' }, { type: 'text', text: longDocumentContent, cache_control: { type: 'ephemeral' }, }, ], messages: [{ role: 'user', content: 'Summarize the key points.' }], }); console.log(message.usage); // { input_tokens: 50, output_tokens: 200, // cache_creation_input_tokens: 10000, cache_read_input_tokens: 0 } ``` **Python (Anthropic SDK)** ```python message = client.messages.create( model='claude-sonnet-4-6', max_tokens=1024, system=[ {'type': 'text', 'text': 'You are a helpful assistant.'}, { 'type': 'text', 'text': long_document_content, 'cache_control': {'type': 'ephemeral'}, }, ], messages=[{'role': 'user', 'content': 'Summarize the key points.'}], ) print(message.usage) # input_tokens=50, output_tokens=200, # cache_creation_input_tokens=10000, cache_read_input_tokens=0 ``` ## Extended thinking The gateway forwards the `thinking` parameter to Anthropic unchanged. Set `budget_tokens` to control how many tokens Claude can use for thinking. `max_tokens` must be greater than `budget_tokens`. **Important:** `claude-opus-5-5`, `claude-opus-5`, `claude-sonnet-5`, `claude-fable-5`, `claude-fable-5-1`, `claude-opus-4-8`, and `claude-opus-4-7` do not accept `thinking.type: "enabled"`. They return `400` with: ``` "thinking.type.enabled" is not supported for this model. Use "thinking.type.adaptive" and "output_config.effort" to control thinking. ``` Use `thinking: { type: 'adaptive' }` with `output_config: { effort: 'low' | 'medium' | 'high' | 'xhigh' | 'max' }` instead. `claude-opus-5-5`, `claude-fable-5`, and `claude-fable-5-1` also reject `thinking.type: "disabled"` — they always think adaptively. `claude-opus-4-6`, `claude-opus-4-5`, `claude-opus-4-1`, `claude-sonnet-4-6`, `claude-sonnet-4-5`, and `claude-haiku-4-5` accept the `enabled` + `budget_tokens` form shown below. **TypeScript (Anthropic SDK)** ```typescript const message = await client.messages.create({ model: 'claude-sonnet-4-6', max_tokens: 16000, thinking: { type: 'enabled', budget_tokens: 10000, }, messages: [{ role: 'user', content: 'Design a database schema for a multi-tenant SaaS app.' }], }); for (const block of message.content) { if (block.type === 'thinking') { console.log('Thinking:', block.thinking); } else if (block.type === 'text') { console.log(block.text); } } ``` **Python (Anthropic SDK)** ```python message = client.messages.create( model='claude-sonnet-4-6', max_tokens=16000, thinking={ 'type': 'enabled', 'budget_tokens': 10000, }, messages=[{'role': 'user', 'content': 'Design a database schema for a multi-tenant SaaS app.'}], ) for block in message.content: if block.type == 'thinking': print('Thinking:', block.thinking) elif block.type == 'text': print(block.text) ``` ## Forwarded headers The gateway forwards these request headers to the upstream provider: `Accept`, `Anthropic-Beta`, `Anthropic-Version`, `Content-Type`, `OpenAI-Beta`, `User-Agent`. All other headers are stripped. The `Authorization` header is replaced with the workspace credential before forwarding. Your `NEON_AI_GATEWAY_TOKEN` is never sent to Anthropic directly. ## Error handling | Status | Message | Cause | | ----------------- | ------------------------------------------------------------------------ | ----------------------------------------- | | `400 Bad Request` | `unknown model ""` | Model ID not in the catalog | | `400 Bad Request` | `model "" is not available on the anthropic_messages endpoint` | Non-Anthropic model sent to this endpoint | For authentication, quota, and upstream errors, see [Troubleshooting](https://neon.com/docs/ai-gateway/troubleshooting). ## Next steps - [Models](https://neon.com/docs/ai-gateway/models): full model catalog - [Chat completions](https://neon.com/docs/ai-gateway/chat-completions): use any model including Anthropic via the unified endpoint - [Authentication](https://neon.com/docs/ai-gateway/authentication): credential scopes and branch binding --- [Document source](https://neon.com/docs/ai-gateway/authentication.md) --- > Summary: AI Gateway uses Neon bearer credentials with the ai_gateway:invoke scope. Credentials are scoped to a branch and its descendants, so a credential created on your main branch works in all preview branches. No provider API keys are required. # AI Gateway authentication How Neon credentials work with AI Gateway Last updated: 2026-10-09 AI Gateway uses Neon bearer credentials, the same scoped-credential system as [Object Storage](https://neon.com/docs/storage/authentication): one credential API mints branch-scoped tokens that differ by scope (AI Gateway uses `ai_gateway:invoke`). No provider API keys are needed. ## Creating a credential A credential must include the `ai_gateway:invoke` scope. **CLI** Create a credential with the [Neon CLI](https://neon.com/docs/cli/credentials): ```bash neon credentials create --scope ai_gateway:invoke --name my-app-credential ``` The `api_token` is printed once; set it as `NEON_AI_GATEWAY_TOKEN`. Run it in a directory [linked](https://neon.com/docs/cli/link) to your project, or pass `--project-id` and `--branch`. **Console** In the Neon Console, click **Connect** at the top of the sidebar and open the **AI Gateway** tab. The snippet includes both gateway env vars (see [Environment variables](https://neon.com/docs/ai-gateway/authentication#environment-variables) below). Click **Reveal credential** to show the token, or **Copy snippet** to copy the full `.env`. Use **Rotate credential** to replace the token in place. The Connect dialog reveals and rotates the current credential. To create a credential with specific scopes, open your project's **Settings** > **Credentials** and select **Create credential**. To list all credentials for the branch or revoke one, use the [Neon CLI](https://neon.com/docs/cli/credentials) or the API (below). **API** ```bash curl -X POST "https://console.neon.tech/api/v2/projects/{project_id}/branches/{branch_id}/credentials" \ -H "Authorization: Bearer $NEON_API_KEY" \ -H "Content-Type: application/json" \ -d '{"scopes": ["ai_gateway:invoke"], "principal_type": "user"}' ``` The response includes an `api_token` field. Store it as an environment variable: ```bash export NEON_AI_GATEWAY_TOKEN=nt_live_... ``` ## Pull credentials with neon For local development, `neon env pull` writes your AI Gateway credentials to your `.env` file automatically, with no manual copy-paste from the API response: ```bash neon env pull --file .env ``` This populates `NEON_AI_GATEWAY_TOKEN` and `NEON_AI_GATEWAY_BASE_URL` for the current branch alongside your database connection string. Running `neon config apply` or `neon deploy` also auto-pulls credentials after a successful apply. To check current credential status: ```bash neon config status ``` For production deployments, use the [API-based workflow](https://neon.com/docs/ai-gateway/authentication#creating-a-credential) to create named credentials. `expires_at` is accepted but not currently enforced. Revoke credentials explicitly instead of relying on expiry. ## Using your credential Pass your credential as a bearer token on every request: ``` Authorization: Bearer ``` When using an AI SDK, set this as the `apiKey` parameter: **TypeScript** ```typescript import OpenAI from 'openai'; const client = new OpenAI({ apiKey: process.env.NEON_AI_GATEWAY_TOKEN, baseURL: `${process.env.NEON_AI_GATEWAY_BASE_URL}/v1`, }); ``` **Python** ```python from openai import OpenAI import os client = OpenAI( api_key=os.environ["NEON_AI_GATEWAY_TOKEN"], base_url=f"{os.environ['NEON_AI_GATEWAY_BASE_URL']}/v1", ) ``` ## Environment variables Neon provides two gateway env vars. `NEON_AI_GATEWAY_BASE_URL` is the bare branch host, so you append the dialect path yourself when configuring an SDK. | Variable | Value | | -------------------------- | ----------------------------------------------------------------------------------------- | | `NEON_AI_GATEWAY_TOKEN` | Bearer token (`nt_live_...`) | | `NEON_AI_GATEWAY_BASE_URL` | Bare branch host: `https://`, with no path. Append the dialect path yourself | Append the dialect path for the endpoint you need: ``` NEON_AI_GATEWAY_BASE_URL + /v1 → chat completions (all providers) NEON_AI_GATEWAY_BASE_URL + /openai/v1 → OpenAI Responses API NEON_AI_GATEWAY_BASE_URL + /anthropic → Anthropic Messages API NEON_AI_GATEWAY_BASE_URL + /gemini → Gemini generateContent API ``` The Anthropic and Gemini values are SDK base URLs: the Anthropic SDK appends `/v1/messages` and google-genai appends `/v1beta/models/...`, so don't add those segments yourself. Calling either endpoint directly takes the full path, `/anthropic/v1/messages` or `/gemini/v1beta/models/:`. Each inference dialect is also reachable at a longer `/ai-gateway//v1` path (e.g. `/ai-gateway/mlflow/v1` for chat completions, `/ai-gateway/openai/v1` for Responses, `/ai-gateway/anthropic/v1` for Anthropic Messages, `/ai-gateway/gemini` for Gemini). Both forms behave identically and neither is deprecated, but the shorter paths are what the docs and SDKs use. The model list is the exception: it has only `GET /v1/models`, with no `/ai-gateway/...` form. See [Shorter paths](https://neon.com/docs/ai-gateway/models#shorter-paths) for the full mapping. To use an OpenAI SDK, set its `apiKey` and `baseURL` from these variables (see the examples below). ## Credentials in Neon Functions When your code runs inside Neon Functions, both gateway env vars are injected automatically. No credential creation step required: | Variable | Value | | -------------------------- | --------------------------------------------------- | | `NEON_AI_GATEWAY_TOKEN` | Bearer token for the AI Gateway | | `NEON_AI_GATEWAY_BASE_URL` | Branch gateway host with `https://` prefix, no path | See [Environment variables](https://neon.com/docs/compute/functions/environment-variables) for the full list of variables Neon injects into a function. Configure an OpenAI SDK by setting `apiKey` and `baseURL` from these variables. Use the OpenAI Responses dialect for `responses.create()`: ```typescript import OpenAI from 'openai'; const client = new OpenAI({ apiKey: process.env.NEON_AI_GATEWAY_TOKEN, baseURL: `${process.env.NEON_AI_GATEWAY_BASE_URL}/openai/v1`, }); const response = await client.responses.create({ model: 'gpt-5-mini', input: 'What is Neon?', }); ``` For the chat completions endpoint, point the base URL at `/v1` instead: ```typescript import OpenAI from 'openai'; const client = new OpenAI({ apiKey: process.env.NEON_AI_GATEWAY_TOKEN, baseURL: `${process.env.NEON_AI_GATEWAY_BASE_URL}/v1`, }); ``` ## How branch binding works Each credential is tied to the branch it was created on. It's valid for: - That branch (the anchor branch) - Any branch descended from it: preview branches, feature branches, CI branches It's **not** valid for branches outside that lineage. This means a credential created on your `main` branch works in all branches that were forked from `main`. A credential created on a feature branch only works within that feature branch's descendants. ``` main ──── credential valid here └── preview/feature-x ──── and here └── preview/sub-branch ──── and here staging ──── credential NOT valid here (different lineage) ``` This design lets you use a single credential across your entire development workflow (local dev, preview deployments, and CI) without creating separate credentials for each environment. ## Common auth errors | Error | Cause | Fix | | ------------------------- | ------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------- | | `401 Unauthorized` | Missing or invalid credential | Check that `NEON_AI_GATEWAY_TOKEN` is set and contains the full token | | `403 Forbidden` | Credential lacks `ai_gateway:invoke` scope | Recreate the credential with the correct scope | | `403 Forbidden` | Branch not in credential lineage | Use a credential created on this branch or an ancestor branch. The gateway returns: `credential not authorized for this branch` | | `503 Service Unavailable` | Auth store temporarily unavailable | Retry the request | ## Rotating credentials To rotate a credential in place with the [Neon CLI](https://neon.com/docs/cli/credentials), run `neon credentials rotate ` (find the id with `neon credentials list`). The `token_id` stays the same and a new `api_token` is minted, so update `NEON_AI_GATEWAY_TOKEN` with it. Otherwise, create a new credential, update your environment variables, then revoke the old one. The Console's **Connect** dialog can rotate a credential (**AI Gateway** tab > **Rotate credential**) but not revoke one. To revoke, use the [Neon CLI](https://neon.com/docs/cli/credentials) (`neon credentials revoke `) or the API: ```bash curl -X DELETE "https://console.neon.tech/api/v2/projects/{project_id}/branches/{branch_id}/credentials/{token_id}" \ -H "Authorization: Bearer $NEON_API_KEY" ``` Or with the [Neon CLI](https://neon.com/docs/cli/credentials): ```bash neon credentials revoke ``` --- [Document source](https://neon.com/docs/ai-gateway/chat-completions.md) --- > Summary: The chat completions endpoint is the recommended starting point for Neon AI Gateway. It is OpenAI Chat Completions-compatible, works with any model in the catalog, and lets you switch providers without changing your SDK code. # Chat completions The OpenAI-compatible unified endpoint Last updated: 2026-10-23 The chat completions endpoint is the recommended way to use Neon AI Gateway. It's fully compatible with the [OpenAI Chat Completions API](https://platform.openai.com/docs/api-reference/chat) and works with every model in the [AI Gateway catalog](https://neon.com/docs/ai-gateway/models). Switch models by changing a single field. **Base URL:** `https:///v1` This endpoint is also reachable at the longer `/ai-gateway/mlflow/v1/chat/completions` path. Both behave identically and neither is deprecated. See [Shorter paths](https://neon.com/docs/ai-gateway/models#shorter-paths) for the full list of aliases. If you're using an OpenRouter-compatible client that asks for a base URL, set it to `https:///v1` and call `/chat/completions`. ## Setup Set these environment variables. See [Get started](https://neon.com/docs/ai-gateway/get-started) for how to obtain them. ```bash NEON_AI_GATEWAY_TOKEN=nt_live_... NEON_AI_GATEWAY_BASE_URL=https://br-winter-pond-aptw82ef-api.ai.c-2.us-east-2.aws.neon.tech ``` ## Basic request **TypeScript (OpenAI SDK)** ```typescript import OpenAI from 'openai'; const client = new OpenAI({ apiKey: process.env.NEON_AI_GATEWAY_TOKEN, baseURL: `${process.env.NEON_AI_GATEWAY_BASE_URL}/v1`, }); const response = await client.chat.completions.create({ model: 'gpt-5-mini', messages: [ { role: 'system', content: 'You are a helpful assistant.' }, { role: 'user', content: 'What is Neon?' }, ], max_tokens: 256, }); console.log(response.choices[0].message.content); ``` **Python (OpenAI SDK)** ```python from openai import OpenAI import os client = OpenAI( api_key=os.environ["NEON_AI_GATEWAY_TOKEN"], base_url=f"{os.environ['NEON_AI_GATEWAY_BASE_URL']}/v1", ) response = client.chat.completions.create( model="gpt-5-mini", messages=[ {"role": "system", "content": "You are a helpful assistant."}, {"role": "user", "content": "What is Neon?"}, ], max_tokens=256, ) print(response.choices[0].message.content) ``` **cURL** ```bash curl -X POST "$NEON_AI_GATEWAY_BASE_URL/v1/chat/completions" \ -H "Authorization: Bearer $NEON_AI_GATEWAY_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "model": "gpt-5-mini", "messages": [ {"role": "system", "content": "You are a helpful assistant."}, {"role": "user", "content": "What is Neon?"} ], "max_tokens": 256 }' ``` ## Streaming Add `stream: true` to receive a server-sent events response. **TypeScript (OpenAI SDK)** ```typescript import OpenAI from 'openai'; const client = new OpenAI({ apiKey: process.env.NEON_AI_GATEWAY_TOKEN, baseURL: `${process.env.NEON_AI_GATEWAY_BASE_URL}/v1`, }); const stream = await client.chat.completions.create({ model: 'gpt-5-mini', messages: [{ role: 'user', content: 'Explain branching in Postgres.' }], stream: true, }); for await (const chunk of stream) { process.stdout.write(chunk.choices[0]?.delta?.content ?? ''); } ``` **Python (OpenAI SDK)** ```python from openai import OpenAI import os client = OpenAI( api_key=os.environ["NEON_AI_GATEWAY_TOKEN"], base_url=f"{os.environ['NEON_AI_GATEWAY_BASE_URL']}/v1", ) with client.chat.completions.create( model="gpt-5-mini", messages=[{"role": "user", "content": "Explain branching in Postgres."}], stream=True, ) as stream: for chunk in stream: print(chunk.choices[0].delta.content or "", end="", flush=True) ``` **cURL** ```bash curl -X POST "$NEON_AI_GATEWAY_BASE_URL/v1/chat/completions" \ -H "Authorization: Bearer $NEON_AI_GATEWAY_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "model": "gpt-5-mini", "messages": [{"role": "user", "content": "Explain branching in Postgres."}], "stream": true }' ``` ## Switching models Change the `model` field to use a different provider. Everything else stays the same. ```typescript // OpenAI model: 'gpt-5-4' // Google model: 'gemini-3-flash' // Alibaba model: 'qwen3-next-80b-a3b-instruct' ``` For a few models, `message.content` comes back as an array of content blocks instead of a plain string. See [Content shape varies by model](https://neon.com/docs/ai-gateway/models#which-endpoint-to-use) before swapping in a model you haven't used yet. Gemini models don't support `parallel_tool_calls: false`, and a request that sets it returns `400` with `Unknown name "parallel_tool_calls"`. Leave the field out instead. Gemini makes parallel tool calls by default, so your code needs to handle more than one tool call per turn. `gemini-4-argon` doesn't support `temperature` or `reasoning_effort` on this endpoint, and a request that sets either returns `400`. Leave both out. If you need to control them, call the model through the [Gemini endpoint](https://neon.com/docs/ai-gateway/gemini) instead, where `temperature` and `thinkingConfig.thinkingLevel` both work. See [Models](https://neon.com/docs/ai-gateway/models) for the full list. ## Rate limiting There are two separate rate limit tiers: - **Neon account quota:** enforced by Neon. Returns `429` with error code `REQUEST_LIMIT_EXCEEDED`. See [Rate limits](https://neon.com/docs/ai-gateway/models#rate-limits) for current limits. - **Upstream provider limit:** enforced by the Databricks workspace serving the model. Returns `429` with forwarded rate limit headers. When the upstream provider rate-limits a request, AI Gateway forwards the relevant headers so your client can back off correctly: | Header | Description | | -------------------------------- | ------------------------------------------ | | `Retry-After` | Seconds to wait before retrying (RFC 9110) | | `X-Ratelimit-Limit-Requests` | Request limit | | `X-Ratelimit-Remaining-Requests` | Remaining requests | | `X-Ratelimit-Reset-Requests` | Time until request limit resets | | `X-Ratelimit-Limit-Tokens` | Token limit | | `X-Ratelimit-Remaining-Tokens` | Remaining tokens | | `X-Ratelimit-Reset-Tokens` | Time until token limit resets | ## Error handling | Status | Meaning | Common cause | | ------------------------------ | ---------------------- | -------------------------------------------------------------------------------------------------------------------------------------------- | | `400 Bad Request` | Invalid request | Unknown model ID, or model used on the wrong endpoint | | `413 Request Entity Too Large` | Body too large | Request body exceeds 32 MiB. Reduce the size of your request. | | `401 Unauthorized` | Authentication failed | Missing or invalid `NEON_AI_GATEWAY_TOKEN` | | `403 Forbidden` | Access denied | Credential lacks `ai_gateway:invoke` scope, or branch not in credential lineage | | `429 Too Many Requests` | Account quota exceeded | Your account's AI Gateway quota is blocked. Error code: `REQUEST_LIMIT_EXCEEDED`. Check `Retry-After` for when to retry, or contact support. | | `429 Too Many Requests` | Upstream rate limited | Upstream provider rate limit. Check the `Retry-After` and `X-Ratelimit-*` headers. | | `502 Bad Gateway` | Upstream error | Temporary issue with the upstream workspace. Retry the request. | Error responses are a JSON object with an `error.message` field: ```json { "error": { "message": "unknown model \"\"" } } ``` ## Next steps - [Models](https://neon.com/docs/ai-gateway/models): full model catalog - [OpenAI Responses API](https://neon.com/docs/ai-gateway/openai-responses): Responses API endpoint - [Authentication](https://neon.com/docs/ai-gateway/authentication): credential scopes and branch binding --- [Document source](https://neon.com/docs/ai-gateway/data-retention.md) --- > Summary: Most Neon AI Gateway models run on Databricks Model Serving, where Databricks may temporarily store inputs and outputs for up to 30 days to prevent, detect, and mitigate abuse. OpenAI and Anthropic may retain data for safety purposes for certain models. Jev is hosted by TypeSafe AI, and TypeSafe AI's terms apply. # Neon AI Gateway data retention What Databricks and model providers retain when you use Neon AI Gateway Last updated: 2026-10-29 Neon AI Gateway gives you one credential for many models. Most models are served through [Databricks Model Serving](https://docs.databricks.com/aws/en/machine-learning/model-serving), and data retention for those requests follows Databricks' policy, which covers what Databricks retains and what partner model providers may retain. This page summarizes those policies. For the authoritative and latest terms, see [Databricks Model Serving data retention](https://docs.databricks.com/aws/en/machine-learning/model-serving#data-retention) and, for Jev, the TypeSafe AI [data processing addendum](https://typesafe.ai/legal/data-processing). ## Databricks data retention For all Model Serving workloads, Databricks retains container build logs for up to 30 days and metrics data for up to 14 days. As part of providing the service, Databricks may temporarily process and store your inputs and outputs to prevent, detect, and mitigate abuse or harmful uses. Your inputs and outputs are: - Isolated from those of other customers - Stored in the region where your request was processed, for up to 30 days - Only accessible for detecting and responding to security or abuse concerns ## Partner model provider data retention Partner model providers may retain data for safety purposes. This retention relies on automated scanning before any limited human review. ### OpenAI In accordance with [OpenAI's safety retention policy](https://developers.openai.com/api/docs/guides/your-data#safety-retention), for `gpt-5-5`, `gpt-5-5-pro`, and future models, OpenAI may retain certain coding and routing customers' content that OpenAI's classifiers detect as potentially violating OpenAI's usage policies. Otherwise, retention isn't affected. Coding and routing customers are customers that: - Provide software engineering or deployment work for third parties, such as code generation, code completion, and agentic development or deployment workflows - Act as model-access intermediary platforms or services that let third parties use OpenAI models for cyber-risk-relevant software development, alongside access to other providers' models All other customers may be subject to additional retention upon advance notice. ### Anthropic For Anthropic's Fable 5 and future Mythos-class models, all customers are subject to data retention for safety purposes, as described in [Anthropic's data retention practices](https://support.claude.com/en/articles/15425996-data-retention-practices-for-mythos-class-models). ## TypeSafe AI data retention Jev is hosted by TypeSafe AI, Inc. Its [data processing addendum](https://typesafe.ai/legal/data-processing) and [privacy policy](https://typesafe.ai/legal/privacy-policy) describe how TypeSafe AI handles your requests. The privacy policy states that TypeSafe AI: - Doesn't train or fine-tune AI or machine learning models on your prompts or other input - Retains personal data for as long as reasonably necessary to provide its services - Hosts its services in the United States Neither document gives a fixed retention period for inputs or outputs. --- [Document source](https://neon.com/docs/ai-gateway/decisions.md) --- > Summary: Neon AI Gateway serves TypeSafe's System One decision models, Jev 1.14 and OpenJev, on the /typesafe/v1/systemone endpoint. Ask yes/no, choice, and score questions about text, JSON, or images and get back probabilities instead of generated text, with the same Neon credential you use for chat completions. # Decisions Answer questions about text, JSON, or images with System One decision models Last updated: 2026-10-30 Decision models don't generate text. You send a piece of text or JSON, called the state, and a set of named questions about it. The model answers each one with numbers: the probability of a yes, the option it picked and how sure it is, or where the input falls on a scale you define. Use them to classify, route, or score input without prompting a chat model and parsing its reply. You can also [ask about an image](https://neon.com/docs/ai-gateway/decisions#ask-about-an-image). The Neon AI Gateway serves TypeSafe's [System One](https://docs.typesafe.ai/) decision models, using the same Neon credential as the other AI Gateway endpoints. You can call them with the TypeSafe SDKs, the [Vercel AI SDK](https://neon.com/docs/ai-gateway/decisions#use-with-the-vercel-ai-sdk), or plain HTTP. **Endpoint:** `POST https:///typesafe/v1/systemone` Decision models aren't available on any other endpoint, and this one doesn't serve chat models. ## Models | Model ID | Name | Context window | Notes | | ----------------------- | --------------------- | -------------- | ----------------------------- | | `typesafeai-jev-1-14-0` | Jev 1.14 | 65,536 tokens | TypeSafe's proprietary model. | | `openjev-qwen35-4b` | OpenJev (Qwen 3.5 4B) | 131,072 tokens | Open weights. | Both are billed on **input tokens only**. See the [model catalog](https://neon.com/docs/ai-gateway/overview#available-models) for rates. ## Setup The examples use two environment variables: ```bash NEON_AI_GATEWAY_TOKEN=nt_live_... NEON_AI_GATEWAY_BASE_URL=https://br-... ``` Run `neon env pull --file .env` to write both to your `.env` for the current branch. You can also copy them from the Neon Console's **Connect** panel, on the **AI Gateway** tab. Inside Neon Functions they're injected automatically. See [Authentication](https://neon.com/docs/ai-gateway/authentication) for details. Install the TypeSafe SDK with `npm install @typesafe-ai/sdk` or `pip install typesafe-sdk`. The SDKs take `${NEON_AI_GATEWAY_BASE_URL}/typesafe` as their base URL and add `/v1/systemone` themselves. The TypeSafe SDKs are built for TypeSafe's own API, where the default model is `jev-latest`. The gateway uses its own model IDs, so set one when you create the client (`defaultModel` in TypeScript, `model` in Python), as the examples below do. ## Basic request This request asks three questions about a support message, one of each type: **TypeScript (TypeSafe SDK)** ```typescript import { choice, noul, score, TypeSafeClient } from '@typesafe-ai/sdk'; const client = new TypeSafeClient({ apiKey: process.env.NEON_AI_GATEWAY_TOKEN, baseURL: `${process.env.NEON_AI_GATEWAY_BASE_URL}/typesafe`, defaultModel: 'typesafeai-jev-1-14-0', }); const { answers } = await client.systemOne({ state: 'I was charged twice this month and need the extra charge refunded.', questions: { department: choice('Which team should handle this?', { billing: 'Payments and refunds', support: 'Other requests', }), severity: score('How severe is the issue?', [ 'Cosmetic', 'Workaround exists', 'Blocking; no workaround', ]), refund: noul('Is the customer asking for money back?'), }, }); console.log(answers.department.choice); // billing console.log(answers.refund.noul); // 0.98 ``` **Python (TypeSafe SDK)** ```python import os from typesafe_sdk import Choice, Noul, Score, TypeSafeClient with TypeSafeClient( api_key=os.environ["NEON_AI_GATEWAY_TOKEN"], base_url=f"{os.environ['NEON_AI_GATEWAY_BASE_URL']}/typesafe", model="typesafeai-jev-1-14-0", ) as client: response = client.system_one( state="I was charged twice this month and need the extra charge refunded.", questions={ "department": Choice( instructions="Which team should handle this?", criteria={"billing": "Payments and refunds", "support": "Other requests"}, ), "severity": Score( instructions="How severe is the issue?", criteria=["Cosmetic", "Workaround exists", "Blocking; no workaround"], ), "refund": Noul(instructions="Is the customer asking for money back?"), }, ) print(response.answers["department"].choice) # billing print(response.answers["refund"].noul) # 0.98 ``` **cURL** ```bash curl -X POST "$NEON_AI_GATEWAY_BASE_URL/typesafe/v1/systemone" \ -H "Authorization: Bearer $NEON_AI_GATEWAY_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "model": "typesafeai-jev-1-14-0", "state": "I was charged twice this month and need the extra charge refunded.", "questions": { "department": { "type": "choice", "instructions": "Which team should handle this?", "criteria": {"billing": "Payments and refunds", "support": "Other requests"} }, "severity": { "type": "score", "instructions": "How severe is the issue?", "criteria": ["Cosmetic", "Workaround exists", "Blocking; no workaround"] }, "refund": { "type": "noul", "instructions": "Is the customer asking for money back?" } } }' ``` The model answers each question on its own, so you can ask several in one request. The state can be a string, as here, or a JSON object such as `{ "message": "...", "plan": "Launch" }`. ## Question types | Type | Criteria | Answer | | --------------- | ---------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------- | | `noul` (yes/no) | Optional `true` and `false` descriptions | `noul`: the probability of a yes, from 0 to 1 | | `choice` | A map of option names to descriptions | `choice`: the option picked, plus a `confidence` and per-option `probabilities` | | `score` | Level descriptions, indexed from 0. Use at least two: with one, the answer is always `0` | `score`: the expected level, which can fall between levels, plus `confidence`, `probabilities`, and a `legend` of the levels | A `score` of `1.02` with the rubric above means "about `Workaround exists`"; read `probabilities` when you need the full distribution. ## Response shape A response for the request above. Values can vary slightly from run to run: ```json { "model": "jev-1.14.0", "answers": { "department": { "type": "choice", "choice": "billing", "confidence": 1.0, "probabilities": { "billing": 1.0, "support": 0.0 } }, "severity": { "type": "score", "score": 1.02, "confidence": 0.52, "legend": { "0": "Cosmetic", "1": "Workaround exists", "2": "Blocking; no workaround" }, "probabilities": { "0": 0.15, "1": 0.68, "2": 0.17 } }, "refund": { "type": "noul", "noul": 0.98 } }, "usage": { "input_tokens": 383, "output_tokens": 61 } } ``` `model` reports the name that served the request (`jev-1.14.0` here, `databricks-openjev-qwen35-4b` for OpenJev). Keep sending the model IDs from [Models](https://neon.com/docs/ai-gateway/decisions#models). ## Ask about an image Add a top-level `assets` field and link it to the question: 1. `assets` holds the image under a reference you choose (`img-7d2f`). 2. A `state` field holds that reference (`"photo": "img-7d2f"`). 3. The question names that field in backticks (`` `photo` ``). Jev 1.14 also needs the `TypeSafe-Danger-Zone-Images: true` header, TypeSafe's opt-in for its experimental image input, and returns `400` without it. OpenJev doesn't need the header. **cURL** ```bash IMAGE_B64=$(base64 < package.png | tr -d '\n') curl -X POST "$NEON_AI_GATEWAY_BASE_URL/typesafe/v1/systemone" \ -H "Authorization: Bearer $NEON_AI_GATEWAY_TOKEN" \ -H "Content-Type: application/json" \ -H "TypeSafe-Danger-Zone-Images: true" \ -d @- < Summary: Neon AI Gateway serves text-embedding models on an OpenAI-compatible /v1/embeddings endpoint. Use short model IDs like qwen3-embedding-0-6b, bge-large-en, or gte-large-en, all 1024-dimensional, with the same Neon credential you use for chat completions. # Embeddings The OpenAI-compatible embeddings endpoint Last updated: 2026-10-23 Embeddings turn text into vectors that capture meaning, so you can match text by what it means rather than by the exact words. They power semantic search, recommendations, clustering, and retrieval-augmented generation (RAG). The Neon AI Gateway embeddings endpoint generates those vectors so you can store and search them in Postgres. It's compatible with the [OpenAI Embeddings API](https://platform.openai.com/docs/api-reference/embeddings): the same OpenAI SDK you use elsewhere works against the gateway, using the same Neon credential as the other AI Gateway endpoints. **Base URL:** `https:///v1` This endpoint is also reachable at the longer `/ai-gateway/mlflow/v1/embeddings` path. Both behave identically and neither is deprecated. See [Shorter paths](https://neon.com/docs/ai-gateway/models#shorter-paths). **Important: OpenAI JavaScript SDK v6: pass encoding_format: float** On the `openai` JavaScript/TypeScript SDK **v6**, pass `encoding_format: "float"` on embedding calls (as shown below), or upgrade to v7 or later. Without it, v6 returns a broken all-zeros vector with no error. The Python SDK and raw HTTP are unaffected. ## Models Three embedding models are available today. All return **1024-dimensional** vectors and are billed on **input tokens only**. | Model ID | Dimensions | Notes | | -------------------------------------------------------------------------------------- | ---------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------- | | [`qwen3-embedding-0-6b`](https://neon.com/docs/ai-gateway/models/qwen3-embedding-0-6b) | 1024 | Unit-normalized (L2 norm = 1), so dot product equals cosine similarity. Supports the `dimensions` parameter for shorter vectors. | | [`bge-large-en`](https://neon.com/docs/ai-gateway/models/bge-large-en) | 1024 | Unit-normalized (L2 norm = 1), so dot product equals cosine similarity. Reads only the first 512 tokens of each input. Ignores the `dimensions` parameter. | | [`gte-large-en`](https://neon.com/docs/ai-gateway/models/gte-large-en) | 1024 | Not normalized (L2 norm ≈ 24). Use cosine distance, or normalize the vectors yourself. Ignores the `dimensions` parameter. | Use the short model IDs shown above. The `databricks-` prefixed forms (`databricks-qwen3-embedding-0-6b`, `databricks-bge-large-en`, `databricks-gte-large-en`) are also accepted. Each model ID links to its catalog page, which lists the input price per million tokens and has copy-paste quickstarts in TypeScript, Python, and cURL. ## Setup The examples use two environment variables: ```bash NEON_AI_GATEWAY_TOKEN=nt_live_... NEON_AI_GATEWAY_BASE_URL=https://br-... ``` Run `neon env pull --file .env` to write both to your `.env` for the current branch (`neon deploy` and `neon config apply` also pull them). You can also copy them from the Neon Console's **Connect** panel, on the **AI Gateway** tab. Inside Neon Functions they're injected automatically. See [Authentication](https://neon.com/docs/ai-gateway/authentication) for details. The examples below use the `openai` SDK. Install it with `npm install openai` or `pip install openai`. ## Basic request **TypeScript (OpenAI SDK)** ```typescript import OpenAI from 'openai'; const client = new OpenAI({ apiKey: process.env.NEON_AI_GATEWAY_TOKEN, baseURL: `${process.env.NEON_AI_GATEWAY_BASE_URL}/v1`, }); const response = await client.embeddings.create({ model: 'qwen3-embedding-0-6b', input: 'The quick brown fox jumps over the lazy dog.', encoding_format: 'float', // required on the openai SDK v6; harmless on v7+ }); console.log(response.data[0].embedding.length); // 1024 ``` **Python (OpenAI SDK)** ```python from openai import OpenAI import os client = OpenAI( api_key=os.environ["NEON_AI_GATEWAY_TOKEN"], base_url=f"{os.environ['NEON_AI_GATEWAY_BASE_URL']}/v1", ) response = client.embeddings.create( model="qwen3-embedding-0-6b", input="The quick brown fox jumps over the lazy dog.", ) print(len(response.data[0].embedding)) # 1024 ``` **cURL** ```bash curl -X POST "$NEON_AI_GATEWAY_BASE_URL/v1/embeddings" \ -H "Authorization: Bearer $NEON_AI_GATEWAY_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "model": "qwen3-embedding-0-6b", "input": "The quick brown fox jumps over the lazy dog." }' ``` ## Response shape The response is OpenAI-compatible: a list of embedding objects, one per input, each with the vector and its position. ```json { "id": "...", "object": "list", "model": "qwen3-embedding-0-6b-112025", "data": [ { "index": 0, "object": "embedding", "embedding": [-0.0149, 0.0172, -0.0119, "..."] } ], "usage": { "prompt_tokens": 11, "total_tokens": 11 } } ``` The `model` field reports the resolved, versioned name that served the request (`qwen3-embedding-0-6b-112025` here), which is handy for logging. Keep sending the short model ID (`qwen3-embedding-0-6b`, `bge-large-en`, or `gte-large-en`) in your requests. ## Use with the Vercel AI SDK For TypeScript apps and agents, [`@neon/ai-sdk-provider`](https://www.npmjs.com/package/@neon/ai-sdk-provider) exposes the gateway's embedding models to the [Vercel AI SDK](https://ai-sdk.dev). It reads `NEON_AI_GATEWAY_BASE_URL` and `NEON_AI_GATEWAY_TOKEN` (the same variables from [Setup](https://neon.com/docs/ai-gateway/embeddings#setup)), so no extra configuration is needed. Install it with `npm install @neon/ai-sdk-provider ai`. ```typescript import { neon } from '@neon/ai-sdk-provider'; import { embed } from 'ai'; const { embedding } = await embed({ model: neon.embeddingModel('qwen3-embedding-0-6b'), value: 'The quick brown fox jumps over the lazy dog.', }); console.log(embedding.length); // 1024 ``` Use `embedMany()` to embed a batch in one call. The gateway accepts up to 150 inputs per request (see [Batch input](https://neon.com/docs/ai-gateway/embeddings#batch-input)). ## Batch input Pass an array of strings to embed many inputs in one request. The response returns one embedding per input, in the same order, with a matching `index`. `bge-large-en` embeds only the first 512 tokens of each input and silently drops the rest, with no error (`usage.prompt_tokens` stops at 512). Split longer documents into chunks and send the chunks as a batch. **TypeScript (OpenAI SDK)** ```typescript const response = await client.embeddings.create({ model: 'qwen3-embedding-0-6b', input: ['First document.', 'Second document.', 'Third document.'], encoding_format: 'float', }); for (const item of response.data) { console.log(item.index, item.embedding.length); } ``` **Python (OpenAI SDK)** ```python response = client.embeddings.create( model="qwen3-embedding-0-6b", input=["First document.", "Second document.", "Third document."], ) for item in response.data: print(item.index, len(item.embedding)) ``` ## Shorter vectors with `dimensions` `qwen3-embedding-0-6b` supports the `dimensions` parameter to return a shorter, Matryoshka-style vector (for example `dimensions: 256`), which trades some accuracy for smaller storage and faster search. `bge-large-en` and `gte-large-en` ignore this parameter and always return 1024 dimensions. ```typescript const response = await client.embeddings.create({ model: 'qwen3-embedding-0-6b', input: 'A shorter embedding.', dimensions: 256, encoding_format: 'float', }); console.log(response.data[0].embedding.length); // 256 ``` ## Choosing a distance operator The models differ in how their vectors are scaled, which affects the pgvector operator class you index and query with: - **`qwen3-embedding-0-6b`** and **`bge-large-en`** are unit-normalized (every vector has L2 norm 1), so cosine distance and inner product rank results identically. Cosine (`vector_cosine_ops`, `<=>`) is a safe default. - **`gte-large-en`** is not normalized (L2 norm ≈ 24). Use cosine distance (`vector_cosine_ops`, `<=>`), which is scale-invariant, or normalize the vectors before storing them. For an end-to-end example that stores AI Gateway embeddings in Postgres and searches them, see [Get started with Lakebase Search](https://neon.com/docs/ai/lakebase-search-get-started). ## Not supported - **Streaming.** Embeddings don't stream. A request with `stream: true` returns `400`. - **Wrong endpoint.** An embedding model called on a chat endpoint (or a chat model on this endpoint) is rejected. Send embedding requests to `/v1/embeddings`. ## Error handling | Status | Meaning | Common cause | | ----------------------- | --------------------- | ---------------------------------------------------------------------------------------------------------------- | | `400 Bad Request` | Invalid request | Unknown model ID, an embedding model used on a chat endpoint, or `stream: true` | | `401 Unauthorized` | Authentication failed | Missing or invalid `NEON_AI_GATEWAY_TOKEN` | | `403 Forbidden` | Access denied | Credential lacks `ai_gateway:invoke` scope, or branch not in credential lineage | | `429 Too Many Requests` | Quota or rate limited | Account quota or per-minute token limit. See [Rate limits](https://neon.com/docs/ai-gateway/models#rate-limits). | ## Next steps - [Get started with Lakebase Search](https://neon.com/docs/ai/lakebase-search-get-started): store and search AI Gateway embeddings in Postgres - [Models](https://neon.com/docs/ai-gateway/models): full model catalog - [Chat completions](https://neon.com/docs/ai-gateway/chat-completions): the OpenAI-compatible chat endpoint --- [Document source](https://neon.com/docs/ai-gateway/gemini.md) --- > Summary: The Gemini endpoint exposes the Google Gemini generateContent and streamGenerateContent APIs through Neon AI Gateway. Use the google-genai SDK with a custom base URL. # Gemini API Use the Google Gemini API with Neon AI Gateway Last updated: 2026-10-23 The Gemini endpoint exposes the [Google Gemini API](https://ai.google.dev/api/generate-content) through Neon AI Gateway. Use it when you're already working with the `google-genai` SDK and want to keep your existing code. For most use cases, the [chat completions](https://neon.com/docs/ai-gateway/chat-completions) endpoint is simpler to set up and works with Gemini models via the OpenAI SDK. **Supported actions:** `:generateContent` and `:streamGenerateContent` **Endpoint pattern:** `https:///gemini/v1beta/models/:` **Note:** Only `generateContent` and `streamGenerateContent` are supported. Requests to other actions (such as `countTokens`) return `404 unsupported gemini action`. This endpoint is also reachable at the longer `/ai-gateway/gemini/v1beta/models/:` path. Both behave identically and neither is deprecated. See [Shorter paths](https://neon.com/docs/ai-gateway/models#shorter-paths) for the full list of aliases. ## Setup Set these environment variables. See [Get started](https://neon.com/docs/ai-gateway/get-started) for how to obtain them. ```bash NEON_AI_GATEWAY_TOKEN=nt_live_... NEON_AI_GATEWAY_BASE_URL=https://br-winter-pond-aptw82ef-api.ai.c-2.us-east-2.aws.neon.tech ``` ## Supported models This endpoint accepts Google models only: | Model ID | Notes | | ----------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | `gemini-4-argon` | Supports `temperature` and `thinkingConfig.thinkingLevel` on this endpoint, but not on [chat completions](https://neon.com/docs/ai-gateway/chat-completions#switching-models). | | `gemini-3-8-flash` | | | `gemini-3-7-flash` | | | `gemini-3-6-flash` | | | `gemini-3-5-flash` | | | `gemini-3-5-flash-lite` | | | `gemini-3-1-pro` | | | `gemini-3-1-flash-lite` | | | `gemini-3-flash` | | Sending a non-Google model ID returns `400 model "" is not available on the gemini_generate_content endpoint`, naming whichever model you sent. Use the [chat completions endpoint](https://neon.com/docs/ai-gateway/chat-completions) if you want to call Gemini models alongside other providers from the same code. ## Basic request **Note:** The `google-genai` SDK's `apiKey` option sends an `x-goog-api-key` header, but Neon AI Gateway expects `Authorization: Bearer `. Set your credential as an explicit header instead, and pass any non-empty string as `apiKey` since the SDK requires the field even though the gateway ignores it. **TypeScript (google-genai)** ```typescript import { GoogleGenAI } from '@google/genai'; const client = new GoogleGenAI({ apiKey: 'placeholder', httpOptions: { baseUrl: `${process.env.NEON_AI_GATEWAY_BASE_URL}/gemini`, headers: { Authorization: `Bearer ${process.env.NEON_AI_GATEWAY_TOKEN}`, }, }, }); const response = await client.models.generateContent({ model: 'gemini-3-flash', contents: [{ role: 'user', parts: [{ text: 'What is Neon?' }] }], }); console.log(response.text); ``` **Python (google-genai)** ```python from google import genai from google.genai import types import os client = genai.Client( api_key='placeholder', http_options=types.HttpOptions( base_url=f"{os.environ['NEON_AI_GATEWAY_BASE_URL']}/gemini", headers={'Authorization': f"Bearer {os.environ['NEON_AI_GATEWAY_TOKEN']}"}, ), ) response = client.models.generate_content( model='gemini-3-flash', contents='What is Neon?', ) print(response.text) ``` **cURL** ```bash curl -X POST \ "$NEON_AI_GATEWAY_BASE_URL/gemini/v1beta/models/gemini-3-flash:generateContent" \ -H "Authorization: Bearer $NEON_AI_GATEWAY_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "contents": [{"role": "user", "parts": [{"text": "What is Neon?"}]}] }' ``` ## Streaming **TypeScript (google-genai)** ```typescript const stream = await client.models.generateContentStream({ model: 'gemini-3-flash', contents: [{ role: 'user', parts: [{ text: 'Explain database branching.' }] }], }); for await (const chunk of stream) { process.stdout.write(chunk.text ?? ''); } ``` **Python (google-genai)** ```python for chunk in client.models.generate_content_stream( model='gemini-3-flash', contents='Explain database branching.', ): print(chunk.text, end='', flush=True) ``` ## URL structure The gateway uses the model ID and action directly in the URL path. The `google-genai` SDK constructs this automatically from the base URL and model parameter: ``` base_url: https:///gemini model: gemini-3-flash action: generateContent or streamGenerateContent → https:///gemini/v1beta/models/gemini-3-flash:generateContent → https:///gemini/v1beta/models/gemini-3-flash:streamGenerateContent ``` When calling the REST API directly, the model ID and action must appear in the path as shown above. ## Error handling | Status | Message | Cause | | ----------------- | ----------------------------------------------------------------------------- | --------------------------------------------------------------------- | | `400 Bad Request` | `unknown model ""` | Model ID not in the catalog | | `400 Bad Request` | `model "" is not available on the gemini_generate_content endpoint` | Non-Google model sent to this endpoint | | `404 Not Found` | `unsupported gemini action` | Action other than `generateContent` or `streamGenerateContent` in URL | | `404 Not Found` | `invalid gemini model path` | Malformed `model:action` segment in URL | For authentication, quota, and upstream errors, see [Troubleshooting](https://neon.com/docs/ai-gateway/troubleshooting). ## Next steps - [Models](https://neon.com/docs/ai-gateway/models): full model catalog - [Chat completions](https://neon.com/docs/ai-gateway/chat-completions): use Gemini models via the unified OpenAI-compatible endpoint - [Authentication](https://neon.com/docs/ai-gateway/authentication): credential scopes and branch binding --- [Document source](https://neon.com/docs/ai-gateway/get-started.md) --- > Summary: This quickstart walks you through getting a credential, finding your branch host, and making your first request to the Neon AI Gateway using the OpenAI SDK. No provider API keys required. Authenticate with your Neon credential. # Get started with Neon AI Gateway Make your first inference request in minutes Last updated: 2026-10-01 To set up Neon AI Gateway with an AI coding assistant, install the Neon Platform (`neon`) and Neon AI Gateway skills with the [Neon CLI](https://neon.com/docs/cli): ```bash neon skills -s neon -s neon-ai-gateway ``` Without the Neon CLI, run `npx skills add neondatabase/agent-skills -s neon -s neon-ai-gateway` instead. ## Get access You need a project in AWS US East (Ohio) (`aws-us-east-2`), AWS US East (N. Virginia) (`aws-us-east-1`), AWS Europe (Frankfurt) (`aws-eu-central-1`), or AWS Asia Pacific (Singapore) (`aws-ap-southeast-1`). Support is expanding toward [all regions](https://neon.com/docs/introduction/regions). Using the AI Gateway requires prepaid credits, which you can buy on any Neon plan, including Free. Credits give you every model in the catalog. See [Model access](https://neon.com/docs/ai-gateway/models#model-access) for details. ## Create a credential With the [Neon CLI](https://neon.com/docs/cli/credentials), run: ```bash neon credentials create --scope ai_gateway:invoke ``` Or, in the Neon Console, click **Connect** at the top of the sidebar and open the **AI Gateway** tab. Click **Reveal credential** to show `NEON_AI_GATEWAY_TOKEN`, or **Copy snippet** to copy it together with `NEON_AI_GATEWAY_BASE_URL`. Use **Rotate credential** to issue a new token. Or use the API: ```bash curl -X POST "https://console.neon.tech/api/v2/projects/{project_id}/branches/{branch_id}/credentials" \ -H "Authorization: Bearer $NEON_API_KEY" \ -H "Content-Type: application/json" \ -d '{"scopes": ["ai_gateway:invoke"], "principal_type": "user"}' ``` **Using neon.ts?:** If your project has a `neon.ts` file, run [`neon config add ai-gateway`](https://neon.com/docs/cli/config#add) (or declare `aiGateway: true` yourself) and then `neon deploy`. Credentials are provisioned and pulled into your local `.env` automatically, with no manual creation step. See [Authentication](https://neon.com/docs/ai-gateway/authentication) for details. Store the credential as an environment variable: ```bash export NEON_AI_GATEWAY_TOKEN=nt_live_... ``` ## Find your branch host Your branch's AI Gateway host is available in the Neon Console from the **Connect** dialog's **AI Gateway** tab, or via the Neon API. It follows this format: ``` br--api.ai...aws.neon.tech ``` For example: ```bash export NEON_AI_GATEWAY_BASE_URL=https://br-winter-pond-aptw82ef-api.ai.c-2.us-east-2.aws.neon.tech ``` This is different from your database connection string. ## Install dependencies The quickstart uses the OpenAI SDK because the chat completions endpoint is OpenAI-compatible. It works with any model in the catalog, including GPT and Gemini. **npm** ```bash npm install openai dotenv ``` **yarn** ```bash yarn add openai dotenv ``` **pnpm** ```bash pnpm add openai dotenv ``` **pip** ```bash pip install openai python-dotenv ``` ## Make your first request The chat completions endpoint is OpenAI-compatible. Set `baseURL` to your branch host and `apiKey` to your credential. No other changes needed. **TypeScript** ```typescript import OpenAI from 'openai'; import 'dotenv/config'; const client = new OpenAI({ apiKey: process.env.NEON_AI_GATEWAY_TOKEN, baseURL: `${process.env.NEON_AI_GATEWAY_BASE_URL}/v1`, }); const response = await client.chat.completions.create({ model: 'gpt-5-mini', messages: [{ role: 'user', content: 'Hello!' }], }); console.log(response.choices[0].message.content); ``` **Python** ```python from openai import OpenAI from dotenv import load_dotenv import os load_dotenv() client = OpenAI( api_key=os.environ["NEON_AI_GATEWAY_TOKEN"], base_url=f"{os.environ['NEON_AI_GATEWAY_BASE_URL']}/v1", ) response = client.chat.completions.create( model="gpt-5-mini", messages=[{"role": "user", "content": "Hello!"}], ) print(response.choices[0].message.content) ``` **cURL** ```bash curl -X POST "$NEON_AI_GATEWAY_BASE_URL/v1/chat/completions" \ -H "Authorization: Bearer $NEON_AI_GATEWAY_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "model": "gpt-5-mini", "messages": [{"role": "user", "content": "Hello!"}] }' ``` ## Stream a response Add `stream: true` to receive a streamed response. Your existing streaming code works without changes. The gateway forwards `text/event-stream` responses from the upstream provider. **TypeScript** ```typescript import OpenAI from 'openai'; import 'dotenv/config'; const client = new OpenAI({ apiKey: process.env.NEON_AI_GATEWAY_TOKEN, baseURL: `${process.env.NEON_AI_GATEWAY_BASE_URL}/v1`, }); const stream = await client.chat.completions.create({ model: 'gpt-5-mini', messages: [{ role: 'user', content: 'Write a haiku about serverless databases.' }], stream: true, }); for await (const chunk of stream) { process.stdout.write(chunk.choices[0]?.delta?.content ?? ''); } ``` **Python** ```python from openai import OpenAI from dotenv import load_dotenv import os load_dotenv() client = OpenAI( api_key=os.environ["NEON_AI_GATEWAY_TOKEN"], base_url=f"{os.environ['NEON_AI_GATEWAY_BASE_URL']}/v1", ) with client.chat.completions.create( model="gpt-5-mini", messages=[{"role": "user", "content": "Write a haiku about serverless databases."}], stream=True, ) as stream: for chunk in stream: print(chunk.choices[0].delta.content or "", end="", flush=True) ``` **cURL** ```bash curl -X POST "$NEON_AI_GATEWAY_BASE_URL/v1/chat/completions" \ -H "Authorization: Bearer $NEON_AI_GATEWAY_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "model": "gpt-5-mini", "messages": [{"role": "user", "content": "Write a haiku about serverless databases."}], "stream": true }' ``` ## Swap models Change the `model` field to use a different provider. No other code changes required. ```typescript // OpenAI model: 'gpt-5-mini' // Google model: 'gemini-3-flash' // Alibaba model: 'qwen3-next-80b-a3b-instruct' ``` See [Models](https://neon.com/docs/ai-gateway/models) for the full list of available model IDs. **Using the AI SDK?:** For TypeScript apps and agents, use [`@neon/ai-sdk-provider`](https://www.npmjs.com/package/@neon/ai-sdk-provider) with the Vercel AI SDK. It reads `NEON_AI_GATEWAY_BASE_URL` and `NEON_AI_GATEWAY_TOKEN`, then routes each catalog model to the best AI Gateway endpoint for that provider. ## Next steps - [Models](https://neon.com/docs/ai-gateway/models): full model catalog and which endpoint to use per provider - [Chat completions](https://neon.com/docs/ai-gateway/chat-completions): detailed reference for the unified endpoint - [Authentication](https://neon.com/docs/ai-gateway/authentication): credential scopes, branch binding, and rotation --- [Document source](https://neon.com/docs/ai-gateway/models.md) --- > Summary: Reference for Neon AI Gateway: model access and how to request foundation models, which endpoint to use, shorter and longer request paths, the /v1/models API, rate limits, pricing, and provider terms. # Model reference How to call models through AI Gateway, with the endpoints, limits, and rules that apply Last updated: 2026-11-04 This page covers how to call models through Neon AI Gateway and the rules that apply. For the full list of models you can call, see the [model catalog](https://neon.com/ai-gateway#models). > **See every model on Neon AI Gateway** > > Compare every available model by lab, inputs, context window, and pricing. > > [Browse all models](https://neon.com/ai-gateway#models) Neon AI Gateway serves models from many providers behind one credential. Use short model IDs in the `model` field, for example `gpt-5-mini` or `gemini-3-flash`. The `databricks-` prefixed form is also accepted. The Neon Console and most examples use the short form. **Important:** Most models are served through Databricks. Jev is the exception: TypeSafe AI, which made it, also hosts it. [Provider terms](https://neon.com/docs/ai-gateway/models#provider-terms) links each provider's terms and notes where hosting differs. Wherever a model is hosted, you're responsible for complying with its provider's terms of use. Model availability may vary by region, and the catalog expands over time, so check back for new additions. > AI Gateway is currently available in AWS US East (Ohio) (`aws-us-east-2`), AWS US East (N. Virginia) (`aws-us-east-1`), AWS Europe (Frankfurt) (`aws-eu-central-1`), and AWS Asia Pacific (Singapore) (`aws-ap-southeast-1`). Create your project in one of these regions to use it. Support is expanding toward [all regions](https://neon.com/docs/introduction/regions). It's available on any Neon plan with prepaid credits. See [Pricing](https://neon.com/docs/ai-gateway/models#pricing) for details. The full catalog is served as JSON at [`neon.com/models.json`](https://neon.com/models.json), the machine-readable source of truth, and mirrored as the [`neon` provider on models.dev](https://models.dev/providers/neon). Each model lists its `lab`, the organization that made it, and its `provider`, the organization that provides it: Databricks for every model except Jev, which TypeSafe AI hosts. Both field names follow models.dev. Every model in the catalog carries a `released` boolean. `false` marks a model listed ahead of its announcement: it stays in `neon.com/models.json` and `neon.com/models`, and an app that shows a model list should leave it out: ```js const models = Object.values(catalog.neon.models).filter((model) => model.released); ``` ## Model access Neon AI Gateway gives you one credential for both open-weight and foundation models. Any account with prepaid credits can use every model in the catalog, on any plan. The [model catalog](https://neon.com/docs/ai-gateway/overview#available-models) is always the source of truth for what you can call today. ## Rate limits The following limits apply per account. Input and output tokens are limited separately: | Limit | Value | | ------------------------------ | ------- | | Input tokens per minute (TPM) | 200,000 | | Output tokens per minute (TPM) | 200,000 | If you hit the limit, you'll receive a `429 Too Many Requests` response with a message that starts with `You've exceeded your AI Gateway input token limit for model ""`. Requests resume when the rate limit window resets. The TPM limit applies to input tokens and output tokens separately. Each direction has its own limit, so using up your output allowance doesn't use up your input allowance. Upstream output token limits (20,000 OTPM for most models) apply independently, so you can hit a `429` on output tokens without reaching the gateway's TPM limit. See [Databricks Foundation Model API limits](https://docs.databricks.com/aws/en/machine-learning/foundation-model-apis/limits) for details. Both 200,000 TPM limits are soft limits. If you need a higher limit, [contact Support](https://neon.com/docs/introduction/support). A separate account-level daily spend cap also applies and can block AI Gateway requests with a `429` / `REQUEST_LIMIT_EXCEEDED`. It isn't a fixed published number and can vary by account. See [Pricing](https://neon.com/docs/ai-gateway/models#pricing) for details, or [Troubleshooting](https://neon.com/docs/ai-gateway/troubleshooting#429-account-quota-exceeded) if you hit it. ## Pricing AI Gateway usage draws down a prepaid credit balance. Here's how pricing works: - **Any plan.** AI Gateway is available on every Neon plan, including Free, with no difference in pricing or model access between plans. On the Free plan, you add a payment card to buy credits and your organization stays on Free. Any account with prepaid credits can use every model in the catalog. See [Model access](https://neon.com/docs/ai-gateway/models#model-access) for details. - **No markup.** Neon charges the same per-token rate as the model provider. Published provider prices are passed on to users with no additional markup. - **Prepaid credits.** Inference draws down a prepaid credit balance. 1 credit equals $1 USD, with a $5 minimum purchase, and credits are valid for 12 months from purchase. You buy credits from the **Billing** page in the [Neon Console](https://console.neon.tech/app/billing). See the [model catalog](https://neon.com/docs/ai-gateway/overview#available-models) for per-model rates, and [AI Gateway prepaid credits](https://neon.com/docs/ai-gateway/prepaid-credits) for how to buy credits and manage your balance. Independent of billing, Neon enforces an account-level daily spend cap on AI Gateway usage, separate from the per-minute rate limits above. If your account exceeds it, every AI Gateway endpoint returns `429 Too Many Requests` with error code `REQUEST_LIMIT_EXCEEDED` until the cap resets or the block is lifted. The cap is $20 per day by default, but it may vary by account. To have it raised, [contact Support](https://neon.com/docs/introduction/support). See [Troubleshooting](https://neon.com/docs/ai-gateway/troubleshooting#429-account-quota-exceeded) if you hit this. ## Which endpoint to use Most models work with the [Chat completions](https://neon.com/docs/ai-gateway/chat-completions) endpoint. It is the recommended starting point and works with all providers. Use a provider-specific endpoint when required: All paths below are appended to your branch's bare AI Gateway host (`NEON_AI_GATEWAY_BASE_URL`). | Provider | Recommended endpoint | Notes | | --------------------------------------- | ------------------------ | ------------------------------------------------------------------------------------------------------------------------ | | OpenAI (most models) | `/v1/chat/completions` | Use `/openai/v1/responses` for Responses API features | | OpenAI (`gpt-5-3-codex`, `gpt-5-5-pro`) | `/openai/v1/responses` | These models require the Responses API and don't work with chat/completions | | Anthropic Claude | `/v1/chat/completions` | Use `/anthropic/v1/messages` with the Anthropic SDK for extended thinking and prompt caching | | Google Gemini | `/v1/chat/completions` | Use `/gemini/v1beta/models/{model}:generateContent` with the google-genai SDK | | Google Gemma 3 12B | `/v1/chat/completions` | Chat completions only. Doesn't support the Gemini SDK endpoint | | Meta, Zhipu AI, Moonshot AI | `/v1/chat/completions` | Chat completions only | | Alibaba (chat models) | `/v1/chat/completions` | Chat completions only | | Alibaba, BAAI (embedding models) | `/v1/embeddings` | No chat completions. Returns a vector, not text | | TypeSafe AI (decision models) | `/typesafe/v1/systemone` | No chat completions. Returns answers to questions, not text. See [Decisions](https://neon.com/docs/ai-gateway/decisions) | **Warning: Content shape varies by model** For most models, `message.content` in a chat completions response is a plain string. For `claude-opus-5-5`, it's an array of typed content blocks once the model reasons (`{ type: 'reasoning', ... }`, `{ type: 'text', text: ... }`); a trivial prompt still returns a string. For `gemini-4-argon`, it's an array of `text` blocks, even for a trivial prompt. A low `max_tokens` value can also cut a response off before the `text` block appears, leaving only a `reasoning` block. Handle both shapes: ```typescript // The OpenAI SDK types content as string | null, so read it as unknown. const content: unknown = response.choices[0].message.content; const text = typeof content === 'string' ? content : Array.isArray(content) ? (content.find((block) => block?.type === 'text')?.text ?? '') : ''; ``` ## Shorter paths Each inference dialect is reachable at two equivalent paths: a shorter top-level path (recommended, and what most examples and the `@neon/ai-sdk-provider` use) and a longer `/ai-gateway//v1` path. Both forms behave identically, using the same branch host, bearer token, request body, response body, model routing, rate limits, and quota, and **neither is deprecated**. The longer `/ai-gateway/...` paths keep working indefinitely. The shorter form isn't a uniform `/v1/` rule. The unified chat completions endpoint is a bare `/v1/chat/completions`, matching the OpenAI and OpenRouter convention. The native dialects are prefixed by provider instead, and each keeps its own upstream version segment so the path matches what that provider's SDK expects: `/openai/v1/...`, `/anthropic/v1/...`, and `/gemini/v1beta/...`. Decisions are the exception: they're served only at `/typesafe/v1/systemone`. Use the shorter paths when you want OpenAI/OpenRouter-style URLs. Use the `/ai-gateway/...` paths when a framework or existing Neon example expects the older dialect-specific route. | Shorter path | Equivalent to | | ---------------------------------------------------- | ---------------------------------------------------------- | | `POST /v1/chat/completions` | `/ai-gateway/mlflow/v1/chat/completions` | | `POST /openai/v1/responses` | `/ai-gateway/openai/v1/responses` | | `POST /anthropic/v1/messages` | `/ai-gateway/anthropic/v1/messages` | | `POST /gemini/v1beta/models/{model}:generateContent` | `/ai-gateway/gemini/v1beta/models/{model}:generateContent` | ### List available models `GET /v1/models` lists the model catalog in an OpenRouter-shaped response, authenticated the same way as the endpoints above. Unlike the inference dialects, the model list has only this `/v1/models` path, with no `/ai-gateway/...` form. Decision models are also listed at `GET /typesafe/v1/models`; see [Decisions](https://neon.com/docs/ai-gateway/decisions#list-the-models). ```bash curl "$NEON_AI_GATEWAY_BASE_URL/v1/models" \ -H "Authorization: Bearer $NEON_AI_GATEWAY_TOKEN" ``` ```json { "object": "list", "data": [ { "id": "gpt-5-mini", "canonical_slug": "gpt-5-mini", "name": "GPT-5 Mini", "object": "model", "owned_by": "openai", "created": 0, "enabled": true, "context_length": null, "architecture": { "modality": "text->text", "input_modalities": ["text"], "output_modalities": ["text"], "tokenizer": "GPT", "instruct_type": null }, "top_provider": { "is_moderated": false, "context_length": null, "max_completion_tokens": null }, "pricing": null, "per_request_limits": null } ] } ``` The response returns one object per model. Key fields: - `enabled` is whether the model is currently callable. Any account with prepaid credits can call every model in the catalog. See [Model access](https://neon.com/docs/ai-gateway/models#model-access) for details. - `id`, `name`, and `owned_by` identify the model. Use `id` (or its `databricks-` prefixed form) in the `model` field of a request. - `canonical_slug`, `architecture`, and `top_provider` are OpenRouter-compatible descriptive fields. - `created` is always `0`, and `pricing`, `per_request_limits`, and `context_length` are currently always `null`. Use the [model catalog](https://neon.com/docs/ai-gateway/overview#available-models) for context windows and model details. ### Check what your account can call To list only the models your account can call, filter on `enabled`: ```bash curl "$NEON_AI_GATEWAY_BASE_URL/v1/models" \ -H "Authorization: Bearer $NEON_AI_GATEWAY_TOKEN" \ | jq -r '.data[] | select(.enabled) | .id' ``` ## Provider terms Review a model's provider terms before you use it. You're responsible for complying with them, including any acceptable-use restrictions and license requirements. | Provider | Terms | | ----------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | OpenAI | [OpenAI Usage Policies](https://openai.com/policies/usage-policies) | | Google Gemini | [Google Cloud Acceptable Use Policy](https://cloud.google.com/terms/aup) · [Google Generative AI Prohibited Use Policy](https://policies.google.com/terms/generative-ai/use-policy) | | Google Gemma | [Gemma Terms of Use](https://ai.google.dev/gemma/terms) · [Gemma Prohibited Use Policy](https://ai.google.dev/gemma/prohibited_use_policy) | | Meta | Terms differ by Llama version. See the Notes column in the [models catalog](https://neon.com/docs/ai-gateway/overview#available-models). | | TypeSafe AI (Jev) | [Terms of use](https://typesafe.ai/legal/terms) · [Data processing addendum](https://typesafe.ai/legal/data-processing) · [Privacy policy](https://typesafe.ai/legal/privacy-policy) | Jev is hosted by TypeSafe AI, Inc. and served through Neon AI Gateway. Neon provides access, authentication, and routing, and TypeSafe AI operates the environment the model runs in. OpenJev, the open-weight decision model, is hosted by Databricks. See [Decisions](https://neon.com/docs/ai-gateway/decisions#models). **Important:** Use of AI Gateway is subject to our Terms of Service. Access is not available to users, organizations, or entities located in or operating from regions restricted by Anthropic's [Supported Regions Policy](https://www.anthropic.com/supported-countries). This restriction also applies to entities that are majority owned, directly or indirectly, by companies headquartered in unsupported regions. For what Databricks and model providers retain, see [Data retention](https://neon.com/docs/ai-gateway/data-retention). --- [Document source](https://neon.com/docs/ai-gateway/models/bge-large-en.md) --- # BGE Large (En) ## About Neon AI Gateway provides BGE Large (En) by BAAI. It returns 1024-dimensional embeddings on `POST /v1/embeddings`. ## Command ### Embeddings #### TypeScript Install: ```bash npm i openai ``` ```typescript import OpenAI from "openai"; const client = new OpenAI({ apiKey: process.env.NEON_AI_GATEWAY_TOKEN, baseURL: `${process.env.NEON_AI_GATEWAY_BASE_URL}/v1`, }); const resp = await client.embeddings.create({ model: "bge-large-en", input: ["Explain Serverless Postgres."], encoding_format: "float", }); console.log(resp.data[0].embedding.length, resp.usage); ``` #### Python Install: ```bash pip install openai ``` ```python import os from openai import OpenAI client = OpenAI( api_key=os.environ["NEON_AI_GATEWAY_TOKEN"], base_url=f"{os.environ['NEON_AI_GATEWAY_BASE_URL']}/v1", ) resp = client.embeddings.create( model="bge-large-en", input=["Explain Serverless Postgres."], encoding_format="float", ) print(len(resp.data[0].embedding), resp.usage) ``` #### cURL ```bash curl "${NEON_AI_GATEWAY_BASE_URL}/v1/embeddings" \ -H "Authorization: Bearer ${NEON_AI_GATEWAY_TOKEN}" \ -H "Content-Type: application/json" \ -d '{ "model": "bge-large-en", "input": ["Explain Serverless Postgres."], "encoding_format": "float" }' ``` **Environment variables** ```bash # Injected by `neon env pull` when AI Gateway is enabled on the branch (neon.ts preview.aiGateway). # Neon injects ONLY the NEON_AI_GATEWAY_* vars (not OPENAI_*). Build the OpenAI SDK / curl # apiKey + baseURL from them: apiKey = NEON_AI_GATEWAY_TOKEN (the bearer, nt_live_...). # # NEON_AI_GATEWAY_BASE_URL is the bare gateway host (no path). Append the route you need: # - `/v1` - unified Chat Completions and `/v1/embeddings` # - `/openai/v1` - OpenAI Responses API # - `/typesafe` - TypeSafe SDK base URL for System One decisions (`/typesafe/v1/systemone`) # @neon/ai-sdk-provider and Mastra route requests automatically. NEON_AI_GATEWAY_TOKEN=nt_live_... NEON_AI_GATEWAY_BASE_URL=https://-api.ai....neon.tech ``` ## Model ID bge-large-en ## Lab BAAI makes BGE Large (En). Access it through the Neon AI Gateway's `POST /v1/embeddings` endpoint. ## Provider Databricks ## Dimensions 1024 ## Released Sep 2023 ## Input /M $0.10 --- [Document source](https://neon.com/docs/ai-gateway/models/claude-fable-5-1.md) --- # Claude Fable 5.1 ## About Neon AI Gateway provides Claude Fable 5.1 by Anthropic. The model supports text, image, pdf inputs and a 1M context window. ## Command ### Text generation #### AI SDK Install: ```bash npm i ai @neon/ai-sdk-provider ``` ```typescript import { generateText } from "ai"; import { neon } from "@neon/ai-sdk-provider"; const { text } = await generateText({ model: neon("claude-fable-5-1"), prompt: "Explain Serverless Postgres.", }); console.log(text); ``` #### Mastra Install: ```bash npm i @mastra/core ``` ```typescript import { Agent } from "@mastra/core/agent"; const agent = new Agent({ id: "neon-demo", name: "neon-demo", instructions: "You are a helpful assistant.", model: "neon/claude-fable-5-1", }); const { text } = await agent.generate("Explain Serverless Postgres."); console.log(text); ``` #### TypeScript Install: ```bash npm i openai ``` ```typescript import OpenAI from "openai"; const client = new OpenAI({ apiKey: process.env.NEON_AI_GATEWAY_TOKEN, baseURL: `${process.env.NEON_AI_GATEWAY_BASE_URL}/v1`, }); const resp = await client.chat.completions.create({ model: "claude-fable-5-1", messages: [{ role: "user", content: "Explain Serverless Postgres." }], }); console.log(resp.choices[0].message.content); ``` #### Python Install: ```bash pip install openai ``` ```python import os from openai import OpenAI client = OpenAI( api_key=os.environ["NEON_AI_GATEWAY_TOKEN"], base_url=f"{os.environ['NEON_AI_GATEWAY_BASE_URL']}/v1", ) resp = client.chat.completions.create( model="claude-fable-5-1", messages=[{"role": "user", "content": "Explain Serverless Postgres."}], ) print(resp.choices[0].message.content) ``` #### cURL ```bash curl "${NEON_AI_GATEWAY_BASE_URL}/v1/chat/completions" \ -H "Authorization: Bearer ${NEON_AI_GATEWAY_TOKEN}" \ -H "Content-Type: application/json" \ -d '{ "model": "claude-fable-5-1", "messages": [{"role": "user", "content": "Explain Serverless Postgres."}] }' ``` **Environment variables** ```bash # Injected by `neon env pull` when AI Gateway is enabled on the branch (neon.ts preview.aiGateway). # Neon injects ONLY the NEON_AI_GATEWAY_* vars (not OPENAI_*). Build the OpenAI SDK / curl # apiKey + baseURL from them: apiKey = NEON_AI_GATEWAY_TOKEN (the bearer, nt_live_...). # # NEON_AI_GATEWAY_BASE_URL is the bare gateway host (no path). Append the route you need: # - `/v1` - unified Chat Completions and `/v1/embeddings` # - `/openai/v1` - OpenAI Responses API # - `/typesafe` - TypeSafe SDK base URL for System One decisions (`/typesafe/v1/systemone`) # @neon/ai-sdk-provider and Mastra route requests automatically. NEON_AI_GATEWAY_TOKEN=nt_live_... NEON_AI_GATEWAY_BASE_URL=https://-api.ai....neon.tech ``` ## Model ID claude-fable-5-1 ## Lab Anthropic makes Claude Fable 5.1. Access the model through the Neon AI Gateway using chat/completions and anthropic/messages. ## Provider Databricks ## Inputs Text, image, pdf ## Context 1M ## Released Sep 2026 ## Input /M $10 ## Output /M $50 --- [Document source](https://neon.com/docs/ai-gateway/models/claude-fable-5.md) --- # Claude Fable 5 ## About Neon AI Gateway provides Claude Fable 5 by Anthropic. The model supports text, image, pdf inputs and a 1M context window. ## Command ### Text generation #### AI SDK Install: ```bash npm i ai @neon/ai-sdk-provider ``` ```typescript import { generateText } from "ai"; import { neon } from "@neon/ai-sdk-provider"; const { text } = await generateText({ model: neon("claude-fable-5"), prompt: "Explain Serverless Postgres.", }); console.log(text); ``` #### Mastra Install: ```bash npm i @mastra/core ``` ```typescript import { Agent } from "@mastra/core/agent"; const agent = new Agent({ id: "neon-demo", name: "neon-demo", instructions: "You are a helpful assistant.", model: "neon/claude-fable-5", }); const { text } = await agent.generate("Explain Serverless Postgres."); console.log(text); ``` #### TypeScript Install: ```bash npm i openai ``` ```typescript import OpenAI from "openai"; const client = new OpenAI({ apiKey: process.env.NEON_AI_GATEWAY_TOKEN, baseURL: `${process.env.NEON_AI_GATEWAY_BASE_URL}/v1`, }); const resp = await client.chat.completions.create({ model: "claude-fable-5", messages: [{ role: "user", content: "Explain Serverless Postgres." }], }); console.log(resp.choices[0].message.content); ``` #### Python Install: ```bash pip install openai ``` ```python import os from openai import OpenAI client = OpenAI( api_key=os.environ["NEON_AI_GATEWAY_TOKEN"], base_url=f"{os.environ['NEON_AI_GATEWAY_BASE_URL']}/v1", ) resp = client.chat.completions.create( model="claude-fable-5", messages=[{"role": "user", "content": "Explain Serverless Postgres."}], ) print(resp.choices[0].message.content) ``` #### cURL ```bash curl "${NEON_AI_GATEWAY_BASE_URL}/v1/chat/completions" \ -H "Authorization: Bearer ${NEON_AI_GATEWAY_TOKEN}" \ -H "Content-Type: application/json" \ -d '{ "model": "claude-fable-5", "messages": [{"role": "user", "content": "Explain Serverless Postgres."}] }' ``` **Environment variables** ```bash # Injected by `neon env pull` when AI Gateway is enabled on the branch (neon.ts preview.aiGateway). # Neon injects ONLY the NEON_AI_GATEWAY_* vars (not OPENAI_*). Build the OpenAI SDK / curl # apiKey + baseURL from them: apiKey = NEON_AI_GATEWAY_TOKEN (the bearer, nt_live_...). # # NEON_AI_GATEWAY_BASE_URL is the bare gateway host (no path). Append the route you need: # - `/v1` - unified Chat Completions and `/v1/embeddings` # - `/openai/v1` - OpenAI Responses API # - `/typesafe` - TypeSafe SDK base URL for System One decisions (`/typesafe/v1/systemone`) # @neon/ai-sdk-provider and Mastra route requests automatically. NEON_AI_GATEWAY_TOKEN=nt_live_... NEON_AI_GATEWAY_BASE_URL=https://-api.ai....neon.tech ``` ## Model ID claude-fable-5 ## Lab Anthropic makes Claude Fable 5. Access the model through the Neon AI Gateway using chat/completions and anthropic/messages. ## Provider Databricks ## Inputs Text, image, pdf ## Context 1M ## Released Jun 2026 ## Input /M $10 ## Output /M $50 --- [Document source](https://neon.com/docs/ai-gateway/models/claude-haiku-4-5.md) --- # Claude Haiku 4.5 ## About Neon AI Gateway provides Claude Haiku 4.5 by Anthropic. The model supports text, image, pdf inputs and a 200K context window. ## Command ### Text generation #### AI SDK Install: ```bash npm i ai @neon/ai-sdk-provider ``` ```typescript import { generateText } from "ai"; import { neon } from "@neon/ai-sdk-provider"; const { text } = await generateText({ model: neon("claude-haiku-4-5"), prompt: "Explain Serverless Postgres.", }); console.log(text); ``` #### Mastra Install: ```bash npm i @mastra/core ``` ```typescript import { Agent } from "@mastra/core/agent"; const agent = new Agent({ id: "neon-demo", name: "neon-demo", instructions: "You are a helpful assistant.", model: "neon/claude-haiku-4-5", }); const { text } = await agent.generate("Explain Serverless Postgres."); console.log(text); ``` #### TypeScript Install: ```bash npm i openai ``` ```typescript import OpenAI from "openai"; const client = new OpenAI({ apiKey: process.env.NEON_AI_GATEWAY_TOKEN, baseURL: `${process.env.NEON_AI_GATEWAY_BASE_URL}/v1`, }); const resp = await client.chat.completions.create({ model: "claude-haiku-4-5", messages: [{ role: "user", content: "Explain Serverless Postgres." }], }); console.log(resp.choices[0].message.content); ``` #### Python Install: ```bash pip install openai ``` ```python import os from openai import OpenAI client = OpenAI( api_key=os.environ["NEON_AI_GATEWAY_TOKEN"], base_url=f"{os.environ['NEON_AI_GATEWAY_BASE_URL']}/v1", ) resp = client.chat.completions.create( model="claude-haiku-4-5", messages=[{"role": "user", "content": "Explain Serverless Postgres."}], ) print(resp.choices[0].message.content) ``` #### cURL ```bash curl "${NEON_AI_GATEWAY_BASE_URL}/v1/chat/completions" \ -H "Authorization: Bearer ${NEON_AI_GATEWAY_TOKEN}" \ -H "Content-Type: application/json" \ -d '{ "model": "claude-haiku-4-5", "messages": [{"role": "user", "content": "Explain Serverless Postgres."}] }' ``` **Environment variables** ```bash # Injected by `neon env pull` when AI Gateway is enabled on the branch (neon.ts preview.aiGateway). # Neon injects ONLY the NEON_AI_GATEWAY_* vars (not OPENAI_*). Build the OpenAI SDK / curl # apiKey + baseURL from them: apiKey = NEON_AI_GATEWAY_TOKEN (the bearer, nt_live_...). # # NEON_AI_GATEWAY_BASE_URL is the bare gateway host (no path). Append the route you need: # - `/v1` - unified Chat Completions and `/v1/embeddings` # - `/openai/v1` - OpenAI Responses API # - `/typesafe` - TypeSafe SDK base URL for System One decisions (`/typesafe/v1/systemone`) # @neon/ai-sdk-provider and Mastra route requests automatically. NEON_AI_GATEWAY_TOKEN=nt_live_... NEON_AI_GATEWAY_BASE_URL=https://-api.ai....neon.tech ``` ## Model ID claude-haiku-4-5 ## Lab Anthropic makes Claude Haiku 4.5. Access the model through the Neon AI Gateway using chat/completions and anthropic/messages. ## Provider Databricks ## Inputs Text, image, pdf ## Context 200K ## Released Oct 2025 ## Input /M $1 ## Output /M $5 --- [Document source](https://neon.com/docs/ai-gateway/models/claude-haiku-5-5.md) --- # Claude Haiku 5.5 ## About Neon AI Gateway provides Claude Haiku 5.5 by Anthropic. The model supports text, image, pdf inputs and a 200K context window. ## Command ### Text generation #### AI SDK Install: ```bash npm i ai @neon/ai-sdk-provider ``` ```typescript import { generateText } from "ai"; import { neon } from "@neon/ai-sdk-provider"; const { text } = await generateText({ model: neon("claude-haiku-5-5"), prompt: "Explain Serverless Postgres.", }); console.log(text); ``` #### Mastra Install: ```bash npm i @mastra/core ai @neon/ai-sdk-provider ``` ```typescript import { Agent } from "@mastra/core/agent"; import { neon } from "@neon/ai-sdk-provider"; const agent = new Agent({ id: "neon-demo", name: "neon-demo", instructions: "You are a helpful assistant.", model: neon("claude-haiku-5-5"), }); const { text } = await agent.generate("Explain Serverless Postgres."); console.log(text); ``` #### cURL ```bash curl "${NEON_AI_GATEWAY_BASE_URL}/anthropic/v1/messages" \ -H "Authorization: Bearer ${NEON_AI_GATEWAY_TOKEN}" \ -H "Content-Type: application/json" \ -d '{ "model": "claude-haiku-5-5", "max_tokens": 1024, "messages": [{"role": "user", "content": "Explain Serverless Postgres."}] }' ``` **Environment variables** ```bash # Injected by `neon env pull` when AI Gateway is enabled on the branch (neon.ts preview.aiGateway). # Neon injects ONLY the NEON_AI_GATEWAY_* vars (not OPENAI_*). Build the OpenAI SDK / curl # apiKey + baseURL from them: apiKey = NEON_AI_GATEWAY_TOKEN (the bearer, nt_live_...). # # NEON_AI_GATEWAY_BASE_URL is the bare gateway host (no path). Append the route you need: # - `/v1` - unified Chat Completions and `/v1/embeddings` # - `/openai/v1` - OpenAI Responses API # - `/typesafe` - TypeSafe SDK base URL for System One decisions (`/typesafe/v1/systemone`) # @neon/ai-sdk-provider and Mastra route requests automatically. NEON_AI_GATEWAY_TOKEN=nt_live_... NEON_AI_GATEWAY_BASE_URL=https://-api.ai....neon.tech ``` ## Model ID claude-haiku-5-5 ## Lab Anthropic makes Claude Haiku 5.5. Access the model through the Neon AI Gateway using chat/completions and anthropic/messages. ## Provider Databricks ## Inputs Text, image, pdf ## Context 200K ## Released Oct 2026 ## Input /M $0.10 ## Output /M $0.50 --- [Document source](https://neon.com/docs/ai-gateway/models/claude-opus-4-1.md) --- # Claude Opus 4.1 ## About Neon AI Gateway provides Claude Opus 4.1 by Anthropic. The model supports text, image, pdf inputs and a 200K context window. ## Command ### Text generation #### AI SDK Install: ```bash npm i ai @neon/ai-sdk-provider ``` ```typescript import { generateText } from "ai"; import { neon } from "@neon/ai-sdk-provider"; const { text } = await generateText({ model: neon("claude-opus-4-1"), prompt: "Explain Serverless Postgres.", }); console.log(text); ``` #### Mastra Install: ```bash npm i @mastra/core ``` ```typescript import { Agent } from "@mastra/core/agent"; const agent = new Agent({ id: "neon-demo", name: "neon-demo", instructions: "You are a helpful assistant.", model: "neon/claude-opus-4-1", }); const { text } = await agent.generate("Explain Serverless Postgres."); console.log(text); ``` #### TypeScript Install: ```bash npm i openai ``` ```typescript import OpenAI from "openai"; const client = new OpenAI({ apiKey: process.env.NEON_AI_GATEWAY_TOKEN, baseURL: `${process.env.NEON_AI_GATEWAY_BASE_URL}/v1`, }); const resp = await client.chat.completions.create({ model: "claude-opus-4-1", messages: [{ role: "user", content: "Explain Serverless Postgres." }], }); console.log(resp.choices[0].message.content); ``` #### Python Install: ```bash pip install openai ``` ```python import os from openai import OpenAI client = OpenAI( api_key=os.environ["NEON_AI_GATEWAY_TOKEN"], base_url=f"{os.environ['NEON_AI_GATEWAY_BASE_URL']}/v1", ) resp = client.chat.completions.create( model="claude-opus-4-1", messages=[{"role": "user", "content": "Explain Serverless Postgres."}], ) print(resp.choices[0].message.content) ``` #### cURL ```bash curl "${NEON_AI_GATEWAY_BASE_URL}/v1/chat/completions" \ -H "Authorization: Bearer ${NEON_AI_GATEWAY_TOKEN}" \ -H "Content-Type: application/json" \ -d '{ "model": "claude-opus-4-1", "messages": [{"role": "user", "content": "Explain Serverless Postgres."}] }' ``` **Environment variables** ```bash # Injected by `neon env pull` when AI Gateway is enabled on the branch (neon.ts preview.aiGateway). # Neon injects ONLY the NEON_AI_GATEWAY_* vars (not OPENAI_*). Build the OpenAI SDK / curl # apiKey + baseURL from them: apiKey = NEON_AI_GATEWAY_TOKEN (the bearer, nt_live_...). # # NEON_AI_GATEWAY_BASE_URL is the bare gateway host (no path). Append the route you need: # - `/v1` - unified Chat Completions and `/v1/embeddings` # - `/openai/v1` - OpenAI Responses API # - `/typesafe` - TypeSafe SDK base URL for System One decisions (`/typesafe/v1/systemone`) # @neon/ai-sdk-provider and Mastra route requests automatically. NEON_AI_GATEWAY_TOKEN=nt_live_... NEON_AI_GATEWAY_BASE_URL=https://-api.ai....neon.tech ``` ## Model ID claude-opus-4-1 ## Lab Anthropic makes Claude Opus 4.1. Access the model through the Neon AI Gateway using chat/completions and anthropic/messages. ## Provider Databricks ## Inputs Text, image, pdf ## Context 200K ## Released Aug 2025 ## Input /M $15 ## Output /M $75 --- [Document source](https://neon.com/docs/ai-gateway/models/claude-opus-4-5.md) --- # Claude Opus 4.5 ## About Neon AI Gateway provides Claude Opus 4.5 by Anthropic. The model supports text, image, pdf inputs and a 200K context window. ## Command ### Text generation #### AI SDK Install: ```bash npm i ai @neon/ai-sdk-provider ``` ```typescript import { generateText } from "ai"; import { neon } from "@neon/ai-sdk-provider"; const { text } = await generateText({ model: neon("claude-opus-4-5"), prompt: "Explain Serverless Postgres.", }); console.log(text); ``` #### Mastra Install: ```bash npm i @mastra/core ``` ```typescript import { Agent } from "@mastra/core/agent"; const agent = new Agent({ id: "neon-demo", name: "neon-demo", instructions: "You are a helpful assistant.", model: "neon/claude-opus-4-5", }); const { text } = await agent.generate("Explain Serverless Postgres."); console.log(text); ``` #### TypeScript Install: ```bash npm i openai ``` ```typescript import OpenAI from "openai"; const client = new OpenAI({ apiKey: process.env.NEON_AI_GATEWAY_TOKEN, baseURL: `${process.env.NEON_AI_GATEWAY_BASE_URL}/v1`, }); const resp = await client.chat.completions.create({ model: "claude-opus-4-5", messages: [{ role: "user", content: "Explain Serverless Postgres." }], }); console.log(resp.choices[0].message.content); ``` #### Python Install: ```bash pip install openai ``` ```python import os from openai import OpenAI client = OpenAI( api_key=os.environ["NEON_AI_GATEWAY_TOKEN"], base_url=f"{os.environ['NEON_AI_GATEWAY_BASE_URL']}/v1", ) resp = client.chat.completions.create( model="claude-opus-4-5", messages=[{"role": "user", "content": "Explain Serverless Postgres."}], ) print(resp.choices[0].message.content) ``` #### cURL ```bash curl "${NEON_AI_GATEWAY_BASE_URL}/v1/chat/completions" \ -H "Authorization: Bearer ${NEON_AI_GATEWAY_TOKEN}" \ -H "Content-Type: application/json" \ -d '{ "model": "claude-opus-4-5", "messages": [{"role": "user", "content": "Explain Serverless Postgres."}] }' ``` **Environment variables** ```bash # Injected by `neon env pull` when AI Gateway is enabled on the branch (neon.ts preview.aiGateway). # Neon injects ONLY the NEON_AI_GATEWAY_* vars (not OPENAI_*). Build the OpenAI SDK / curl # apiKey + baseURL from them: apiKey = NEON_AI_GATEWAY_TOKEN (the bearer, nt_live_...). # # NEON_AI_GATEWAY_BASE_URL is the bare gateway host (no path). Append the route you need: # - `/v1` - unified Chat Completions and `/v1/embeddings` # - `/openai/v1` - OpenAI Responses API # - `/typesafe` - TypeSafe SDK base URL for System One decisions (`/typesafe/v1/systemone`) # @neon/ai-sdk-provider and Mastra route requests automatically. NEON_AI_GATEWAY_TOKEN=nt_live_... NEON_AI_GATEWAY_BASE_URL=https://-api.ai....neon.tech ``` ## Model ID claude-opus-4-5 ## Lab Anthropic makes Claude Opus 4.5. Access the model through the Neon AI Gateway using chat/completions and anthropic/messages. ## Provider Databricks ## Inputs Text, image, pdf ## Context 200K ## Released Nov 2025 ## Input /M $5 ## Output /M $25 --- [Document source](https://neon.com/docs/ai-gateway/models/claude-opus-4-6.md) --- # Claude Opus 4.6 ## About Neon AI Gateway provides Claude Opus 4.6 by Anthropic. The model supports text, image, pdf inputs and a 1M context window. ## Command ### Text generation #### AI SDK Install: ```bash npm i ai @neon/ai-sdk-provider ``` ```typescript import { generateText } from "ai"; import { neon } from "@neon/ai-sdk-provider"; const { text } = await generateText({ model: neon("claude-opus-4-6"), prompt: "Explain Serverless Postgres.", }); console.log(text); ``` #### Mastra Install: ```bash npm i @mastra/core ``` ```typescript import { Agent } from "@mastra/core/agent"; const agent = new Agent({ id: "neon-demo", name: "neon-demo", instructions: "You are a helpful assistant.", model: "neon/claude-opus-4-6", }); const { text } = await agent.generate("Explain Serverless Postgres."); console.log(text); ``` #### TypeScript Install: ```bash npm i openai ``` ```typescript import OpenAI from "openai"; const client = new OpenAI({ apiKey: process.env.NEON_AI_GATEWAY_TOKEN, baseURL: `${process.env.NEON_AI_GATEWAY_BASE_URL}/v1`, }); const resp = await client.chat.completions.create({ model: "claude-opus-4-6", messages: [{ role: "user", content: "Explain Serverless Postgres." }], }); console.log(resp.choices[0].message.content); ``` #### Python Install: ```bash pip install openai ``` ```python import os from openai import OpenAI client = OpenAI( api_key=os.environ["NEON_AI_GATEWAY_TOKEN"], base_url=f"{os.environ['NEON_AI_GATEWAY_BASE_URL']}/v1", ) resp = client.chat.completions.create( model="claude-opus-4-6", messages=[{"role": "user", "content": "Explain Serverless Postgres."}], ) print(resp.choices[0].message.content) ``` #### cURL ```bash curl "${NEON_AI_GATEWAY_BASE_URL}/v1/chat/completions" \ -H "Authorization: Bearer ${NEON_AI_GATEWAY_TOKEN}" \ -H "Content-Type: application/json" \ -d '{ "model": "claude-opus-4-6", "messages": [{"role": "user", "content": "Explain Serverless Postgres."}] }' ``` **Environment variables** ```bash # Injected by `neon env pull` when AI Gateway is enabled on the branch (neon.ts preview.aiGateway). # Neon injects ONLY the NEON_AI_GATEWAY_* vars (not OPENAI_*). Build the OpenAI SDK / curl # apiKey + baseURL from them: apiKey = NEON_AI_GATEWAY_TOKEN (the bearer, nt_live_...). # # NEON_AI_GATEWAY_BASE_URL is the bare gateway host (no path). Append the route you need: # - `/v1` - unified Chat Completions and `/v1/embeddings` # - `/openai/v1` - OpenAI Responses API # - `/typesafe` - TypeSafe SDK base URL for System One decisions (`/typesafe/v1/systemone`) # @neon/ai-sdk-provider and Mastra route requests automatically. NEON_AI_GATEWAY_TOKEN=nt_live_... NEON_AI_GATEWAY_BASE_URL=https://-api.ai....neon.tech ``` ## Model ID claude-opus-4-6 ## Lab Anthropic makes Claude Opus 4.6. Access the model through the Neon AI Gateway using chat/completions and anthropic/messages. ## Provider Databricks ## Inputs Text, image, pdf ## Context 1M ## Released Feb 2026 ## Input /M $5 ## Output /M $25 --- [Document source](https://neon.com/docs/ai-gateway/models/claude-opus-4-7.md) --- # Claude Opus 4.7 ## About Neon AI Gateway provides Claude Opus 4.7 by Anthropic. The model supports text, image, pdf inputs and a 1M context window. ## Command ### Text generation #### AI SDK Install: ```bash npm i ai @neon/ai-sdk-provider ``` ```typescript import { generateText } from "ai"; import { neon } from "@neon/ai-sdk-provider"; const { text } = await generateText({ model: neon("claude-opus-4-7"), prompt: "Explain Serverless Postgres.", }); console.log(text); ``` #### Mastra Install: ```bash npm i @mastra/core ``` ```typescript import { Agent } from "@mastra/core/agent"; const agent = new Agent({ id: "neon-demo", name: "neon-demo", instructions: "You are a helpful assistant.", model: "neon/claude-opus-4-7", }); const { text } = await agent.generate("Explain Serverless Postgres."); console.log(text); ``` #### TypeScript Install: ```bash npm i openai ``` ```typescript import OpenAI from "openai"; const client = new OpenAI({ apiKey: process.env.NEON_AI_GATEWAY_TOKEN, baseURL: `${process.env.NEON_AI_GATEWAY_BASE_URL}/v1`, }); const resp = await client.chat.completions.create({ model: "claude-opus-4-7", messages: [{ role: "user", content: "Explain Serverless Postgres." }], }); console.log(resp.choices[0].message.content); ``` #### Python Install: ```bash pip install openai ``` ```python import os from openai import OpenAI client = OpenAI( api_key=os.environ["NEON_AI_GATEWAY_TOKEN"], base_url=f"{os.environ['NEON_AI_GATEWAY_BASE_URL']}/v1", ) resp = client.chat.completions.create( model="claude-opus-4-7", messages=[{"role": "user", "content": "Explain Serverless Postgres."}], ) print(resp.choices[0].message.content) ``` #### cURL ```bash curl "${NEON_AI_GATEWAY_BASE_URL}/v1/chat/completions" \ -H "Authorization: Bearer ${NEON_AI_GATEWAY_TOKEN}" \ -H "Content-Type: application/json" \ -d '{ "model": "claude-opus-4-7", "messages": [{"role": "user", "content": "Explain Serverless Postgres."}] }' ``` **Environment variables** ```bash # Injected by `neon env pull` when AI Gateway is enabled on the branch (neon.ts preview.aiGateway). # Neon injects ONLY the NEON_AI_GATEWAY_* vars (not OPENAI_*). Build the OpenAI SDK / curl # apiKey + baseURL from them: apiKey = NEON_AI_GATEWAY_TOKEN (the bearer, nt_live_...). # # NEON_AI_GATEWAY_BASE_URL is the bare gateway host (no path). Append the route you need: # - `/v1` - unified Chat Completions and `/v1/embeddings` # - `/openai/v1` - OpenAI Responses API # - `/typesafe` - TypeSafe SDK base URL for System One decisions (`/typesafe/v1/systemone`) # @neon/ai-sdk-provider and Mastra route requests automatically. NEON_AI_GATEWAY_TOKEN=nt_live_... NEON_AI_GATEWAY_BASE_URL=https://-api.ai....neon.tech ``` ## Model ID claude-opus-4-7 ## Lab Anthropic makes Claude Opus 4.7. Access the model through the Neon AI Gateway using chat/completions and anthropic/messages. ## Provider Databricks ## Inputs Text, image, pdf ## Context 1M ## Released Apr 2026 ## Input /M $5 ## Output /M $25 --- [Document source](https://neon.com/docs/ai-gateway/models/claude-opus-4-8.md) --- # Claude Opus 4.8 ## About Neon AI Gateway provides Claude Opus 4.8 by Anthropic. The model supports text, image, pdf inputs and a 1M context window. ## Command ### Text generation #### AI SDK Install: ```bash npm i ai @neon/ai-sdk-provider ``` ```typescript import { generateText } from "ai"; import { neon } from "@neon/ai-sdk-provider"; const { text } = await generateText({ model: neon("claude-opus-4-8"), prompt: "Explain Serverless Postgres.", }); console.log(text); ``` #### Mastra Install: ```bash npm i @mastra/core ``` ```typescript import { Agent } from "@mastra/core/agent"; const agent = new Agent({ id: "neon-demo", name: "neon-demo", instructions: "You are a helpful assistant.", model: "neon/claude-opus-4-8", }); const { text } = await agent.generate("Explain Serverless Postgres."); console.log(text); ``` #### TypeScript Install: ```bash npm i openai ``` ```typescript import OpenAI from "openai"; const client = new OpenAI({ apiKey: process.env.NEON_AI_GATEWAY_TOKEN, baseURL: `${process.env.NEON_AI_GATEWAY_BASE_URL}/v1`, }); const resp = await client.chat.completions.create({ model: "claude-opus-4-8", messages: [{ role: "user", content: "Explain Serverless Postgres." }], }); console.log(resp.choices[0].message.content); ``` #### Python Install: ```bash pip install openai ``` ```python import os from openai import OpenAI client = OpenAI( api_key=os.environ["NEON_AI_GATEWAY_TOKEN"], base_url=f"{os.environ['NEON_AI_GATEWAY_BASE_URL']}/v1", ) resp = client.chat.completions.create( model="claude-opus-4-8", messages=[{"role": "user", "content": "Explain Serverless Postgres."}], ) print(resp.choices[0].message.content) ``` #### cURL ```bash curl "${NEON_AI_GATEWAY_BASE_URL}/v1/chat/completions" \ -H "Authorization: Bearer ${NEON_AI_GATEWAY_TOKEN}" \ -H "Content-Type: application/json" \ -d '{ "model": "claude-opus-4-8", "messages": [{"role": "user", "content": "Explain Serverless Postgres."}] }' ``` **Environment variables** ```bash # Injected by `neon env pull` when AI Gateway is enabled on the branch (neon.ts preview.aiGateway). # Neon injects ONLY the NEON_AI_GATEWAY_* vars (not OPENAI_*). Build the OpenAI SDK / curl # apiKey + baseURL from them: apiKey = NEON_AI_GATEWAY_TOKEN (the bearer, nt_live_...). # # NEON_AI_GATEWAY_BASE_URL is the bare gateway host (no path). Append the route you need: # - `/v1` - unified Chat Completions and `/v1/embeddings` # - `/openai/v1` - OpenAI Responses API # - `/typesafe` - TypeSafe SDK base URL for System One decisions (`/typesafe/v1/systemone`) # @neon/ai-sdk-provider and Mastra route requests automatically. NEON_AI_GATEWAY_TOKEN=nt_live_... NEON_AI_GATEWAY_BASE_URL=https://-api.ai....neon.tech ``` ## Model ID claude-opus-4-8 ## Lab Anthropic makes Claude Opus 4.8. Access the model through the Neon AI Gateway using chat/completions and anthropic/messages. ## Provider Databricks ## Inputs Text, image, pdf ## Context 1M ## Released May 2026 ## Input /M $5 ## Output /M $25 --- [Document source](https://neon.com/docs/ai-gateway/models/claude-opus-5-5.md) --- # Claude Opus 5.5 ## About Neon AI Gateway provides Claude Opus 5.5 by Anthropic. The model supports text, image, pdf inputs and a 1M context window. ## Command ### Text generation #### AI SDK Install: ```bash npm i ai @neon/ai-sdk-provider ``` ```typescript import { generateText } from "ai"; import { neon } from "@neon/ai-sdk-provider"; const { text } = await generateText({ model: neon("claude-opus-5-5"), prompt: "Explain Serverless Postgres.", }); console.log(text); ``` #### Mastra Install: ```bash npm i @mastra/core ai @neon/ai-sdk-provider ``` ```typescript import { Agent } from "@mastra/core/agent"; import { neon } from "@neon/ai-sdk-provider"; const agent = new Agent({ id: "neon-demo", name: "neon-demo", instructions: "You are a helpful assistant.", model: neon("claude-opus-5-5"), }); const { text } = await agent.generate("Explain Serverless Postgres."); console.log(text); ``` #### cURL ```bash curl "${NEON_AI_GATEWAY_BASE_URL}/anthropic/v1/messages" \ -H "Authorization: Bearer ${NEON_AI_GATEWAY_TOKEN}" \ -H "Content-Type: application/json" \ -d '{ "model": "claude-opus-5-5", "max_tokens": 1024, "messages": [{"role": "user", "content": "Explain Serverless Postgres."}] }' ``` **Environment variables** ```bash # Injected by `neon env pull` when AI Gateway is enabled on the branch (neon.ts preview.aiGateway). # Neon injects ONLY the NEON_AI_GATEWAY_* vars (not OPENAI_*). Build the OpenAI SDK / curl # apiKey + baseURL from them: apiKey = NEON_AI_GATEWAY_TOKEN (the bearer, nt_live_...). # # NEON_AI_GATEWAY_BASE_URL is the bare gateway host (no path). Append the route you need: # - `/v1` - unified Chat Completions and `/v1/embeddings` # - `/openai/v1` - OpenAI Responses API # - `/typesafe` - TypeSafe SDK base URL for System One decisions (`/typesafe/v1/systemone`) # @neon/ai-sdk-provider and Mastra route requests automatically. NEON_AI_GATEWAY_TOKEN=nt_live_... NEON_AI_GATEWAY_BASE_URL=https://-api.ai....neon.tech ``` ## Model ID claude-opus-5-5 ## Lab Anthropic makes Claude Opus 5.5. Access the model through the Neon AI Gateway using chat/completions and anthropic/messages. ## Provider Databricks ## Inputs Text, image, pdf ## Context 1M ## Released Sep 2026 ## Input /M $4 ## Output /M $20 --- [Document source](https://neon.com/docs/ai-gateway/models/claude-opus-5.md) --- # Claude Opus 5 ## About Neon AI Gateway provides Claude Opus 5 by Anthropic. The model supports text, image, pdf inputs and a 1M context window. ## Command ### Text generation #### AI SDK Install: ```bash npm i ai @neon/ai-sdk-provider ``` ```typescript import { generateText } from "ai"; import { neon } from "@neon/ai-sdk-provider"; const { text } = await generateText({ model: neon("claude-opus-5"), prompt: "Explain Serverless Postgres.", }); console.log(text); ``` #### Mastra Install: ```bash npm i @mastra/core ``` ```typescript import { Agent } from "@mastra/core/agent"; const agent = new Agent({ id: "neon-demo", name: "neon-demo", instructions: "You are a helpful assistant.", model: "neon/claude-opus-5", }); const { text } = await agent.generate("Explain Serverless Postgres."); console.log(text); ``` #### TypeScript Install: ```bash npm i openai ``` ```typescript import OpenAI from "openai"; const client = new OpenAI({ apiKey: process.env.NEON_AI_GATEWAY_TOKEN, baseURL: `${process.env.NEON_AI_GATEWAY_BASE_URL}/v1`, }); const resp = await client.chat.completions.create({ model: "claude-opus-5", messages: [{ role: "user", content: "Explain Serverless Postgres." }], }); console.log(resp.choices[0].message.content); ``` #### Python Install: ```bash pip install openai ``` ```python import os from openai import OpenAI client = OpenAI( api_key=os.environ["NEON_AI_GATEWAY_TOKEN"], base_url=f"{os.environ['NEON_AI_GATEWAY_BASE_URL']}/v1", ) resp = client.chat.completions.create( model="claude-opus-5", messages=[{"role": "user", "content": "Explain Serverless Postgres."}], ) print(resp.choices[0].message.content) ``` #### cURL ```bash curl "${NEON_AI_GATEWAY_BASE_URL}/v1/chat/completions" \ -H "Authorization: Bearer ${NEON_AI_GATEWAY_TOKEN}" \ -H "Content-Type: application/json" \ -d '{ "model": "claude-opus-5", "messages": [{"role": "user", "content": "Explain Serverless Postgres."}] }' ``` **Environment variables** ```bash # Injected by `neon env pull` when AI Gateway is enabled on the branch (neon.ts preview.aiGateway). # Neon injects ONLY the NEON_AI_GATEWAY_* vars (not OPENAI_*). Build the OpenAI SDK / curl # apiKey + baseURL from them: apiKey = NEON_AI_GATEWAY_TOKEN (the bearer, nt_live_...). # # NEON_AI_GATEWAY_BASE_URL is the bare gateway host (no path). Append the route you need: # - `/v1` - unified Chat Completions and `/v1/embeddings` # - `/openai/v1` - OpenAI Responses API # - `/typesafe` - TypeSafe SDK base URL for System One decisions (`/typesafe/v1/systemone`) # @neon/ai-sdk-provider and Mastra route requests automatically. NEON_AI_GATEWAY_TOKEN=nt_live_... NEON_AI_GATEWAY_BASE_URL=https://-api.ai....neon.tech ``` ## Model ID claude-opus-5 ## Lab Anthropic makes Claude Opus 5. Access the model through the Neon AI Gateway using chat/completions and anthropic/messages. ## Provider Databricks ## Inputs Text, image, pdf ## Context 1M ## Released Jul 2026 ## Input /M $5 ## Output /M $25 --- [Document source](https://neon.com/docs/ai-gateway/models/claude-sonnet-4-5.md) --- # Claude Sonnet 4.5 ## About Neon AI Gateway provides Claude Sonnet 4.5 by Anthropic. The model supports text, image, pdf inputs and a 200K context window. ## Command ### Text generation #### AI SDK Install: ```bash npm i ai @neon/ai-sdk-provider ``` ```typescript import { generateText } from "ai"; import { neon } from "@neon/ai-sdk-provider"; const { text } = await generateText({ model: neon("claude-sonnet-4-5"), prompt: "Explain Serverless Postgres.", }); console.log(text); ``` #### Mastra Install: ```bash npm i @mastra/core ``` ```typescript import { Agent } from "@mastra/core/agent"; const agent = new Agent({ id: "neon-demo", name: "neon-demo", instructions: "You are a helpful assistant.", model: "neon/claude-sonnet-4-5", }); const { text } = await agent.generate("Explain Serverless Postgres."); console.log(text); ``` #### TypeScript Install: ```bash npm i openai ``` ```typescript import OpenAI from "openai"; const client = new OpenAI({ apiKey: process.env.NEON_AI_GATEWAY_TOKEN, baseURL: `${process.env.NEON_AI_GATEWAY_BASE_URL}/v1`, }); const resp = await client.chat.completions.create({ model: "claude-sonnet-4-5", messages: [{ role: "user", content: "Explain Serverless Postgres." }], }); console.log(resp.choices[0].message.content); ``` #### Python Install: ```bash pip install openai ``` ```python import os from openai import OpenAI client = OpenAI( api_key=os.environ["NEON_AI_GATEWAY_TOKEN"], base_url=f"{os.environ['NEON_AI_GATEWAY_BASE_URL']}/v1", ) resp = client.chat.completions.create( model="claude-sonnet-4-5", messages=[{"role": "user", "content": "Explain Serverless Postgres."}], ) print(resp.choices[0].message.content) ``` #### cURL ```bash curl "${NEON_AI_GATEWAY_BASE_URL}/v1/chat/completions" \ -H "Authorization: Bearer ${NEON_AI_GATEWAY_TOKEN}" \ -H "Content-Type: application/json" \ -d '{ "model": "claude-sonnet-4-5", "messages": [{"role": "user", "content": "Explain Serverless Postgres."}] }' ``` **Environment variables** ```bash # Injected by `neon env pull` when AI Gateway is enabled on the branch (neon.ts preview.aiGateway). # Neon injects ONLY the NEON_AI_GATEWAY_* vars (not OPENAI_*). Build the OpenAI SDK / curl # apiKey + baseURL from them: apiKey = NEON_AI_GATEWAY_TOKEN (the bearer, nt_live_...). # # NEON_AI_GATEWAY_BASE_URL is the bare gateway host (no path). Append the route you need: # - `/v1` - unified Chat Completions and `/v1/embeddings` # - `/openai/v1` - OpenAI Responses API # - `/typesafe` - TypeSafe SDK base URL for System One decisions (`/typesafe/v1/systemone`) # @neon/ai-sdk-provider and Mastra route requests automatically. NEON_AI_GATEWAY_TOKEN=nt_live_... NEON_AI_GATEWAY_BASE_URL=https://-api.ai....neon.tech ``` ## Model ID claude-sonnet-4-5 ## Lab Anthropic makes Claude Sonnet 4.5. Access the model through the Neon AI Gateway using chat/completions and anthropic/messages. ## Provider Databricks ## Inputs Text, image, pdf ## Context 200K ## Released Sep 2025 ## Input /M $3 ## Output /M $15 --- [Document source](https://neon.com/docs/ai-gateway/models/claude-sonnet-4-6.md) --- # Claude Sonnet 4.6 ## About Neon AI Gateway provides Claude Sonnet 4.6 by Anthropic. The model supports text, image, pdf inputs and a 1M context window. ## Command ### Text generation #### AI SDK Install: ```bash npm i ai @neon/ai-sdk-provider ``` ```typescript import { generateText } from "ai"; import { neon } from "@neon/ai-sdk-provider"; const { text } = await generateText({ model: neon("claude-sonnet-4-6"), prompt: "Explain Serverless Postgres.", }); console.log(text); ``` #### Mastra Install: ```bash npm i @mastra/core ``` ```typescript import { Agent } from "@mastra/core/agent"; const agent = new Agent({ id: "neon-demo", name: "neon-demo", instructions: "You are a helpful assistant.", model: "neon/claude-sonnet-4-6", }); const { text } = await agent.generate("Explain Serverless Postgres."); console.log(text); ``` #### TypeScript Install: ```bash npm i openai ``` ```typescript import OpenAI from "openai"; const client = new OpenAI({ apiKey: process.env.NEON_AI_GATEWAY_TOKEN, baseURL: `${process.env.NEON_AI_GATEWAY_BASE_URL}/v1`, }); const resp = await client.chat.completions.create({ model: "claude-sonnet-4-6", messages: [{ role: "user", content: "Explain Serverless Postgres." }], }); console.log(resp.choices[0].message.content); ``` #### Python Install: ```bash pip install openai ``` ```python import os from openai import OpenAI client = OpenAI( api_key=os.environ["NEON_AI_GATEWAY_TOKEN"], base_url=f"{os.environ['NEON_AI_GATEWAY_BASE_URL']}/v1", ) resp = client.chat.completions.create( model="claude-sonnet-4-6", messages=[{"role": "user", "content": "Explain Serverless Postgres."}], ) print(resp.choices[0].message.content) ``` #### cURL ```bash curl "${NEON_AI_GATEWAY_BASE_URL}/v1/chat/completions" \ -H "Authorization: Bearer ${NEON_AI_GATEWAY_TOKEN}" \ -H "Content-Type: application/json" \ -d '{ "model": "claude-sonnet-4-6", "messages": [{"role": "user", "content": "Explain Serverless Postgres."}] }' ``` **Environment variables** ```bash # Injected by `neon env pull` when AI Gateway is enabled on the branch (neon.ts preview.aiGateway). # Neon injects ONLY the NEON_AI_GATEWAY_* vars (not OPENAI_*). Build the OpenAI SDK / curl # apiKey + baseURL from them: apiKey = NEON_AI_GATEWAY_TOKEN (the bearer, nt_live_...). # # NEON_AI_GATEWAY_BASE_URL is the bare gateway host (no path). Append the route you need: # - `/v1` - unified Chat Completions and `/v1/embeddings` # - `/openai/v1` - OpenAI Responses API # - `/typesafe` - TypeSafe SDK base URL for System One decisions (`/typesafe/v1/systemone`) # @neon/ai-sdk-provider and Mastra route requests automatically. NEON_AI_GATEWAY_TOKEN=nt_live_... NEON_AI_GATEWAY_BASE_URL=https://-api.ai....neon.tech ``` ## Model ID claude-sonnet-4-6 ## Lab Anthropic makes Claude Sonnet 4.6. Access the model through the Neon AI Gateway using chat/completions and anthropic/messages. ## Provider Databricks ## Inputs Text, image, pdf ## Context 1M ## Released Feb 2026 ## Input /M $3 ## Output /M $15 --- [Document source](https://neon.com/docs/ai-gateway/models/claude-sonnet-5-5.md) --- # Claude Sonnet 5.5 ## About Neon AI Gateway provides Claude Sonnet 5.5 by Anthropic. The model supports text, image, pdf inputs and a 1M context window. ## Command ### Text generation #### AI SDK Install: ```bash npm i ai @neon/ai-sdk-provider ``` ```typescript import { generateText } from "ai"; import { neon } from "@neon/ai-sdk-provider"; const { text } = await generateText({ model: neon("claude-sonnet-5-5"), prompt: "Explain Serverless Postgres.", }); console.log(text); ``` #### Mastra Install: ```bash npm i @mastra/core ``` ```typescript import { Agent } from "@mastra/core/agent"; const agent = new Agent({ id: "neon-demo", name: "neon-demo", instructions: "You are a helpful assistant.", model: "neon/claude-sonnet-5-5", }); const { text } = await agent.generate("Explain Serverless Postgres."); console.log(text); ``` #### TypeScript Install: ```bash npm i openai ``` ```typescript import OpenAI from "openai"; const client = new OpenAI({ apiKey: process.env.NEON_AI_GATEWAY_TOKEN, baseURL: `${process.env.NEON_AI_GATEWAY_BASE_URL}/v1`, }); const resp = await client.chat.completions.create({ model: "claude-sonnet-5-5", messages: [{ role: "user", content: "Explain Serverless Postgres." }], }); console.log(resp.choices[0].message.content); ``` #### Python Install: ```bash pip install openai ``` ```python import os from openai import OpenAI client = OpenAI( api_key=os.environ["NEON_AI_GATEWAY_TOKEN"], base_url=f"{os.environ['NEON_AI_GATEWAY_BASE_URL']}/v1", ) resp = client.chat.completions.create( model="claude-sonnet-5-5", messages=[{"role": "user", "content": "Explain Serverless Postgres."}], ) print(resp.choices[0].message.content) ``` #### cURL ```bash curl "${NEON_AI_GATEWAY_BASE_URL}/v1/chat/completions" \ -H "Authorization: Bearer ${NEON_AI_GATEWAY_TOKEN}" \ -H "Content-Type: application/json" \ -d '{ "model": "claude-sonnet-5-5", "messages": [{"role": "user", "content": "Explain Serverless Postgres."}] }' ``` **Environment variables** ```bash # Injected by `neon env pull` when AI Gateway is enabled on the branch (neon.ts preview.aiGateway). # Neon injects ONLY the NEON_AI_GATEWAY_* vars (not OPENAI_*). Build the OpenAI SDK / curl # apiKey + baseURL from them: apiKey = NEON_AI_GATEWAY_TOKEN (the bearer, nt_live_...). # # NEON_AI_GATEWAY_BASE_URL is the bare gateway host (no path). Append the route you need: # - `/v1` - unified Chat Completions and `/v1/embeddings` # - `/openai/v1` - OpenAI Responses API # - `/typesafe` - TypeSafe SDK base URL for System One decisions (`/typesafe/v1/systemone`) # @neon/ai-sdk-provider and Mastra route requests automatically. NEON_AI_GATEWAY_TOKEN=nt_live_... NEON_AI_GATEWAY_BASE_URL=https://-api.ai....neon.tech ``` ## Model ID claude-sonnet-5-5 ## Lab Anthropic makes Claude Sonnet 5.5. Access the model through the Neon AI Gateway using chat/completions and anthropic/messages. ## Provider Databricks ## Inputs Text, image, pdf ## Context 1M ## Released Sep 2026 ## Input /M $2 ## Output /M $10 --- [Document source](https://neon.com/docs/ai-gateway/models/claude-sonnet-5.md) --- # Claude Sonnet 5 ## About Neon AI Gateway provides Claude Sonnet 5 by Anthropic. The model supports text, image, pdf inputs and a 1M context window. ## Command ### Text generation #### AI SDK Install: ```bash npm i ai @neon/ai-sdk-provider ``` ```typescript import { generateText } from "ai"; import { neon } from "@neon/ai-sdk-provider"; const { text } = await generateText({ model: neon("claude-sonnet-5"), prompt: "Explain Serverless Postgres.", }); console.log(text); ``` #### Mastra Install: ```bash npm i @mastra/core ``` ```typescript import { Agent } from "@mastra/core/agent"; const agent = new Agent({ id: "neon-demo", name: "neon-demo", instructions: "You are a helpful assistant.", model: "neon/claude-sonnet-5", }); const { text } = await agent.generate("Explain Serverless Postgres."); console.log(text); ``` #### TypeScript Install: ```bash npm i openai ``` ```typescript import OpenAI from "openai"; const client = new OpenAI({ apiKey: process.env.NEON_AI_GATEWAY_TOKEN, baseURL: `${process.env.NEON_AI_GATEWAY_BASE_URL}/v1`, }); const resp = await client.chat.completions.create({ model: "claude-sonnet-5", messages: [{ role: "user", content: "Explain Serverless Postgres." }], }); console.log(resp.choices[0].message.content); ``` #### Python Install: ```bash pip install openai ``` ```python import os from openai import OpenAI client = OpenAI( api_key=os.environ["NEON_AI_GATEWAY_TOKEN"], base_url=f"{os.environ['NEON_AI_GATEWAY_BASE_URL']}/v1", ) resp = client.chat.completions.create( model="claude-sonnet-5", messages=[{"role": "user", "content": "Explain Serverless Postgres."}], ) print(resp.choices[0].message.content) ``` #### cURL ```bash curl "${NEON_AI_GATEWAY_BASE_URL}/v1/chat/completions" \ -H "Authorization: Bearer ${NEON_AI_GATEWAY_TOKEN}" \ -H "Content-Type: application/json" \ -d '{ "model": "claude-sonnet-5", "messages": [{"role": "user", "content": "Explain Serverless Postgres."}] }' ``` **Environment variables** ```bash # Injected by `neon env pull` when AI Gateway is enabled on the branch (neon.ts preview.aiGateway). # Neon injects ONLY the NEON_AI_GATEWAY_* vars (not OPENAI_*). Build the OpenAI SDK / curl # apiKey + baseURL from them: apiKey = NEON_AI_GATEWAY_TOKEN (the bearer, nt_live_...). # # NEON_AI_GATEWAY_BASE_URL is the bare gateway host (no path). Append the route you need: # - `/v1` - unified Chat Completions and `/v1/embeddings` # - `/openai/v1` - OpenAI Responses API # - `/typesafe` - TypeSafe SDK base URL for System One decisions (`/typesafe/v1/systemone`) # @neon/ai-sdk-provider and Mastra route requests automatically. NEON_AI_GATEWAY_TOKEN=nt_live_... NEON_AI_GATEWAY_BASE_URL=https://-api.ai....neon.tech ``` ## Model ID claude-sonnet-5 ## Lab Anthropic makes Claude Sonnet 5. Access the model through the Neon AI Gateway using chat/completions and anthropic/messages. ## Provider Databricks ## Inputs Text, image, pdf ## Context 1M ## Released Jun 2026 ## Input /M $2 ## Output /M $10 --- [Document source](https://neon.com/docs/ai-gateway/models/deepseek-v4-1-flash.md) --- # DeepSeek V4.1 Flash ## About Neon AI Gateway provides DeepSeek V4.1 Flash by DeepSeek. The model supports text, image inputs and a 128K context window. ## Command ### Text generation #### AI SDK Install: ```bash npm i ai @neon/ai-sdk-provider ``` ```typescript import { generateText } from "ai"; import { neon } from "@neon/ai-sdk-provider"; const { text } = await generateText({ model: neon("deepseek-v4-1-flash"), prompt: "Explain Serverless Postgres.", }); console.log(text); ``` #### Mastra Install: ```bash npm i @mastra/core ``` ```typescript import { Agent } from "@mastra/core/agent"; const agent = new Agent({ id: "neon-demo", name: "neon-demo", instructions: "You are a helpful assistant.", model: "neon/deepseek-v4-1-flash", }); const { text } = await agent.generate("Explain Serverless Postgres."); console.log(text); ``` #### TypeScript Install: ```bash npm i openai ``` ```typescript import OpenAI from "openai"; const client = new OpenAI({ apiKey: process.env.NEON_AI_GATEWAY_TOKEN, baseURL: `${process.env.NEON_AI_GATEWAY_BASE_URL}/v1`, }); const resp = await client.chat.completions.create({ model: "deepseek-v4-1-flash", messages: [{ role: "user", content: "Explain Serverless Postgres." }], }); console.log(resp.choices[0].message.content); ``` #### Python Install: ```bash pip install openai ``` ```python import os from openai import OpenAI client = OpenAI( api_key=os.environ["NEON_AI_GATEWAY_TOKEN"], base_url=f"{os.environ['NEON_AI_GATEWAY_BASE_URL']}/v1", ) resp = client.chat.completions.create( model="deepseek-v4-1-flash", messages=[{"role": "user", "content": "Explain Serverless Postgres."}], ) print(resp.choices[0].message.content) ``` #### cURL ```bash curl "${NEON_AI_GATEWAY_BASE_URL}/v1/chat/completions" \ -H "Authorization: Bearer ${NEON_AI_GATEWAY_TOKEN}" \ -H "Content-Type: application/json" \ -d '{ "model": "deepseek-v4-1-flash", "messages": [{"role": "user", "content": "Explain Serverless Postgres."}] }' ``` **Environment variables** ```bash # Injected by `neon env pull` when AI Gateway is enabled on the branch (neon.ts preview.aiGateway). # Neon injects ONLY the NEON_AI_GATEWAY_* vars (not OPENAI_*). Build the OpenAI SDK / curl # apiKey + baseURL from them: apiKey = NEON_AI_GATEWAY_TOKEN (the bearer, nt_live_...). # # NEON_AI_GATEWAY_BASE_URL is the bare gateway host (no path). Append the route you need: # - `/v1` - unified Chat Completions and `/v1/embeddings` # - `/openai/v1` - OpenAI Responses API # - `/typesafe` - TypeSafe SDK base URL for System One decisions (`/typesafe/v1/systemone`) # @neon/ai-sdk-provider and Mastra route requests automatically. NEON_AI_GATEWAY_TOKEN=nt_live_... NEON_AI_GATEWAY_BASE_URL=https://-api.ai....neon.tech ``` ## Model ID deepseek-v4-1-flash ## Lab DeepSeek makes DeepSeek V4.1 Flash. Access the model through the Neon AI Gateway using chat/completions. ## Provider Databricks ## Inputs Text, image ## Context 128K ## Released Sep 2026 ## Input /M $0.30 ## Output /M $1.20 --- [Document source](https://neon.com/docs/ai-gateway/models/gemini-3-1-flash-lite.md) --- # Gemini 3.1 Flash Lite ## About Neon AI Gateway provides Gemini 3.1 Flash Lite by Google. The model supports text, image, video, audio, pdf inputs and a 1M context window. ## Command ### Text generation #### AI SDK Install: ```bash npm i ai @neon/ai-sdk-provider ``` ```typescript import { generateText } from "ai"; import { neon } from "@neon/ai-sdk-provider"; const { text } = await generateText({ model: neon("gemini-3-1-flash-lite"), prompt: "Explain Serverless Postgres.", }); console.log(text); ``` #### Mastra Install: ```bash npm i @mastra/core ``` ```typescript import { Agent } from "@mastra/core/agent"; const agent = new Agent({ id: "neon-demo", name: "neon-demo", instructions: "You are a helpful assistant.", model: "neon/gemini-3-1-flash-lite", }); const { text } = await agent.generate("Explain Serverless Postgres."); console.log(text); ``` #### TypeScript Install: ```bash npm i openai ``` ```typescript import OpenAI from "openai"; const client = new OpenAI({ apiKey: process.env.NEON_AI_GATEWAY_TOKEN, baseURL: `${process.env.NEON_AI_GATEWAY_BASE_URL}/v1`, }); const resp = await client.chat.completions.create({ model: "gemini-3-1-flash-lite", messages: [{ role: "user", content: "Explain Serverless Postgres." }], }); console.log(resp.choices[0].message.content); ``` #### Python Install: ```bash pip install openai ``` ```python import os from openai import OpenAI client = OpenAI( api_key=os.environ["NEON_AI_GATEWAY_TOKEN"], base_url=f"{os.environ['NEON_AI_GATEWAY_BASE_URL']}/v1", ) resp = client.chat.completions.create( model="gemini-3-1-flash-lite", messages=[{"role": "user", "content": "Explain Serverless Postgres."}], ) print(resp.choices[0].message.content) ``` #### cURL ```bash curl "${NEON_AI_GATEWAY_BASE_URL}/v1/chat/completions" \ -H "Authorization: Bearer ${NEON_AI_GATEWAY_TOKEN}" \ -H "Content-Type: application/json" \ -d '{ "model": "gemini-3-1-flash-lite", "messages": [{"role": "user", "content": "Explain Serverless Postgres."}] }' ``` **Environment variables** ```bash # Injected by `neon env pull` when AI Gateway is enabled on the branch (neon.ts preview.aiGateway). # Neon injects ONLY the NEON_AI_GATEWAY_* vars (not OPENAI_*). Build the OpenAI SDK / curl # apiKey + baseURL from them: apiKey = NEON_AI_GATEWAY_TOKEN (the bearer, nt_live_...). # # NEON_AI_GATEWAY_BASE_URL is the bare gateway host (no path). Append the route you need: # - `/v1` - unified Chat Completions and `/v1/embeddings` # - `/openai/v1` - OpenAI Responses API # - `/typesafe` - TypeSafe SDK base URL for System One decisions (`/typesafe/v1/systemone`) # @neon/ai-sdk-provider and Mastra route requests automatically. NEON_AI_GATEWAY_TOKEN=nt_live_... NEON_AI_GATEWAY_BASE_URL=https://-api.ai....neon.tech ``` ## Model ID gemini-3-1-flash-lite ## Lab Google makes Gemini 3.1 Flash Lite. Access the model through the Neon AI Gateway using chat/completions and gemini. ## Provider Databricks ## Inputs Text, image, video, audio, pdf ## Context 1M ## Released Mar 2026 ## Input /M $0.25 ## Output /M $1.50 --- [Document source](https://neon.com/docs/ai-gateway/models/gemini-3-1-pro.md) --- # Gemini 3.1 Pro ## About Neon AI Gateway provides Gemini 3.1 Pro by Google. The model supports text, image, video, audio, pdf inputs and a 1M context window. ## Command ### Text generation #### AI SDK Install: ```bash npm i ai @neon/ai-sdk-provider ``` ```typescript import { generateText } from "ai"; import { neon } from "@neon/ai-sdk-provider"; const { text } = await generateText({ model: neon("gemini-3-1-pro"), prompt: "Explain Serverless Postgres.", }); console.log(text); ``` #### Mastra Install: ```bash npm i @mastra/core ``` ```typescript import { Agent } from "@mastra/core/agent"; const agent = new Agent({ id: "neon-demo", name: "neon-demo", instructions: "You are a helpful assistant.", model: "neon/gemini-3-1-pro", }); const { text } = await agent.generate("Explain Serverless Postgres."); console.log(text); ``` #### TypeScript Install: ```bash npm i openai ``` ```typescript import OpenAI from "openai"; const client = new OpenAI({ apiKey: process.env.NEON_AI_GATEWAY_TOKEN, baseURL: `${process.env.NEON_AI_GATEWAY_BASE_URL}/v1`, }); const resp = await client.chat.completions.create({ model: "gemini-3-1-pro", messages: [{ role: "user", content: "Explain Serverless Postgres." }], }); console.log(resp.choices[0].message.content); ``` #### Python Install: ```bash pip install openai ``` ```python import os from openai import OpenAI client = OpenAI( api_key=os.environ["NEON_AI_GATEWAY_TOKEN"], base_url=f"{os.environ['NEON_AI_GATEWAY_BASE_URL']}/v1", ) resp = client.chat.completions.create( model="gemini-3-1-pro", messages=[{"role": "user", "content": "Explain Serverless Postgres."}], ) print(resp.choices[0].message.content) ``` #### cURL ```bash curl "${NEON_AI_GATEWAY_BASE_URL}/v1/chat/completions" \ -H "Authorization: Bearer ${NEON_AI_GATEWAY_TOKEN}" \ -H "Content-Type: application/json" \ -d '{ "model": "gemini-3-1-pro", "messages": [{"role": "user", "content": "Explain Serverless Postgres."}] }' ``` **Environment variables** ```bash # Injected by `neon env pull` when AI Gateway is enabled on the branch (neon.ts preview.aiGateway). # Neon injects ONLY the NEON_AI_GATEWAY_* vars (not OPENAI_*). Build the OpenAI SDK / curl # apiKey + baseURL from them: apiKey = NEON_AI_GATEWAY_TOKEN (the bearer, nt_live_...). # # NEON_AI_GATEWAY_BASE_URL is the bare gateway host (no path). Append the route you need: # - `/v1` - unified Chat Completions and `/v1/embeddings` # - `/openai/v1` - OpenAI Responses API # - `/typesafe` - TypeSafe SDK base URL for System One decisions (`/typesafe/v1/systemone`) # @neon/ai-sdk-provider and Mastra route requests automatically. NEON_AI_GATEWAY_TOKEN=nt_live_... NEON_AI_GATEWAY_BASE_URL=https://-api.ai....neon.tech ``` ## Model ID gemini-3-1-pro ## Lab Google makes Gemini 3.1 Pro. Access the model through the Neon AI Gateway using chat/completions and gemini. ## Provider Databricks ## Inputs Text, image, video, audio, pdf ## Context 1M ## Released Feb 2026 ## Input /M $2 ## Output /M $12 --- [Document source](https://neon.com/docs/ai-gateway/models/gemini-3-5-flash-lite.md) --- # Gemini 3.5 Flash Lite ## About Neon AI Gateway provides Gemini 3.5 Flash Lite by Google. The model supports text, image, video, audio, pdf inputs and a 1M context window. ## Command ### Text generation #### AI SDK Install: ```bash npm i ai @neon/ai-sdk-provider ``` ```typescript import { generateText } from "ai"; import { neon } from "@neon/ai-sdk-provider"; const { text } = await generateText({ model: neon("gemini-3-5-flash-lite"), prompt: "Explain Serverless Postgres.", }); console.log(text); ``` #### Mastra Install: ```bash npm i @mastra/core ``` ```typescript import { Agent } from "@mastra/core/agent"; const agent = new Agent({ id: "neon-demo", name: "neon-demo", instructions: "You are a helpful assistant.", model: "neon/gemini-3-5-flash-lite", }); const { text } = await agent.generate("Explain Serverless Postgres."); console.log(text); ``` #### TypeScript Install: ```bash npm i openai ``` ```typescript import OpenAI from "openai"; const client = new OpenAI({ apiKey: process.env.NEON_AI_GATEWAY_TOKEN, baseURL: `${process.env.NEON_AI_GATEWAY_BASE_URL}/v1`, }); const resp = await client.chat.completions.create({ model: "gemini-3-5-flash-lite", messages: [{ role: "user", content: "Explain Serverless Postgres." }], }); console.log(resp.choices[0].message.content); ``` #### Python Install: ```bash pip install openai ``` ```python import os from openai import OpenAI client = OpenAI( api_key=os.environ["NEON_AI_GATEWAY_TOKEN"], base_url=f"{os.environ['NEON_AI_GATEWAY_BASE_URL']}/v1", ) resp = client.chat.completions.create( model="gemini-3-5-flash-lite", messages=[{"role": "user", "content": "Explain Serverless Postgres."}], ) print(resp.choices[0].message.content) ``` #### cURL ```bash curl "${NEON_AI_GATEWAY_BASE_URL}/v1/chat/completions" \ -H "Authorization: Bearer ${NEON_AI_GATEWAY_TOKEN}" \ -H "Content-Type: application/json" \ -d '{ "model": "gemini-3-5-flash-lite", "messages": [{"role": "user", "content": "Explain Serverless Postgres."}] }' ``` **Environment variables** ```bash # Injected by `neon env pull` when AI Gateway is enabled on the branch (neon.ts preview.aiGateway). # Neon injects ONLY the NEON_AI_GATEWAY_* vars (not OPENAI_*). Build the OpenAI SDK / curl # apiKey + baseURL from them: apiKey = NEON_AI_GATEWAY_TOKEN (the bearer, nt_live_...). # # NEON_AI_GATEWAY_BASE_URL is the bare gateway host (no path). Append the route you need: # - `/v1` - unified Chat Completions and `/v1/embeddings` # - `/openai/v1` - OpenAI Responses API # - `/typesafe` - TypeSafe SDK base URL for System One decisions (`/typesafe/v1/systemone`) # @neon/ai-sdk-provider and Mastra route requests automatically. NEON_AI_GATEWAY_TOKEN=nt_live_... NEON_AI_GATEWAY_BASE_URL=https://-api.ai....neon.tech ``` ## Model ID gemini-3-5-flash-lite ## Lab Google makes Gemini 3.5 Flash Lite. Access the model through the Neon AI Gateway using chat/completions and gemini. ## Provider Databricks ## Inputs Text, image, video, audio, pdf ## Context 1M ## Released Jul 2026 ## Input /M $0.30 ## Output /M $2.50 --- [Document source](https://neon.com/docs/ai-gateway/models/gemini-3-5-flash.md) --- # Gemini 3.5 Flash ## About Neon AI Gateway provides Gemini 3.5 Flash by Google. The model supports text, image, video, audio, pdf inputs and a 1M context window. ## Command ### Text generation #### AI SDK Install: ```bash npm i ai @neon/ai-sdk-provider ``` ```typescript import { generateText } from "ai"; import { neon } from "@neon/ai-sdk-provider"; const { text } = await generateText({ model: neon("gemini-3-5-flash"), prompt: "Explain Serverless Postgres.", }); console.log(text); ``` #### Mastra Install: ```bash npm i @mastra/core ``` ```typescript import { Agent } from "@mastra/core/agent"; const agent = new Agent({ id: "neon-demo", name: "neon-demo", instructions: "You are a helpful assistant.", model: "neon/gemini-3-5-flash", }); const { text } = await agent.generate("Explain Serverless Postgres."); console.log(text); ``` #### TypeScript Install: ```bash npm i openai ``` ```typescript import OpenAI from "openai"; const client = new OpenAI({ apiKey: process.env.NEON_AI_GATEWAY_TOKEN, baseURL: `${process.env.NEON_AI_GATEWAY_BASE_URL}/v1`, }); const resp = await client.chat.completions.create({ model: "gemini-3-5-flash", messages: [{ role: "user", content: "Explain Serverless Postgres." }], }); console.log(resp.choices[0].message.content); ``` #### Python Install: ```bash pip install openai ``` ```python import os from openai import OpenAI client = OpenAI( api_key=os.environ["NEON_AI_GATEWAY_TOKEN"], base_url=f"{os.environ['NEON_AI_GATEWAY_BASE_URL']}/v1", ) resp = client.chat.completions.create( model="gemini-3-5-flash", messages=[{"role": "user", "content": "Explain Serverless Postgres."}], ) print(resp.choices[0].message.content) ``` #### cURL ```bash curl "${NEON_AI_GATEWAY_BASE_URL}/v1/chat/completions" \ -H "Authorization: Bearer ${NEON_AI_GATEWAY_TOKEN}" \ -H "Content-Type: application/json" \ -d '{ "model": "gemini-3-5-flash", "messages": [{"role": "user", "content": "Explain Serverless Postgres."}] }' ``` **Environment variables** ```bash # Injected by `neon env pull` when AI Gateway is enabled on the branch (neon.ts preview.aiGateway). # Neon injects ONLY the NEON_AI_GATEWAY_* vars (not OPENAI_*). Build the OpenAI SDK / curl # apiKey + baseURL from them: apiKey = NEON_AI_GATEWAY_TOKEN (the bearer, nt_live_...). # # NEON_AI_GATEWAY_BASE_URL is the bare gateway host (no path). Append the route you need: # - `/v1` - unified Chat Completions and `/v1/embeddings` # - `/openai/v1` - OpenAI Responses API # - `/typesafe` - TypeSafe SDK base URL for System One decisions (`/typesafe/v1/systemone`) # @neon/ai-sdk-provider and Mastra route requests automatically. NEON_AI_GATEWAY_TOKEN=nt_live_... NEON_AI_GATEWAY_BASE_URL=https://-api.ai....neon.tech ``` ## Model ID gemini-3-5-flash ## Lab Google makes Gemini 3.5 Flash. Access the model through the Neon AI Gateway using chat/completions and gemini. ## Provider Databricks ## Inputs Text, image, video, audio, pdf ## Context 1M ## Released May 2026 ## Input /M $1.50 ## Output /M $9 --- [Document source](https://neon.com/docs/ai-gateway/models/gemini-3-6-flash.md) --- # Gemini 3.6 Flash ## About Neon AI Gateway provides Gemini 3.6 Flash by Google. The model supports text, image, video, audio, pdf inputs and a 1M context window. ## Command ### Text generation #### AI SDK Install: ```bash npm i ai @neon/ai-sdk-provider ``` ```typescript import { generateText } from "ai"; import { neon } from "@neon/ai-sdk-provider"; const { text } = await generateText({ model: neon("gemini-3-6-flash"), prompt: "Explain Serverless Postgres.", }); console.log(text); ``` #### Mastra Install: ```bash npm i @mastra/core ``` ```typescript import { Agent } from "@mastra/core/agent"; const agent = new Agent({ id: "neon-demo", name: "neon-demo", instructions: "You are a helpful assistant.", model: "neon/gemini-3-6-flash", }); const { text } = await agent.generate("Explain Serverless Postgres."); console.log(text); ``` #### TypeScript Install: ```bash npm i openai ``` ```typescript import OpenAI from "openai"; const client = new OpenAI({ apiKey: process.env.NEON_AI_GATEWAY_TOKEN, baseURL: `${process.env.NEON_AI_GATEWAY_BASE_URL}/v1`, }); const resp = await client.chat.completions.create({ model: "gemini-3-6-flash", messages: [{ role: "user", content: "Explain Serverless Postgres." }], }); console.log(resp.choices[0].message.content); ``` #### Python Install: ```bash pip install openai ``` ```python import os from openai import OpenAI client = OpenAI( api_key=os.environ["NEON_AI_GATEWAY_TOKEN"], base_url=f"{os.environ['NEON_AI_GATEWAY_BASE_URL']}/v1", ) resp = client.chat.completions.create( model="gemini-3-6-flash", messages=[{"role": "user", "content": "Explain Serverless Postgres."}], ) print(resp.choices[0].message.content) ``` #### cURL ```bash curl "${NEON_AI_GATEWAY_BASE_URL}/v1/chat/completions" \ -H "Authorization: Bearer ${NEON_AI_GATEWAY_TOKEN}" \ -H "Content-Type: application/json" \ -d '{ "model": "gemini-3-6-flash", "messages": [{"role": "user", "content": "Explain Serverless Postgres."}] }' ``` **Environment variables** ```bash # Injected by `neon env pull` when AI Gateway is enabled on the branch (neon.ts preview.aiGateway). # Neon injects ONLY the NEON_AI_GATEWAY_* vars (not OPENAI_*). Build the OpenAI SDK / curl # apiKey + baseURL from them: apiKey = NEON_AI_GATEWAY_TOKEN (the bearer, nt_live_...). # # NEON_AI_GATEWAY_BASE_URL is the bare gateway host (no path). Append the route you need: # - `/v1` - unified Chat Completions and `/v1/embeddings` # - `/openai/v1` - OpenAI Responses API # - `/typesafe` - TypeSafe SDK base URL for System One decisions (`/typesafe/v1/systemone`) # @neon/ai-sdk-provider and Mastra route requests automatically. NEON_AI_GATEWAY_TOKEN=nt_live_... NEON_AI_GATEWAY_BASE_URL=https://-api.ai....neon.tech ``` ## Model ID gemini-3-6-flash ## Lab Google makes Gemini 3.6 Flash. Access the model through the Neon AI Gateway using chat/completions and gemini. ## Provider Databricks ## Inputs Text, image, video, audio, pdf ## Context 1M ## Released Jul 2026 ## Input /M $1.50 ## Output /M $7.50 --- [Document source](https://neon.com/docs/ai-gateway/models/gemini-3-7-flash.md) --- # Gemini 3.7 Flash ## About Neon AI Gateway provides Gemini 3.7 Flash by Google. The model supports text, image, video, audio, pdf inputs and a 1M context window. ## Command ### Text generation #### AI SDK Install: ```bash npm i ai @neon/ai-sdk-provider ``` ```typescript import { generateText } from "ai"; import { neon } from "@neon/ai-sdk-provider"; const { text } = await generateText({ model: neon("gemini-3-7-flash"), prompt: "Explain Serverless Postgres.", }); console.log(text); ``` #### Mastra Install: ```bash npm i @mastra/core ai @neon/ai-sdk-provider ``` ```typescript import { Agent } from "@mastra/core/agent"; import { neon } from "@neon/ai-sdk-provider"; const agent = new Agent({ id: "neon-demo", name: "neon-demo", instructions: "You are a helpful assistant.", model: neon("gemini-3-7-flash"), }); const { text } = await agent.generate("Explain Serverless Postgres."); console.log(text); ``` #### cURL ```bash curl "${NEON_AI_GATEWAY_BASE_URL}/gemini/v1beta/models/gemini-3-7-flash:generateContent" \ -H "Authorization: Bearer ${NEON_AI_GATEWAY_TOKEN}" \ -H "Content-Type: application/json" \ -d '{ "contents": [ {"role": "user", "parts": [{"text": "Explain Serverless Postgres."}]} ] }' ``` **Environment variables** ```bash # Injected by `neon env pull` when AI Gateway is enabled on the branch (neon.ts preview.aiGateway). # Neon injects ONLY the NEON_AI_GATEWAY_* vars (not OPENAI_*). Build the OpenAI SDK / curl # apiKey + baseURL from them: apiKey = NEON_AI_GATEWAY_TOKEN (the bearer, nt_live_...). # # NEON_AI_GATEWAY_BASE_URL is the bare gateway host (no path). Append the route you need: # - `/v1` - unified Chat Completions and `/v1/embeddings` # - `/openai/v1` - OpenAI Responses API # - `/typesafe` - TypeSafe SDK base URL for System One decisions (`/typesafe/v1/systemone`) # @neon/ai-sdk-provider and Mastra route requests automatically. NEON_AI_GATEWAY_TOKEN=nt_live_... NEON_AI_GATEWAY_BASE_URL=https://-api.ai....neon.tech ``` ## Model ID gemini-3-7-flash ## Lab Google makes Gemini 3.7 Flash. Access the model through the Neon AI Gateway using chat/completions and gemini. ## Provider Databricks ## Inputs Text, image, video, audio, pdf ## Context 1M ## Released Aug 2026 ## Input /M $1.50 ## Output /M $7.50 --- [Document source](https://neon.com/docs/ai-gateway/models/gemini-3-8-flash.md) --- # Gemini 3.8 Flash ## About Neon AI Gateway provides Gemini 3.8 Flash by Google. The model supports text, image, video, audio, pdf inputs and a 1M context window. ## Command ### Text generation #### AI SDK Install: ```bash npm i ai @neon/ai-sdk-provider ``` ```typescript import { generateText } from "ai"; import { neon } from "@neon/ai-sdk-provider"; const { text } = await generateText({ model: neon("gemini-3-8-flash"), prompt: "Explain Serverless Postgres.", }); console.log(text); ``` #### Mastra Install: ```bash npm i @mastra/core ai @neon/ai-sdk-provider ``` ```typescript import { Agent } from "@mastra/core/agent"; import { neon } from "@neon/ai-sdk-provider"; const agent = new Agent({ id: "neon-demo", name: "neon-demo", instructions: "You are a helpful assistant.", model: neon("gemini-3-8-flash"), }); const { text } = await agent.generate("Explain Serverless Postgres."); console.log(text); ``` #### cURL ```bash curl "${NEON_AI_GATEWAY_BASE_URL}/gemini/v1beta/models/gemini-3-8-flash:generateContent" \ -H "Authorization: Bearer ${NEON_AI_GATEWAY_TOKEN}" \ -H "Content-Type: application/json" \ -d '{ "contents": [ {"role": "user", "parts": [{"text": "Explain Serverless Postgres."}]} ] }' ``` **Environment variables** ```bash # Injected by `neon env pull` when AI Gateway is enabled on the branch (neon.ts preview.aiGateway). # Neon injects ONLY the NEON_AI_GATEWAY_* vars (not OPENAI_*). Build the OpenAI SDK / curl # apiKey + baseURL from them: apiKey = NEON_AI_GATEWAY_TOKEN (the bearer, nt_live_...). # # NEON_AI_GATEWAY_BASE_URL is the bare gateway host (no path). Append the route you need: # - `/v1` - unified Chat Completions and `/v1/embeddings` # - `/openai/v1` - OpenAI Responses API # - `/typesafe` - TypeSafe SDK base URL for System One decisions (`/typesafe/v1/systemone`) # @neon/ai-sdk-provider and Mastra route requests automatically. NEON_AI_GATEWAY_TOKEN=nt_live_... NEON_AI_GATEWAY_BASE_URL=https://-api.ai....neon.tech ``` ## Model ID gemini-3-8-flash ## Lab Google makes Gemini 3.8 Flash. Access the model through the Neon AI Gateway using chat/completions and gemini. ## Provider Databricks ## Inputs Text, image, video, audio, pdf ## Context 1M ## Released Sep 2026 ## Input /M $1.50 ## Output /M $7.50 --- [Document source](https://neon.com/docs/ai-gateway/models/gemini-3-flash.md) --- # Gemini 3 Flash ## About Neon AI Gateway provides Gemini 3 Flash by Google. The model supports text, image, video, audio, pdf inputs and a 1M context window. ## Command ### Text generation #### AI SDK Install: ```bash npm i ai @neon/ai-sdk-provider ``` ```typescript import { generateText } from "ai"; import { neon } from "@neon/ai-sdk-provider"; const { text } = await generateText({ model: neon("gemini-3-flash"), prompt: "Explain Serverless Postgres.", }); console.log(text); ``` #### Mastra Install: ```bash npm i @mastra/core ``` ```typescript import { Agent } from "@mastra/core/agent"; const agent = new Agent({ id: "neon-demo", name: "neon-demo", instructions: "You are a helpful assistant.", model: "neon/gemini-3-flash", }); const { text } = await agent.generate("Explain Serverless Postgres."); console.log(text); ``` #### TypeScript Install: ```bash npm i openai ``` ```typescript import OpenAI from "openai"; const client = new OpenAI({ apiKey: process.env.NEON_AI_GATEWAY_TOKEN, baseURL: `${process.env.NEON_AI_GATEWAY_BASE_URL}/v1`, }); const resp = await client.chat.completions.create({ model: "gemini-3-flash", messages: [{ role: "user", content: "Explain Serverless Postgres." }], }); console.log(resp.choices[0].message.content); ``` #### Python Install: ```bash pip install openai ``` ```python import os from openai import OpenAI client = OpenAI( api_key=os.environ["NEON_AI_GATEWAY_TOKEN"], base_url=f"{os.environ['NEON_AI_GATEWAY_BASE_URL']}/v1", ) resp = client.chat.completions.create( model="gemini-3-flash", messages=[{"role": "user", "content": "Explain Serverless Postgres."}], ) print(resp.choices[0].message.content) ``` #### cURL ```bash curl "${NEON_AI_GATEWAY_BASE_URL}/v1/chat/completions" \ -H "Authorization: Bearer ${NEON_AI_GATEWAY_TOKEN}" \ -H "Content-Type: application/json" \ -d '{ "model": "gemini-3-flash", "messages": [{"role": "user", "content": "Explain Serverless Postgres."}] }' ``` **Environment variables** ```bash # Injected by `neon env pull` when AI Gateway is enabled on the branch (neon.ts preview.aiGateway). # Neon injects ONLY the NEON_AI_GATEWAY_* vars (not OPENAI_*). Build the OpenAI SDK / curl # apiKey + baseURL from them: apiKey = NEON_AI_GATEWAY_TOKEN (the bearer, nt_live_...). # # NEON_AI_GATEWAY_BASE_URL is the bare gateway host (no path). Append the route you need: # - `/v1` - unified Chat Completions and `/v1/embeddings` # - `/openai/v1` - OpenAI Responses API # - `/typesafe` - TypeSafe SDK base URL for System One decisions (`/typesafe/v1/systemone`) # @neon/ai-sdk-provider and Mastra route requests automatically. NEON_AI_GATEWAY_TOKEN=nt_live_... NEON_AI_GATEWAY_BASE_URL=https://-api.ai....neon.tech ``` ## Model ID gemini-3-flash ## Lab Google makes Gemini 3 Flash. Access the model through the Neon AI Gateway using chat/completions and gemini. ## Provider Databricks ## Inputs Text, image, video, audio, pdf ## Context 1M ## Released Dec 2025 ## Input /M $0.50 ## Output /M $3 --- [Document source](https://neon.com/docs/ai-gateway/models/gemini-4-argon.md) --- # Gemini 4 Argon ## About Neon AI Gateway provides Gemini 4 Argon by Google. The model supports text, image, video, audio, pdf inputs and a 1M context window. ## Command ### Text generation #### AI SDK Install: ```bash npm i ai @neon/ai-sdk-provider ``` ```typescript import { generateText } from "ai"; import { neon } from "@neon/ai-sdk-provider"; const { text } = await generateText({ model: neon("gemini-4-argon"), prompt: "Explain Serverless Postgres.", }); console.log(text); ``` #### Mastra Install: ```bash npm i @mastra/core ai @neon/ai-sdk-provider ``` ```typescript import { Agent } from "@mastra/core/agent"; import { neon } from "@neon/ai-sdk-provider"; const agent = new Agent({ id: "neon-demo", name: "neon-demo", instructions: "You are a helpful assistant.", model: neon("gemini-4-argon"), }); const { text } = await agent.generate("Explain Serverless Postgres."); console.log(text); ``` #### cURL ```bash curl "${NEON_AI_GATEWAY_BASE_URL}/gemini/v1beta/models/gemini-4-argon:generateContent" \ -H "Authorization: Bearer ${NEON_AI_GATEWAY_TOKEN}" \ -H "Content-Type: application/json" \ -d '{ "contents": [ {"role": "user", "parts": [{"text": "Explain Serverless Postgres."}]} ] }' ``` **Environment variables** ```bash # Injected by `neon env pull` when AI Gateway is enabled on the branch (neon.ts preview.aiGateway). # Neon injects ONLY the NEON_AI_GATEWAY_* vars (not OPENAI_*). Build the OpenAI SDK / curl # apiKey + baseURL from them: apiKey = NEON_AI_GATEWAY_TOKEN (the bearer, nt_live_...). # # NEON_AI_GATEWAY_BASE_URL is the bare gateway host (no path). Append the route you need: # - `/v1` - unified Chat Completions and `/v1/embeddings` # - `/openai/v1` - OpenAI Responses API # - `/typesafe` - TypeSafe SDK base URL for System One decisions (`/typesafe/v1/systemone`) # @neon/ai-sdk-provider and Mastra route requests automatically. NEON_AI_GATEWAY_TOKEN=nt_live_... NEON_AI_GATEWAY_BASE_URL=https://-api.ai....neon.tech ``` ## Model ID gemini-4-argon ## Lab Google makes Gemini 4 Argon. Access the model through the Neon AI Gateway using chat/completions and gemini. ## Provider Databricks ## Inputs Text, image, video, audio, pdf ## Context 1M ## Released Oct 2026 ## Input /M $4 ## Output /M $20 --- [Document source](https://neon.com/docs/ai-gateway/models/gemma-3-12b.md) --- # Gemma 3 12B ## About Neon AI Gateway provides Gemma 3 12B by Google. The model supports text, image inputs and a 131K context window. ## Command ### Text generation #### AI SDK Install: ```bash npm i ai @neon/ai-sdk-provider ``` ```typescript import { generateText } from "ai"; import { neon } from "@neon/ai-sdk-provider"; const { text } = await generateText({ model: neon("gemma-3-12b"), prompt: "Explain Serverless Postgres.", }); console.log(text); ``` #### Mastra Install: ```bash npm i @mastra/core ``` ```typescript import { Agent } from "@mastra/core/agent"; const agent = new Agent({ id: "neon-demo", name: "neon-demo", instructions: "You are a helpful assistant.", model: "neon/gemma-3-12b", }); const { text } = await agent.generate("Explain Serverless Postgres."); console.log(text); ``` #### TypeScript Install: ```bash npm i openai ``` ```typescript import OpenAI from "openai"; const client = new OpenAI({ apiKey: process.env.NEON_AI_GATEWAY_TOKEN, baseURL: `${process.env.NEON_AI_GATEWAY_BASE_URL}/v1`, }); const resp = await client.chat.completions.create({ model: "gemma-3-12b", messages: [{ role: "user", content: "Explain Serverless Postgres." }], }); console.log(resp.choices[0].message.content); ``` #### Python Install: ```bash pip install openai ``` ```python import os from openai import OpenAI client = OpenAI( api_key=os.environ["NEON_AI_GATEWAY_TOKEN"], base_url=f"{os.environ['NEON_AI_GATEWAY_BASE_URL']}/v1", ) resp = client.chat.completions.create( model="gemma-3-12b", messages=[{"role": "user", "content": "Explain Serverless Postgres."}], ) print(resp.choices[0].message.content) ``` #### cURL ```bash curl "${NEON_AI_GATEWAY_BASE_URL}/v1/chat/completions" \ -H "Authorization: Bearer ${NEON_AI_GATEWAY_TOKEN}" \ -H "Content-Type: application/json" \ -d '{ "model": "gemma-3-12b", "messages": [{"role": "user", "content": "Explain Serverless Postgres."}] }' ``` **Environment variables** ```bash # Injected by `neon env pull` when AI Gateway is enabled on the branch (neon.ts preview.aiGateway). # Neon injects ONLY the NEON_AI_GATEWAY_* vars (not OPENAI_*). Build the OpenAI SDK / curl # apiKey + baseURL from them: apiKey = NEON_AI_GATEWAY_TOKEN (the bearer, nt_live_...). # # NEON_AI_GATEWAY_BASE_URL is the bare gateway host (no path). Append the route you need: # - `/v1` - unified Chat Completions and `/v1/embeddings` # - `/openai/v1` - OpenAI Responses API # - `/typesafe` - TypeSafe SDK base URL for System One decisions (`/typesafe/v1/systemone`) # @neon/ai-sdk-provider and Mastra route requests automatically. NEON_AI_GATEWAY_TOKEN=nt_live_... NEON_AI_GATEWAY_BASE_URL=https://-api.ai....neon.tech ``` ## Model ID gemma-3-12b ## Lab Google makes Gemma 3 12B. Access the model through the Neon AI Gateway using chat/completions. ## Provider Databricks ## Inputs Text, image ## Context 131K ## Released Mar 2025 ## Input /M $0.15 ## Output /M $0.50 --- [Document source](https://neon.com/docs/ai-gateway/models/glm-5-2.md) --- # GLM 5.2 ## About Neon AI Gateway provides GLM 5.2 by Zhipu AI. The model supports text inputs and a 1M context window. ## Command ### Text generation #### AI SDK Install: ```bash npm i ai @neon/ai-sdk-provider ``` ```typescript import { generateText } from "ai"; import { neon } from "@neon/ai-sdk-provider"; const { text } = await generateText({ model: neon("glm-5-2"), prompt: "Explain Serverless Postgres.", }); console.log(text); ``` #### Mastra Install: ```bash npm i @mastra/core ``` ```typescript import { Agent } from "@mastra/core/agent"; const agent = new Agent({ id: "neon-demo", name: "neon-demo", instructions: "You are a helpful assistant.", model: "neon/glm-5-2", }); const { text } = await agent.generate("Explain Serverless Postgres."); console.log(text); ``` #### TypeScript Install: ```bash npm i openai ``` ```typescript import OpenAI from "openai"; const client = new OpenAI({ apiKey: process.env.NEON_AI_GATEWAY_TOKEN, baseURL: `${process.env.NEON_AI_GATEWAY_BASE_URL}/v1`, }); const resp = await client.chat.completions.create({ model: "glm-5-2", messages: [{ role: "user", content: "Explain Serverless Postgres." }], }); console.log(resp.choices[0].message.content); ``` #### Python Install: ```bash pip install openai ``` ```python import os from openai import OpenAI client = OpenAI( api_key=os.environ["NEON_AI_GATEWAY_TOKEN"], base_url=f"{os.environ['NEON_AI_GATEWAY_BASE_URL']}/v1", ) resp = client.chat.completions.create( model="glm-5-2", messages=[{"role": "user", "content": "Explain Serverless Postgres."}], ) print(resp.choices[0].message.content) ``` #### cURL ```bash curl "${NEON_AI_GATEWAY_BASE_URL}/v1/chat/completions" \ -H "Authorization: Bearer ${NEON_AI_GATEWAY_TOKEN}" \ -H "Content-Type: application/json" \ -d '{ "model": "glm-5-2", "messages": [{"role": "user", "content": "Explain Serverless Postgres."}] }' ``` **Environment variables** ```bash # Injected by `neon env pull` when AI Gateway is enabled on the branch (neon.ts preview.aiGateway). # Neon injects ONLY the NEON_AI_GATEWAY_* vars (not OPENAI_*). Build the OpenAI SDK / curl # apiKey + baseURL from them: apiKey = NEON_AI_GATEWAY_TOKEN (the bearer, nt_live_...). # # NEON_AI_GATEWAY_BASE_URL is the bare gateway host (no path). Append the route you need: # - `/v1` - unified Chat Completions and `/v1/embeddings` # - `/openai/v1` - OpenAI Responses API # - `/typesafe` - TypeSafe SDK base URL for System One decisions (`/typesafe/v1/systemone`) # @neon/ai-sdk-provider and Mastra route requests automatically. NEON_AI_GATEWAY_TOKEN=nt_live_... NEON_AI_GATEWAY_BASE_URL=https://-api.ai....neon.tech ``` ## Model ID glm-5-2 ## Lab Zhipu AI makes GLM 5.2. Access the model through the Neon AI Gateway using chat/completions. ## Provider Databricks ## Inputs Text ## Context 1M ## Released Jun 2026 ## Input /M $1.40 ## Output /M $4.40 --- [Document source](https://neon.com/docs/ai-gateway/models/glm-5-3-flash.md) --- # GLM 5.3 Flash ## About Neon AI Gateway provides GLM 5.3 Flash by Zhipu AI. The model supports text, image inputs and a 1M context window. ## Command ### Text generation #### AI SDK Install: ```bash npm i ai @neon/ai-sdk-provider ``` ```typescript import { generateText } from "ai"; import { neon } from "@neon/ai-sdk-provider"; const { text } = await generateText({ model: neon("glm-5-3-flash"), prompt: "Explain Serverless Postgres.", }); console.log(text); ``` #### Mastra Install: ```bash npm i @mastra/core ``` ```typescript import { Agent } from "@mastra/core/agent"; const agent = new Agent({ id: "neon-demo", name: "neon-demo", instructions: "You are a helpful assistant.", model: "neon/glm-5-3-flash", }); const { text } = await agent.generate("Explain Serverless Postgres."); console.log(text); ``` #### TypeScript Install: ```bash npm i openai ``` ```typescript import OpenAI from "openai"; const client = new OpenAI({ apiKey: process.env.NEON_AI_GATEWAY_TOKEN, baseURL: `${process.env.NEON_AI_GATEWAY_BASE_URL}/v1`, }); const resp = await client.chat.completions.create({ model: "glm-5-3-flash", messages: [{ role: "user", content: "Explain Serverless Postgres." }], }); console.log(resp.choices[0].message.content); ``` #### Python Install: ```bash pip install openai ``` ```python import os from openai import OpenAI client = OpenAI( api_key=os.environ["NEON_AI_GATEWAY_TOKEN"], base_url=f"{os.environ['NEON_AI_GATEWAY_BASE_URL']}/v1", ) resp = client.chat.completions.create( model="glm-5-3-flash", messages=[{"role": "user", "content": "Explain Serverless Postgres."}], ) print(resp.choices[0].message.content) ``` #### cURL ```bash curl "${NEON_AI_GATEWAY_BASE_URL}/v1/chat/completions" \ -H "Authorization: Bearer ${NEON_AI_GATEWAY_TOKEN}" \ -H "Content-Type: application/json" \ -d '{ "model": "glm-5-3-flash", "messages": [{"role": "user", "content": "Explain Serverless Postgres."}] }' ``` **Environment variables** ```bash # Injected by `neon env pull` when AI Gateway is enabled on the branch (neon.ts preview.aiGateway). # Neon injects ONLY the NEON_AI_GATEWAY_* vars (not OPENAI_*). Build the OpenAI SDK / curl # apiKey + baseURL from them: apiKey = NEON_AI_GATEWAY_TOKEN (the bearer, nt_live_...). # # NEON_AI_GATEWAY_BASE_URL is the bare gateway host (no path). Append the route you need: # - `/v1` - unified Chat Completions and `/v1/embeddings` # - `/openai/v1` - OpenAI Responses API # - `/typesafe` - TypeSafe SDK base URL for System One decisions (`/typesafe/v1/systemone`) # @neon/ai-sdk-provider and Mastra route requests automatically. NEON_AI_GATEWAY_TOKEN=nt_live_... NEON_AI_GATEWAY_BASE_URL=https://-api.ai....neon.tech ``` ## Model ID glm-5-3-flash ## Lab Zhipu AI makes GLM 5.3 Flash. Access the model through the Neon AI Gateway using chat/completions. ## Provider Databricks ## Inputs Text, image ## Context 1M ## Released Aug 2026 ## Input /M $0.15 ## Output /M $0.50 --- [Document source](https://neon.com/docs/ai-gateway/models/glm-5-3.md) --- # GLM 5.3 ## About Neon AI Gateway provides GLM 5.3 by Zhipu AI. The model supports text inputs and a 1M context window. ## Command ### Text generation #### AI SDK Install: ```bash npm i ai @neon/ai-sdk-provider ``` ```typescript import { generateText } from "ai"; import { neon } from "@neon/ai-sdk-provider"; const { text } = await generateText({ model: neon("glm-5-3"), prompt: "Explain Serverless Postgres.", }); console.log(text); ``` #### Mastra Install: ```bash npm i @mastra/core ``` ```typescript import { Agent } from "@mastra/core/agent"; const agent = new Agent({ id: "neon-demo", name: "neon-demo", instructions: "You are a helpful assistant.", model: "neon/glm-5-3", }); const { text } = await agent.generate("Explain Serverless Postgres."); console.log(text); ``` #### TypeScript Install: ```bash npm i openai ``` ```typescript import OpenAI from "openai"; const client = new OpenAI({ apiKey: process.env.NEON_AI_GATEWAY_TOKEN, baseURL: `${process.env.NEON_AI_GATEWAY_BASE_URL}/v1`, }); const resp = await client.chat.completions.create({ model: "glm-5-3", messages: [{ role: "user", content: "Explain Serverless Postgres." }], }); console.log(resp.choices[0].message.content); ``` #### Python Install: ```bash pip install openai ``` ```python import os from openai import OpenAI client = OpenAI( api_key=os.environ["NEON_AI_GATEWAY_TOKEN"], base_url=f"{os.environ['NEON_AI_GATEWAY_BASE_URL']}/v1", ) resp = client.chat.completions.create( model="glm-5-3", messages=[{"role": "user", "content": "Explain Serverless Postgres."}], ) print(resp.choices[0].message.content) ``` #### cURL ```bash curl "${NEON_AI_GATEWAY_BASE_URL}/v1/chat/completions" \ -H "Authorization: Bearer ${NEON_AI_GATEWAY_TOKEN}" \ -H "Content-Type: application/json" \ -d '{ "model": "glm-5-3", "messages": [{"role": "user", "content": "Explain Serverless Postgres."}] }' ``` **Environment variables** ```bash # Injected by `neon env pull` when AI Gateway is enabled on the branch (neon.ts preview.aiGateway). # Neon injects ONLY the NEON_AI_GATEWAY_* vars (not OPENAI_*). Build the OpenAI SDK / curl # apiKey + baseURL from them: apiKey = NEON_AI_GATEWAY_TOKEN (the bearer, nt_live_...). # # NEON_AI_GATEWAY_BASE_URL is the bare gateway host (no path). Append the route you need: # - `/v1` - unified Chat Completions and `/v1/embeddings` # - `/openai/v1` - OpenAI Responses API # - `/typesafe` - TypeSafe SDK base URL for System One decisions (`/typesafe/v1/systemone`) # @neon/ai-sdk-provider and Mastra route requests automatically. NEON_AI_GATEWAY_TOKEN=nt_live_... NEON_AI_GATEWAY_BASE_URL=https://-api.ai....neon.tech ``` ## Model ID glm-5-3 ## Lab Zhipu AI makes GLM 5.3. Access the model through the Neon AI Gateway using chat/completions. ## Provider Databricks ## Inputs Text ## Context 1M ## Released Aug 2026 ## Input /M $1.40 ## Output /M $4.40 --- [Document source](https://neon.com/docs/ai-gateway/models/gpt-5-1.md) --- # GPT-5.1 ## About Neon AI Gateway provides GPT-5.1 by OpenAI. The model supports text, image inputs and a 400K context window. ## Command ### Text generation #### AI SDK Install: ```bash npm i ai @neon/ai-sdk-provider ``` ```typescript import { generateText } from "ai"; import { neon } from "@neon/ai-sdk-provider"; const { text } = await generateText({ model: neon("gpt-5-1"), prompt: "Explain Serverless Postgres.", }); console.log(text); ``` #### Mastra Install: ```bash npm i @mastra/core ``` ```typescript import { Agent } from "@mastra/core/agent"; const agent = new Agent({ id: "neon-demo", name: "neon-demo", instructions: "You are a helpful assistant.", model: "neon/gpt-5-1", }); const { text } = await agent.generate("Explain Serverless Postgres."); console.log(text); ``` #### TypeScript Install: ```bash npm i openai ``` ```typescript import OpenAI from "openai"; const client = new OpenAI({ apiKey: process.env.NEON_AI_GATEWAY_TOKEN, baseURL: `${process.env.NEON_AI_GATEWAY_BASE_URL}/v1`, }); const resp = await client.chat.completions.create({ model: "gpt-5-1", messages: [{ role: "user", content: "Explain Serverless Postgres." }], }); console.log(resp.choices[0].message.content); ``` #### Python Install: ```bash pip install openai ``` ```python import os from openai import OpenAI client = OpenAI( api_key=os.environ["NEON_AI_GATEWAY_TOKEN"], base_url=f"{os.environ['NEON_AI_GATEWAY_BASE_URL']}/v1", ) resp = client.chat.completions.create( model="gpt-5-1", messages=[{"role": "user", "content": "Explain Serverless Postgres."}], ) print(resp.choices[0].message.content) ``` #### cURL ```bash curl "${NEON_AI_GATEWAY_BASE_URL}/v1/chat/completions" \ -H "Authorization: Bearer ${NEON_AI_GATEWAY_TOKEN}" \ -H "Content-Type: application/json" \ -d '{ "model": "gpt-5-1", "messages": [{"role": "user", "content": "Explain Serverless Postgres."}] }' ``` ### Image generation #### AI SDK Install: ```bash npm i ai @neon/ai-sdk-provider ``` ```typescript import { streamText } from "ai"; import { neon } from "@neon/ai-sdk-provider"; const result = streamText({ model: neon("gpt-5-1"), prompt: "A red apple on a wooden table.", tools: { image_generation: neon.tools.imageGeneration({ model: "gpt-image-2", outputFormat: "jpeg", }), }, }); for await (const _ of result.textStream) {} const images = (await result.toolResults).filter((r) => r.toolName === "image_generation"); console.log(images.length); ``` #### Mastra Install: ```bash npm i @mastra/core ai @neon/ai-sdk-provider ``` ```typescript import { Agent } from "@mastra/core/agent"; import { neon } from "@neon/ai-sdk-provider"; const agent = new Agent({ id: "neon-demo", name: "neon-demo", instructions: "Generate the image the user asks for.", model: "neon/gpt-5-1", tools: { image_generation: neon.tools.imageGeneration({ model: "gpt-image-2", outputFormat: "jpeg", }), }, }); const { toolResults } = await agent.generate("A red apple on a wooden table."); const images = toolResults.filter((r) => r.payload.toolName === "image_generation"); console.log(images.map((r) => r.payload.result.result.length)); ``` #### TypeScript Install: ```bash npm i openai ``` ```typescript import OpenAI from "openai"; const client = new OpenAI({ apiKey: process.env.NEON_AI_GATEWAY_TOKEN, baseURL: `${process.env.NEON_AI_GATEWAY_BASE_URL}/openai/v1`, }); const stream = client.responses.stream({ model: "gpt-5-1", input: "A red apple on a wooden table.", tools: [{ type: "image_generation", model: "gpt-image-2" }], }); const response = await stream.finalResponse(); const sizes = response.output.flatMap((item) => { if (item.type !== "image_generation_call") return []; if (!("result" in item) || typeof item.result !== "string") return []; return [item.result.length]; }); console.log(sizes); ``` #### Python Install: ```bash pip install openai ``` ```python import os from openai import OpenAI client = OpenAI( api_key=os.environ["NEON_AI_GATEWAY_TOKEN"], base_url=f"{os.environ['NEON_AI_GATEWAY_BASE_URL']}/openai/v1", ) with client.responses.stream( model="gpt-5-1", input="A red apple on a wooden table.", tools=[{"type": "image_generation", "model": "gpt-image-2"}], ) as stream: for _ in stream: pass response = stream.get_final_response() sizes = [ len(item.result) for item in response.output if item.type == "image_generation_call" and getattr(item, "result", None) ] print(sizes) ``` **Environment variables** ```bash # Injected by `neon env pull` when AI Gateway is enabled on the branch (neon.ts preview.aiGateway). # Neon injects ONLY the NEON_AI_GATEWAY_* vars (not OPENAI_*). Build the OpenAI SDK / curl # apiKey + baseURL from them: apiKey = NEON_AI_GATEWAY_TOKEN (the bearer, nt_live_...). # # NEON_AI_GATEWAY_BASE_URL is the bare gateway host (no path). Append the route you need: # - `/v1` - unified Chat Completions and `/v1/embeddings` # - `/openai/v1` - OpenAI Responses API # - `/typesafe` - TypeSafe SDK base URL for System One decisions (`/typesafe/v1/systemone`) # @neon/ai-sdk-provider and Mastra route requests automatically. NEON_AI_GATEWAY_TOKEN=nt_live_... NEON_AI_GATEWAY_BASE_URL=https://-api.ai....neon.tech ``` ## Model ID gpt-5-1 ## Lab OpenAI makes GPT-5.1. Access the model through the Neon AI Gateway using chat/completions and openai/responses. ## Provider Databricks ## Inputs Text, image ## Context 400K ## Released Nov 2025 ## Input /M $1.25 ## Output /M $10 --- [Document source](https://neon.com/docs/ai-gateway/models/gpt-5-2.md) --- # GPT-5.2 ## About Neon AI Gateway provides GPT-5.2 by OpenAI. The model supports text, image inputs and a 400K context window. ## Command ### Text generation #### AI SDK Install: ```bash npm i ai @neon/ai-sdk-provider ``` ```typescript import { generateText } from "ai"; import { neon } from "@neon/ai-sdk-provider"; const { text } = await generateText({ model: neon("gpt-5-2"), prompt: "Explain Serverless Postgres.", }); console.log(text); ``` #### Mastra Install: ```bash npm i @mastra/core ``` ```typescript import { Agent } from "@mastra/core/agent"; const agent = new Agent({ id: "neon-demo", name: "neon-demo", instructions: "You are a helpful assistant.", model: "neon/gpt-5-2", }); const { text } = await agent.generate("Explain Serverless Postgres."); console.log(text); ``` #### TypeScript Install: ```bash npm i openai ``` ```typescript import OpenAI from "openai"; const client = new OpenAI({ apiKey: process.env.NEON_AI_GATEWAY_TOKEN, baseURL: `${process.env.NEON_AI_GATEWAY_BASE_URL}/v1`, }); const resp = await client.chat.completions.create({ model: "gpt-5-2", messages: [{ role: "user", content: "Explain Serverless Postgres." }], }); console.log(resp.choices[0].message.content); ``` #### Python Install: ```bash pip install openai ``` ```python import os from openai import OpenAI client = OpenAI( api_key=os.environ["NEON_AI_GATEWAY_TOKEN"], base_url=f"{os.environ['NEON_AI_GATEWAY_BASE_URL']}/v1", ) resp = client.chat.completions.create( model="gpt-5-2", messages=[{"role": "user", "content": "Explain Serverless Postgres."}], ) print(resp.choices[0].message.content) ``` #### cURL ```bash curl "${NEON_AI_GATEWAY_BASE_URL}/v1/chat/completions" \ -H "Authorization: Bearer ${NEON_AI_GATEWAY_TOKEN}" \ -H "Content-Type: application/json" \ -d '{ "model": "gpt-5-2", "messages": [{"role": "user", "content": "Explain Serverless Postgres."}] }' ``` ### Image generation #### AI SDK Install: ```bash npm i ai @neon/ai-sdk-provider ``` ```typescript import { streamText } from "ai"; import { neon } from "@neon/ai-sdk-provider"; const result = streamText({ model: neon("gpt-5-2"), prompt: "A red apple on a wooden table.", tools: { image_generation: neon.tools.imageGeneration({ model: "gpt-image-2", outputFormat: "jpeg", }), }, }); for await (const _ of result.textStream) {} const images = (await result.toolResults).filter((r) => r.toolName === "image_generation"); console.log(images.length); ``` #### Mastra Install: ```bash npm i @mastra/core ai @neon/ai-sdk-provider ``` ```typescript import { Agent } from "@mastra/core/agent"; import { neon } from "@neon/ai-sdk-provider"; const agent = new Agent({ id: "neon-demo", name: "neon-demo", instructions: "Generate the image the user asks for.", model: "neon/gpt-5-2", tools: { image_generation: neon.tools.imageGeneration({ model: "gpt-image-2", outputFormat: "jpeg", }), }, }); const { toolResults } = await agent.generate("A red apple on a wooden table."); const images = toolResults.filter((r) => r.payload.toolName === "image_generation"); console.log(images.map((r) => r.payload.result.result.length)); ``` #### TypeScript Install: ```bash npm i openai ``` ```typescript import OpenAI from "openai"; const client = new OpenAI({ apiKey: process.env.NEON_AI_GATEWAY_TOKEN, baseURL: `${process.env.NEON_AI_GATEWAY_BASE_URL}/openai/v1`, }); const stream = client.responses.stream({ model: "gpt-5-2", input: "A red apple on a wooden table.", tools: [{ type: "image_generation", model: "gpt-image-2" }], }); const response = await stream.finalResponse(); const sizes = response.output.flatMap((item) => { if (item.type !== "image_generation_call") return []; if (!("result" in item) || typeof item.result !== "string") return []; return [item.result.length]; }); console.log(sizes); ``` #### Python Install: ```bash pip install openai ``` ```python import os from openai import OpenAI client = OpenAI( api_key=os.environ["NEON_AI_GATEWAY_TOKEN"], base_url=f"{os.environ['NEON_AI_GATEWAY_BASE_URL']}/openai/v1", ) with client.responses.stream( model="gpt-5-2", input="A red apple on a wooden table.", tools=[{"type": "image_generation", "model": "gpt-image-2"}], ) as stream: for _ in stream: pass response = stream.get_final_response() sizes = [ len(item.result) for item in response.output if item.type == "image_generation_call" and getattr(item, "result", None) ] print(sizes) ``` **Environment variables** ```bash # Injected by `neon env pull` when AI Gateway is enabled on the branch (neon.ts preview.aiGateway). # Neon injects ONLY the NEON_AI_GATEWAY_* vars (not OPENAI_*). Build the OpenAI SDK / curl # apiKey + baseURL from them: apiKey = NEON_AI_GATEWAY_TOKEN (the bearer, nt_live_...). # # NEON_AI_GATEWAY_BASE_URL is the bare gateway host (no path). Append the route you need: # - `/v1` - unified Chat Completions and `/v1/embeddings` # - `/openai/v1` - OpenAI Responses API # - `/typesafe` - TypeSafe SDK base URL for System One decisions (`/typesafe/v1/systemone`) # @neon/ai-sdk-provider and Mastra route requests automatically. NEON_AI_GATEWAY_TOKEN=nt_live_... NEON_AI_GATEWAY_BASE_URL=https://-api.ai....neon.tech ``` ## Model ID gpt-5-2 ## Lab OpenAI makes GPT-5.2. Access the model through the Neon AI Gateway using chat/completions and openai/responses. ## Provider Databricks ## Inputs Text, image ## Context 400K ## Released Dec 2025 ## Input /M $1.75 ## Output /M $14 --- [Document source](https://neon.com/docs/ai-gateway/models/gpt-5-3-codex.md) --- # GPT-5.3 Codex ## About Neon AI Gateway provides GPT-5.3 Codex by OpenAI. The model supports text, image, pdf inputs and a 400K context window. ## Command ### Text generation #### AI SDK Install: ```bash npm i ai @neon/ai-sdk-provider ``` ```typescript import { generateText } from "ai"; import { neon } from "@neon/ai-sdk-provider"; const { text } = await generateText({ model: neon("gpt-5-3-codex"), prompt: "Explain Serverless Postgres.", }); console.log(text); ``` #### Mastra Install: ```bash npm i @mastra/core ai @neon/ai-sdk-provider ``` ```typescript import { Agent } from "@mastra/core/agent"; import { neon } from "@neon/ai-sdk-provider"; const agent = new Agent({ id: "neon-demo", name: "neon-demo", instructions: "You are a helpful assistant.", model: neon("gpt-5-3-codex"), }); const { text } = await agent.generate("Explain Serverless Postgres."); console.log(text); ``` #### TypeScript Install: ```bash npm i openai ``` ```typescript import OpenAI from "openai"; const client = new OpenAI({ apiKey: process.env.NEON_AI_GATEWAY_TOKEN, baseURL: `${process.env.NEON_AI_GATEWAY_BASE_URL}/openai/v1`, }); const response = await client.responses.create({ model: "gpt-5-3-codex", input: "Explain Serverless Postgres.", }); console.log(response.output_text); ``` #### Python Install: ```bash pip install openai ``` ```python import os from openai import OpenAI client = OpenAI( api_key=os.environ["NEON_AI_GATEWAY_TOKEN"], base_url=f"{os.environ['NEON_AI_GATEWAY_BASE_URL']}/openai/v1", ) response = client.responses.create( model="gpt-5-3-codex", input="Explain Serverless Postgres.", ) print(response.output_text) ``` #### cURL ```bash curl "${NEON_AI_GATEWAY_BASE_URL}/openai/v1/responses" \ -H "Authorization: Bearer ${NEON_AI_GATEWAY_TOKEN}" \ -H "Content-Type: application/json" \ -d '{ "model": "gpt-5-3-codex", "input": "Explain Serverless Postgres." }' ``` ### Image generation #### AI SDK Install: ```bash npm i ai @neon/ai-sdk-provider ``` ```typescript import { streamText } from "ai"; import { neon } from "@neon/ai-sdk-provider"; const result = streamText({ model: neon("gpt-5-3-codex"), prompt: "A red apple on a wooden table.", tools: { image_generation: neon.tools.imageGeneration({ model: "gpt-image-2", outputFormat: "jpeg", }), }, }); for await (const _ of result.textStream) {} const images = (await result.toolResults).filter((r) => r.toolName === "image_generation"); console.log(images.length); ``` #### Mastra Install: ```bash npm i @mastra/core ai @neon/ai-sdk-provider ``` ```typescript import { Agent } from "@mastra/core/agent"; import { neon } from "@neon/ai-sdk-provider"; const agent = new Agent({ id: "neon-demo", name: "neon-demo", instructions: "Generate the image the user asks for.", model: "neon/gpt-5-3-codex", tools: { image_generation: neon.tools.imageGeneration({ model: "gpt-image-2", outputFormat: "jpeg", }), }, }); const { toolResults } = await agent.generate("A red apple on a wooden table."); const images = toolResults.filter((r) => r.payload.toolName === "image_generation"); console.log(images.map((r) => r.payload.result.result.length)); ``` #### TypeScript Install: ```bash npm i openai ``` ```typescript import OpenAI from "openai"; const client = new OpenAI({ apiKey: process.env.NEON_AI_GATEWAY_TOKEN, baseURL: `${process.env.NEON_AI_GATEWAY_BASE_URL}/openai/v1`, }); const stream = client.responses.stream({ model: "gpt-5-3-codex", input: "A red apple on a wooden table.", tools: [{ type: "image_generation", model: "gpt-image-2" }], }); const response = await stream.finalResponse(); const sizes = response.output.flatMap((item) => { if (item.type !== "image_generation_call") return []; if (!("result" in item) || typeof item.result !== "string") return []; return [item.result.length]; }); console.log(sizes); ``` #### Python Install: ```bash pip install openai ``` ```python import os from openai import OpenAI client = OpenAI( api_key=os.environ["NEON_AI_GATEWAY_TOKEN"], base_url=f"{os.environ['NEON_AI_GATEWAY_BASE_URL']}/openai/v1", ) with client.responses.stream( model="gpt-5-3-codex", input="A red apple on a wooden table.", tools=[{"type": "image_generation", "model": "gpt-image-2"}], ) as stream: for _ in stream: pass response = stream.get_final_response() sizes = [ len(item.result) for item in response.output if item.type == "image_generation_call" and getattr(item, "result", None) ] print(sizes) ``` **Environment variables** ```bash # Injected by `neon env pull` when AI Gateway is enabled on the branch (neon.ts preview.aiGateway). # Neon injects ONLY the NEON_AI_GATEWAY_* vars (not OPENAI_*). Build the OpenAI SDK / curl # apiKey + baseURL from them: apiKey = NEON_AI_GATEWAY_TOKEN (the bearer, nt_live_...). # # NEON_AI_GATEWAY_BASE_URL is the bare gateway host (no path). Append the route you need: # - `/v1` - unified Chat Completions and `/v1/embeddings` # - `/openai/v1` - OpenAI Responses API # - `/typesafe` - TypeSafe SDK base URL for System One decisions (`/typesafe/v1/systemone`) # @neon/ai-sdk-provider and Mastra route requests automatically. NEON_AI_GATEWAY_TOKEN=nt_live_... NEON_AI_GATEWAY_BASE_URL=https://-api.ai....neon.tech ``` ## Model ID gpt-5-3-codex ## Lab OpenAI makes GPT-5.3 Codex. Access the model through the Neon AI Gateway using openai/responses. ## Provider Databricks ## Inputs Text, image, pdf ## Context 400K ## Released Feb 2026 ## Input /M $1.75 ## Output /M $14 --- [Document source](https://neon.com/docs/ai-gateway/models/gpt-5-4-mini.md) --- # GPT-5.4 Mini ## About Neon AI Gateway provides GPT-5.4 Mini by OpenAI. The model supports text, image inputs and a 400K context window. ## Command ### Text generation #### AI SDK Install: ```bash npm i ai @neon/ai-sdk-provider ``` ```typescript import { generateText } from "ai"; import { neon } from "@neon/ai-sdk-provider"; const { text } = await generateText({ model: neon("gpt-5-4-mini"), prompt: "Explain Serverless Postgres.", }); console.log(text); ``` #### Mastra Install: ```bash npm i @mastra/core ``` ```typescript import { Agent } from "@mastra/core/agent"; const agent = new Agent({ id: "neon-demo", name: "neon-demo", instructions: "You are a helpful assistant.", model: "neon/gpt-5-4-mini", }); const { text } = await agent.generate("Explain Serverless Postgres."); console.log(text); ``` #### TypeScript Install: ```bash npm i openai ``` ```typescript import OpenAI from "openai"; const client = new OpenAI({ apiKey: process.env.NEON_AI_GATEWAY_TOKEN, baseURL: `${process.env.NEON_AI_GATEWAY_BASE_URL}/v1`, }); const resp = await client.chat.completions.create({ model: "gpt-5-4-mini", messages: [{ role: "user", content: "Explain Serverless Postgres." }], }); console.log(resp.choices[0].message.content); ``` #### Python Install: ```bash pip install openai ``` ```python import os from openai import OpenAI client = OpenAI( api_key=os.environ["NEON_AI_GATEWAY_TOKEN"], base_url=f"{os.environ['NEON_AI_GATEWAY_BASE_URL']}/v1", ) resp = client.chat.completions.create( model="gpt-5-4-mini", messages=[{"role": "user", "content": "Explain Serverless Postgres."}], ) print(resp.choices[0].message.content) ``` #### cURL ```bash curl "${NEON_AI_GATEWAY_BASE_URL}/v1/chat/completions" \ -H "Authorization: Bearer ${NEON_AI_GATEWAY_TOKEN}" \ -H "Content-Type: application/json" \ -d '{ "model": "gpt-5-4-mini", "messages": [{"role": "user", "content": "Explain Serverless Postgres."}] }' ``` ### Image generation #### AI SDK Install: ```bash npm i ai @neon/ai-sdk-provider ``` ```typescript import { streamText } from "ai"; import { neon } from "@neon/ai-sdk-provider"; const result = streamText({ model: neon("gpt-5-4-mini"), prompt: "A red apple on a wooden table.", tools: { image_generation: neon.tools.imageGeneration({ model: "gpt-image-2", outputFormat: "jpeg", }), }, }); for await (const _ of result.textStream) {} const images = (await result.toolResults).filter((r) => r.toolName === "image_generation"); console.log(images.length); ``` #### Mastra Install: ```bash npm i @mastra/core ai @neon/ai-sdk-provider ``` ```typescript import { Agent } from "@mastra/core/agent"; import { neon } from "@neon/ai-sdk-provider"; const agent = new Agent({ id: "neon-demo", name: "neon-demo", instructions: "Generate the image the user asks for.", model: "neon/gpt-5-4-mini", tools: { image_generation: neon.tools.imageGeneration({ model: "gpt-image-2", outputFormat: "jpeg", }), }, }); const { toolResults } = await agent.generate("A red apple on a wooden table."); const images = toolResults.filter((r) => r.payload.toolName === "image_generation"); console.log(images.map((r) => r.payload.result.result.length)); ``` #### TypeScript Install: ```bash npm i openai ``` ```typescript import OpenAI from "openai"; const client = new OpenAI({ apiKey: process.env.NEON_AI_GATEWAY_TOKEN, baseURL: `${process.env.NEON_AI_GATEWAY_BASE_URL}/openai/v1`, }); const stream = client.responses.stream({ model: "gpt-5-4-mini", input: "A red apple on a wooden table.", tools: [{ type: "image_generation", model: "gpt-image-2" }], }); const response = await stream.finalResponse(); const sizes = response.output.flatMap((item) => { if (item.type !== "image_generation_call") return []; if (!("result" in item) || typeof item.result !== "string") return []; return [item.result.length]; }); console.log(sizes); ``` #### Python Install: ```bash pip install openai ``` ```python import os from openai import OpenAI client = OpenAI( api_key=os.environ["NEON_AI_GATEWAY_TOKEN"], base_url=f"{os.environ['NEON_AI_GATEWAY_BASE_URL']}/openai/v1", ) with client.responses.stream( model="gpt-5-4-mini", input="A red apple on a wooden table.", tools=[{"type": "image_generation", "model": "gpt-image-2"}], ) as stream: for _ in stream: pass response = stream.get_final_response() sizes = [ len(item.result) for item in response.output if item.type == "image_generation_call" and getattr(item, "result", None) ] print(sizes) ``` **Environment variables** ```bash # Injected by `neon env pull` when AI Gateway is enabled on the branch (neon.ts preview.aiGateway). # Neon injects ONLY the NEON_AI_GATEWAY_* vars (not OPENAI_*). Build the OpenAI SDK / curl # apiKey + baseURL from them: apiKey = NEON_AI_GATEWAY_TOKEN (the bearer, nt_live_...). # # NEON_AI_GATEWAY_BASE_URL is the bare gateway host (no path). Append the route you need: # - `/v1` - unified Chat Completions and `/v1/embeddings` # - `/openai/v1` - OpenAI Responses API # - `/typesafe` - TypeSafe SDK base URL for System One decisions (`/typesafe/v1/systemone`) # @neon/ai-sdk-provider and Mastra route requests automatically. NEON_AI_GATEWAY_TOKEN=nt_live_... NEON_AI_GATEWAY_BASE_URL=https://-api.ai....neon.tech ``` ## Model ID gpt-5-4-mini ## Lab OpenAI makes GPT-5.4 Mini. Access the model through the Neon AI Gateway using chat/completions and openai/responses. ## Provider Databricks ## Inputs Text, image ## Context 400K ## Released Mar 2026 ## Input /M $0.75 ## Output /M $4.50 --- [Document source](https://neon.com/docs/ai-gateway/models/gpt-5-4-nano.md) --- # GPT-5.4 Nano ## About Neon AI Gateway provides GPT-5.4 Nano by OpenAI. The model supports text, image inputs and a 400K context window. ## Command ### Text generation #### AI SDK Install: ```bash npm i ai @neon/ai-sdk-provider ``` ```typescript import { generateText } from "ai"; import { neon } from "@neon/ai-sdk-provider"; const { text } = await generateText({ model: neon("gpt-5-4-nano"), prompt: "Explain Serverless Postgres.", }); console.log(text); ``` #### Mastra Install: ```bash npm i @mastra/core ``` ```typescript import { Agent } from "@mastra/core/agent"; const agent = new Agent({ id: "neon-demo", name: "neon-demo", instructions: "You are a helpful assistant.", model: "neon/gpt-5-4-nano", }); const { text } = await agent.generate("Explain Serverless Postgres."); console.log(text); ``` #### TypeScript Install: ```bash npm i openai ``` ```typescript import OpenAI from "openai"; const client = new OpenAI({ apiKey: process.env.NEON_AI_GATEWAY_TOKEN, baseURL: `${process.env.NEON_AI_GATEWAY_BASE_URL}/v1`, }); const resp = await client.chat.completions.create({ model: "gpt-5-4-nano", messages: [{ role: "user", content: "Explain Serverless Postgres." }], }); console.log(resp.choices[0].message.content); ``` #### Python Install: ```bash pip install openai ``` ```python import os from openai import OpenAI client = OpenAI( api_key=os.environ["NEON_AI_GATEWAY_TOKEN"], base_url=f"{os.environ['NEON_AI_GATEWAY_BASE_URL']}/v1", ) resp = client.chat.completions.create( model="gpt-5-4-nano", messages=[{"role": "user", "content": "Explain Serverless Postgres."}], ) print(resp.choices[0].message.content) ``` #### cURL ```bash curl "${NEON_AI_GATEWAY_BASE_URL}/v1/chat/completions" \ -H "Authorization: Bearer ${NEON_AI_GATEWAY_TOKEN}" \ -H "Content-Type: application/json" \ -d '{ "model": "gpt-5-4-nano", "messages": [{"role": "user", "content": "Explain Serverless Postgres."}] }' ``` ### Image generation #### AI SDK Install: ```bash npm i ai @neon/ai-sdk-provider ``` ```typescript import { streamText } from "ai"; import { neon } from "@neon/ai-sdk-provider"; const result = streamText({ model: neon("gpt-5-4-nano"), prompt: "A red apple on a wooden table.", tools: { image_generation: neon.tools.imageGeneration({ model: "gpt-image-2", outputFormat: "jpeg", }), }, }); for await (const _ of result.textStream) {} const images = (await result.toolResults).filter((r) => r.toolName === "image_generation"); console.log(images.length); ``` #### Mastra Install: ```bash npm i @mastra/core ai @neon/ai-sdk-provider ``` ```typescript import { Agent } from "@mastra/core/agent"; import { neon } from "@neon/ai-sdk-provider"; const agent = new Agent({ id: "neon-demo", name: "neon-demo", instructions: "Generate the image the user asks for.", model: "neon/gpt-5-4-nano", tools: { image_generation: neon.tools.imageGeneration({ model: "gpt-image-2", outputFormat: "jpeg", }), }, }); const { toolResults } = await agent.generate("A red apple on a wooden table."); const images = toolResults.filter((r) => r.payload.toolName === "image_generation"); console.log(images.map((r) => r.payload.result.result.length)); ``` #### TypeScript Install: ```bash npm i openai ``` ```typescript import OpenAI from "openai"; const client = new OpenAI({ apiKey: process.env.NEON_AI_GATEWAY_TOKEN, baseURL: `${process.env.NEON_AI_GATEWAY_BASE_URL}/openai/v1`, }); const stream = client.responses.stream({ model: "gpt-5-4-nano", input: "A red apple on a wooden table.", tools: [{ type: "image_generation", model: "gpt-image-2" }], }); const response = await stream.finalResponse(); const sizes = response.output.flatMap((item) => { if (item.type !== "image_generation_call") return []; if (!("result" in item) || typeof item.result !== "string") return []; return [item.result.length]; }); console.log(sizes); ``` #### Python Install: ```bash pip install openai ``` ```python import os from openai import OpenAI client = OpenAI( api_key=os.environ["NEON_AI_GATEWAY_TOKEN"], base_url=f"{os.environ['NEON_AI_GATEWAY_BASE_URL']}/openai/v1", ) with client.responses.stream( model="gpt-5-4-nano", input="A red apple on a wooden table.", tools=[{"type": "image_generation", "model": "gpt-image-2"}], ) as stream: for _ in stream: pass response = stream.get_final_response() sizes = [ len(item.result) for item in response.output if item.type == "image_generation_call" and getattr(item, "result", None) ] print(sizes) ``` **Environment variables** ```bash # Injected by `neon env pull` when AI Gateway is enabled on the branch (neon.ts preview.aiGateway). # Neon injects ONLY the NEON_AI_GATEWAY_* vars (not OPENAI_*). Build the OpenAI SDK / curl # apiKey + baseURL from them: apiKey = NEON_AI_GATEWAY_TOKEN (the bearer, nt_live_...). # # NEON_AI_GATEWAY_BASE_URL is the bare gateway host (no path). Append the route you need: # - `/v1` - unified Chat Completions and `/v1/embeddings` # - `/openai/v1` - OpenAI Responses API # - `/typesafe` - TypeSafe SDK base URL for System One decisions (`/typesafe/v1/systemone`) # @neon/ai-sdk-provider and Mastra route requests automatically. NEON_AI_GATEWAY_TOKEN=nt_live_... NEON_AI_GATEWAY_BASE_URL=https://-api.ai....neon.tech ``` ## Model ID gpt-5-4-nano ## Lab OpenAI makes GPT-5.4 Nano. Access the model through the Neon AI Gateway using chat/completions and openai/responses. ## Provider Databricks ## Inputs Text, image ## Context 400K ## Released Mar 2026 ## Input /M $0.20 ## Output /M $1.25 --- [Document source](https://neon.com/docs/ai-gateway/models/gpt-5-4.md) --- # GPT-5.4 ## About Neon AI Gateway provides GPT-5.4 by OpenAI. The model supports text, image, pdf inputs and a 1.1M context window. ## Command ### Text generation #### AI SDK Install: ```bash npm i ai @neon/ai-sdk-provider ``` ```typescript import { generateText } from "ai"; import { neon } from "@neon/ai-sdk-provider"; const { text } = await generateText({ model: neon("gpt-5-4"), prompt: "Explain Serverless Postgres.", }); console.log(text); ``` #### Mastra Install: ```bash npm i @mastra/core ``` ```typescript import { Agent } from "@mastra/core/agent"; const agent = new Agent({ id: "neon-demo", name: "neon-demo", instructions: "You are a helpful assistant.", model: "neon/gpt-5-4", }); const { text } = await agent.generate("Explain Serverless Postgres."); console.log(text); ``` #### TypeScript Install: ```bash npm i openai ``` ```typescript import OpenAI from "openai"; const client = new OpenAI({ apiKey: process.env.NEON_AI_GATEWAY_TOKEN, baseURL: `${process.env.NEON_AI_GATEWAY_BASE_URL}/v1`, }); const resp = await client.chat.completions.create({ model: "gpt-5-4", messages: [{ role: "user", content: "Explain Serverless Postgres." }], }); console.log(resp.choices[0].message.content); ``` #### Python Install: ```bash pip install openai ``` ```python import os from openai import OpenAI client = OpenAI( api_key=os.environ["NEON_AI_GATEWAY_TOKEN"], base_url=f"{os.environ['NEON_AI_GATEWAY_BASE_URL']}/v1", ) resp = client.chat.completions.create( model="gpt-5-4", messages=[{"role": "user", "content": "Explain Serverless Postgres."}], ) print(resp.choices[0].message.content) ``` #### cURL ```bash curl "${NEON_AI_GATEWAY_BASE_URL}/v1/chat/completions" \ -H "Authorization: Bearer ${NEON_AI_GATEWAY_TOKEN}" \ -H "Content-Type: application/json" \ -d '{ "model": "gpt-5-4", "messages": [{"role": "user", "content": "Explain Serverless Postgres."}] }' ``` ### Image generation #### AI SDK Install: ```bash npm i ai @neon/ai-sdk-provider ``` ```typescript import { streamText } from "ai"; import { neon } from "@neon/ai-sdk-provider"; const result = streamText({ model: neon("gpt-5-4"), prompt: "A red apple on a wooden table.", tools: { image_generation: neon.tools.imageGeneration({ model: "gpt-image-2", outputFormat: "jpeg", }), }, }); for await (const _ of result.textStream) {} const images = (await result.toolResults).filter((r) => r.toolName === "image_generation"); console.log(images.length); ``` #### Mastra Install: ```bash npm i @mastra/core ai @neon/ai-sdk-provider ``` ```typescript import { Agent } from "@mastra/core/agent"; import { neon } from "@neon/ai-sdk-provider"; const agent = new Agent({ id: "neon-demo", name: "neon-demo", instructions: "Generate the image the user asks for.", model: "neon/gpt-5-4", tools: { image_generation: neon.tools.imageGeneration({ model: "gpt-image-2", outputFormat: "jpeg", }), }, }); const { toolResults } = await agent.generate("A red apple on a wooden table."); const images = toolResults.filter((r) => r.payload.toolName === "image_generation"); console.log(images.map((r) => r.payload.result.result.length)); ``` #### TypeScript Install: ```bash npm i openai ``` ```typescript import OpenAI from "openai"; const client = new OpenAI({ apiKey: process.env.NEON_AI_GATEWAY_TOKEN, baseURL: `${process.env.NEON_AI_GATEWAY_BASE_URL}/openai/v1`, }); const stream = client.responses.stream({ model: "gpt-5-4", input: "A red apple on a wooden table.", tools: [{ type: "image_generation", model: "gpt-image-2" }], }); const response = await stream.finalResponse(); const sizes = response.output.flatMap((item) => { if (item.type !== "image_generation_call") return []; if (!("result" in item) || typeof item.result !== "string") return []; return [item.result.length]; }); console.log(sizes); ``` #### Python Install: ```bash pip install openai ``` ```python import os from openai import OpenAI client = OpenAI( api_key=os.environ["NEON_AI_GATEWAY_TOKEN"], base_url=f"{os.environ['NEON_AI_GATEWAY_BASE_URL']}/openai/v1", ) with client.responses.stream( model="gpt-5-4", input="A red apple on a wooden table.", tools=[{"type": "image_generation", "model": "gpt-image-2"}], ) as stream: for _ in stream: pass response = stream.get_final_response() sizes = [ len(item.result) for item in response.output if item.type == "image_generation_call" and getattr(item, "result", None) ] print(sizes) ``` **Environment variables** ```bash # Injected by `neon env pull` when AI Gateway is enabled on the branch (neon.ts preview.aiGateway). # Neon injects ONLY the NEON_AI_GATEWAY_* vars (not OPENAI_*). Build the OpenAI SDK / curl # apiKey + baseURL from them: apiKey = NEON_AI_GATEWAY_TOKEN (the bearer, nt_live_...). # # NEON_AI_GATEWAY_BASE_URL is the bare gateway host (no path). Append the route you need: # - `/v1` - unified Chat Completions and `/v1/embeddings` # - `/openai/v1` - OpenAI Responses API # - `/typesafe` - TypeSafe SDK base URL for System One decisions (`/typesafe/v1/systemone`) # @neon/ai-sdk-provider and Mastra route requests automatically. NEON_AI_GATEWAY_TOKEN=nt_live_... NEON_AI_GATEWAY_BASE_URL=https://-api.ai....neon.tech ``` ## Model ID gpt-5-4 ## Lab OpenAI makes GPT-5.4. Access the model through the Neon AI Gateway using chat/completions and openai/responses. ## Provider Databricks ## Inputs Text, image, pdf ## Context 1.1M ## Released Mar 2026 ## Input /M $2.50 ## Output /M $15 --- [Document source](https://neon.com/docs/ai-gateway/models/gpt-5-5-pro.md) --- # GPT-5.5 Pro ## About Neon AI Gateway provides GPT-5.5 Pro by OpenAI. The model supports text, image, pdf inputs and a 1.1M context window. ## Command ### Text generation #### AI SDK Install: ```bash npm i ai @neon/ai-sdk-provider ``` ```typescript import { generateText } from "ai"; import { neon } from "@neon/ai-sdk-provider"; const { text } = await generateText({ model: neon("gpt-5-5-pro"), prompt: "Explain Serverless Postgres.", }); console.log(text); ``` #### Mastra Install: ```bash npm i @mastra/core ai @neon/ai-sdk-provider ``` ```typescript import { Agent } from "@mastra/core/agent"; import { neon } from "@neon/ai-sdk-provider"; const agent = new Agent({ id: "neon-demo", name: "neon-demo", instructions: "You are a helpful assistant.", model: neon("gpt-5-5-pro"), }); const { text } = await agent.generate("Explain Serverless Postgres."); console.log(text); ``` #### TypeScript Install: ```bash npm i openai ``` ```typescript import OpenAI from "openai"; const client = new OpenAI({ apiKey: process.env.NEON_AI_GATEWAY_TOKEN, baseURL: `${process.env.NEON_AI_GATEWAY_BASE_URL}/openai/v1`, }); const response = await client.responses.create({ model: "gpt-5-5-pro", input: "Explain Serverless Postgres.", }); console.log(response.output_text); ``` #### Python Install: ```bash pip install openai ``` ```python import os from openai import OpenAI client = OpenAI( api_key=os.environ["NEON_AI_GATEWAY_TOKEN"], base_url=f"{os.environ['NEON_AI_GATEWAY_BASE_URL']}/openai/v1", ) response = client.responses.create( model="gpt-5-5-pro", input="Explain Serverless Postgres.", ) print(response.output_text) ``` #### cURL ```bash curl "${NEON_AI_GATEWAY_BASE_URL}/openai/v1/responses" \ -H "Authorization: Bearer ${NEON_AI_GATEWAY_TOKEN}" \ -H "Content-Type: application/json" \ -d '{ "model": "gpt-5-5-pro", "input": "Explain Serverless Postgres." }' ``` ### Image generation #### AI SDK Install: ```bash npm i ai @neon/ai-sdk-provider ``` ```typescript import { streamText } from "ai"; import { neon } from "@neon/ai-sdk-provider"; const result = streamText({ model: neon("gpt-5-5-pro"), prompt: "A red apple on a wooden table.", tools: { image_generation: neon.tools.imageGeneration({ model: "gpt-image-2", outputFormat: "jpeg", }), }, }); for await (const _ of result.textStream) {} const images = (await result.toolResults).filter((r) => r.toolName === "image_generation"); console.log(images.length); ``` #### Mastra Install: ```bash npm i @mastra/core ai @neon/ai-sdk-provider ``` ```typescript import { Agent } from "@mastra/core/agent"; import { neon } from "@neon/ai-sdk-provider"; const agent = new Agent({ id: "neon-demo", name: "neon-demo", instructions: "Generate the image the user asks for.", model: "neon/gpt-5-5-pro", tools: { image_generation: neon.tools.imageGeneration({ model: "gpt-image-2", outputFormat: "jpeg", }), }, }); const { toolResults } = await agent.generate("A red apple on a wooden table."); const images = toolResults.filter((r) => r.payload.toolName === "image_generation"); console.log(images.map((r) => r.payload.result.result.length)); ``` #### TypeScript Install: ```bash npm i openai ``` ```typescript import OpenAI from "openai"; const client = new OpenAI({ apiKey: process.env.NEON_AI_GATEWAY_TOKEN, baseURL: `${process.env.NEON_AI_GATEWAY_BASE_URL}/openai/v1`, }); const stream = client.responses.stream({ model: "gpt-5-5-pro", input: "A red apple on a wooden table.", tools: [{ type: "image_generation", model: "gpt-image-2" }], }); const response = await stream.finalResponse(); const sizes = response.output.flatMap((item) => { if (item.type !== "image_generation_call") return []; if (!("result" in item) || typeof item.result !== "string") return []; return [item.result.length]; }); console.log(sizes); ``` #### Python Install: ```bash pip install openai ``` ```python import os from openai import OpenAI client = OpenAI( api_key=os.environ["NEON_AI_GATEWAY_TOKEN"], base_url=f"{os.environ['NEON_AI_GATEWAY_BASE_URL']}/openai/v1", ) with client.responses.stream( model="gpt-5-5-pro", input="A red apple on a wooden table.", tools=[{"type": "image_generation", "model": "gpt-image-2"}], ) as stream: for _ in stream: pass response = stream.get_final_response() sizes = [ len(item.result) for item in response.output if item.type == "image_generation_call" and getattr(item, "result", None) ] print(sizes) ``` **Environment variables** ```bash # Injected by `neon env pull` when AI Gateway is enabled on the branch (neon.ts preview.aiGateway). # Neon injects ONLY the NEON_AI_GATEWAY_* vars (not OPENAI_*). Build the OpenAI SDK / curl # apiKey + baseURL from them: apiKey = NEON_AI_GATEWAY_TOKEN (the bearer, nt_live_...). # # NEON_AI_GATEWAY_BASE_URL is the bare gateway host (no path). Append the route you need: # - `/v1` - unified Chat Completions and `/v1/embeddings` # - `/openai/v1` - OpenAI Responses API # - `/typesafe` - TypeSafe SDK base URL for System One decisions (`/typesafe/v1/systemone`) # @neon/ai-sdk-provider and Mastra route requests automatically. NEON_AI_GATEWAY_TOKEN=nt_live_... NEON_AI_GATEWAY_BASE_URL=https://-api.ai....neon.tech ``` ## Model ID gpt-5-5-pro ## Lab OpenAI makes GPT-5.5 Pro. Access the model through the Neon AI Gateway using openai/responses. ## Provider Databricks ## Inputs Text, image, pdf ## Context 1.1M ## Released Apr 2026 ## Input /M $30 ## Output /M $180 --- [Document source](https://neon.com/docs/ai-gateway/models/gpt-5-5.md) --- # GPT-5.5 ## About Neon AI Gateway provides GPT-5.5 by OpenAI. The model supports text, image, pdf inputs and a 1.1M context window. ## Command ### Text generation #### AI SDK Install: ```bash npm i ai @neon/ai-sdk-provider ``` ```typescript import { generateText } from "ai"; import { neon } from "@neon/ai-sdk-provider"; const { text } = await generateText({ model: neon("gpt-5-5"), prompt: "Explain Serverless Postgres.", }); console.log(text); ``` #### Mastra Install: ```bash npm i @mastra/core ``` ```typescript import { Agent } from "@mastra/core/agent"; const agent = new Agent({ id: "neon-demo", name: "neon-demo", instructions: "You are a helpful assistant.", model: "neon/gpt-5-5", }); const { text } = await agent.generate("Explain Serverless Postgres."); console.log(text); ``` #### TypeScript Install: ```bash npm i openai ``` ```typescript import OpenAI from "openai"; const client = new OpenAI({ apiKey: process.env.NEON_AI_GATEWAY_TOKEN, baseURL: `${process.env.NEON_AI_GATEWAY_BASE_URL}/v1`, }); const resp = await client.chat.completions.create({ model: "gpt-5-5", messages: [{ role: "user", content: "Explain Serverless Postgres." }], }); console.log(resp.choices[0].message.content); ``` #### Python Install: ```bash pip install openai ``` ```python import os from openai import OpenAI client = OpenAI( api_key=os.environ["NEON_AI_GATEWAY_TOKEN"], base_url=f"{os.environ['NEON_AI_GATEWAY_BASE_URL']}/v1", ) resp = client.chat.completions.create( model="gpt-5-5", messages=[{"role": "user", "content": "Explain Serverless Postgres."}], ) print(resp.choices[0].message.content) ``` #### cURL ```bash curl "${NEON_AI_GATEWAY_BASE_URL}/v1/chat/completions" \ -H "Authorization: Bearer ${NEON_AI_GATEWAY_TOKEN}" \ -H "Content-Type: application/json" \ -d '{ "model": "gpt-5-5", "messages": [{"role": "user", "content": "Explain Serverless Postgres."}] }' ``` ### Image generation #### AI SDK Install: ```bash npm i ai @neon/ai-sdk-provider ``` ```typescript import { streamText } from "ai"; import { neon } from "@neon/ai-sdk-provider"; const result = streamText({ model: neon("gpt-5-5"), prompt: "A red apple on a wooden table.", tools: { image_generation: neon.tools.imageGeneration({ model: "gpt-image-2", outputFormat: "jpeg", }), }, }); for await (const _ of result.textStream) {} const images = (await result.toolResults).filter((r) => r.toolName === "image_generation"); console.log(images.length); ``` #### Mastra Install: ```bash npm i @mastra/core ai @neon/ai-sdk-provider ``` ```typescript import { Agent } from "@mastra/core/agent"; import { neon } from "@neon/ai-sdk-provider"; const agent = new Agent({ id: "neon-demo", name: "neon-demo", instructions: "Generate the image the user asks for.", model: "neon/gpt-5-5", tools: { image_generation: neon.tools.imageGeneration({ model: "gpt-image-2", outputFormat: "jpeg", }), }, }); const { toolResults } = await agent.generate("A red apple on a wooden table."); const images = toolResults.filter((r) => r.payload.toolName === "image_generation"); console.log(images.map((r) => r.payload.result.result.length)); ``` #### TypeScript Install: ```bash npm i openai ``` ```typescript import OpenAI from "openai"; const client = new OpenAI({ apiKey: process.env.NEON_AI_GATEWAY_TOKEN, baseURL: `${process.env.NEON_AI_GATEWAY_BASE_URL}/openai/v1`, }); const stream = client.responses.stream({ model: "gpt-5-5", input: "A red apple on a wooden table.", tools: [{ type: "image_generation", model: "gpt-image-2" }], }); const response = await stream.finalResponse(); const sizes = response.output.flatMap((item) => { if (item.type !== "image_generation_call") return []; if (!("result" in item) || typeof item.result !== "string") return []; return [item.result.length]; }); console.log(sizes); ``` #### Python Install: ```bash pip install openai ``` ```python import os from openai import OpenAI client = OpenAI( api_key=os.environ["NEON_AI_GATEWAY_TOKEN"], base_url=f"{os.environ['NEON_AI_GATEWAY_BASE_URL']}/openai/v1", ) with client.responses.stream( model="gpt-5-5", input="A red apple on a wooden table.", tools=[{"type": "image_generation", "model": "gpt-image-2"}], ) as stream: for _ in stream: pass response = stream.get_final_response() sizes = [ len(item.result) for item in response.output if item.type == "image_generation_call" and getattr(item, "result", None) ] print(sizes) ``` **Environment variables** ```bash # Injected by `neon env pull` when AI Gateway is enabled on the branch (neon.ts preview.aiGateway). # Neon injects ONLY the NEON_AI_GATEWAY_* vars (not OPENAI_*). Build the OpenAI SDK / curl # apiKey + baseURL from them: apiKey = NEON_AI_GATEWAY_TOKEN (the bearer, nt_live_...). # # NEON_AI_GATEWAY_BASE_URL is the bare gateway host (no path). Append the route you need: # - `/v1` - unified Chat Completions and `/v1/embeddings` # - `/openai/v1` - OpenAI Responses API # - `/typesafe` - TypeSafe SDK base URL for System One decisions (`/typesafe/v1/systemone`) # @neon/ai-sdk-provider and Mastra route requests automatically. NEON_AI_GATEWAY_TOKEN=nt_live_... NEON_AI_GATEWAY_BASE_URL=https://-api.ai....neon.tech ``` ## Model ID gpt-5-5 ## Lab OpenAI makes GPT-5.5. Access the model through the Neon AI Gateway using chat/completions and openai/responses. ## Provider Databricks ## Inputs Text, image, pdf ## Context 1.1M ## Released Apr 2026 ## Input /M $5 ## Output /M $30 --- [Document source](https://neon.com/docs/ai-gateway/models/gpt-5-6-luna.md) --- # GPT-5.6 Luna ## About Neon AI Gateway provides GPT-5.6 Luna by OpenAI. The model supports text, image, pdf inputs and a 1.1M context window. ## Command ### Text generation #### AI SDK Install: ```bash npm i ai @neon/ai-sdk-provider ``` ```typescript import { generateText } from "ai"; import { neon } from "@neon/ai-sdk-provider"; const { text } = await generateText({ model: neon("gpt-5-6-luna"), prompt: "Explain Serverless Postgres.", }); console.log(text); ``` #### Mastra Install: ```bash npm i @mastra/core ``` ```typescript import { Agent } from "@mastra/core/agent"; const agent = new Agent({ id: "neon-demo", name: "neon-demo", instructions: "You are a helpful assistant.", model: "neon/gpt-5-6-luna", }); const { text } = await agent.generate("Explain Serverless Postgres."); console.log(text); ``` #### TypeScript Install: ```bash npm i openai ``` ```typescript import OpenAI from "openai"; const client = new OpenAI({ apiKey: process.env.NEON_AI_GATEWAY_TOKEN, baseURL: `${process.env.NEON_AI_GATEWAY_BASE_URL}/v1`, }); const resp = await client.chat.completions.create({ model: "gpt-5-6-luna", messages: [{ role: "user", content: "Explain Serverless Postgres." }], }); console.log(resp.choices[0].message.content); ``` #### Python Install: ```bash pip install openai ``` ```python import os from openai import OpenAI client = OpenAI( api_key=os.environ["NEON_AI_GATEWAY_TOKEN"], base_url=f"{os.environ['NEON_AI_GATEWAY_BASE_URL']}/v1", ) resp = client.chat.completions.create( model="gpt-5-6-luna", messages=[{"role": "user", "content": "Explain Serverless Postgres."}], ) print(resp.choices[0].message.content) ``` #### cURL ```bash curl "${NEON_AI_GATEWAY_BASE_URL}/v1/chat/completions" \ -H "Authorization: Bearer ${NEON_AI_GATEWAY_TOKEN}" \ -H "Content-Type: application/json" \ -d '{ "model": "gpt-5-6-luna", "messages": [{"role": "user", "content": "Explain Serverless Postgres."}] }' ``` ### Image generation #### AI SDK Install: ```bash npm i ai @neon/ai-sdk-provider ``` ```typescript import { streamText } from "ai"; import { neon } from "@neon/ai-sdk-provider"; const result = streamText({ model: neon("gpt-5-6-luna"), prompt: "A red apple on a wooden table.", tools: { image_generation: neon.tools.imageGeneration({ model: "gpt-image-2", outputFormat: "jpeg", }), }, }); for await (const _ of result.textStream) {} const images = (await result.toolResults).filter((r) => r.toolName === "image_generation"); console.log(images.length); ``` #### Mastra Install: ```bash npm i @mastra/core ai @neon/ai-sdk-provider ``` ```typescript import { Agent } from "@mastra/core/agent"; import { neon } from "@neon/ai-sdk-provider"; const agent = new Agent({ id: "neon-demo", name: "neon-demo", instructions: "Generate the image the user asks for.", model: "neon/gpt-5-6-luna", tools: { image_generation: neon.tools.imageGeneration({ model: "gpt-image-2", outputFormat: "jpeg", }), }, }); const { toolResults } = await agent.generate("A red apple on a wooden table."); const images = toolResults.filter((r) => r.payload.toolName === "image_generation"); console.log(images.map((r) => r.payload.result.result.length)); ``` #### TypeScript Install: ```bash npm i openai ``` ```typescript import OpenAI from "openai"; const client = new OpenAI({ apiKey: process.env.NEON_AI_GATEWAY_TOKEN, baseURL: `${process.env.NEON_AI_GATEWAY_BASE_URL}/openai/v1`, }); const stream = client.responses.stream({ model: "gpt-5-6-luna", input: "A red apple on a wooden table.", tools: [{ type: "image_generation", model: "gpt-image-2" }], }); const response = await stream.finalResponse(); const sizes = response.output.flatMap((item) => { if (item.type !== "image_generation_call") return []; if (!("result" in item) || typeof item.result !== "string") return []; return [item.result.length]; }); console.log(sizes); ``` #### Python Install: ```bash pip install openai ``` ```python import os from openai import OpenAI client = OpenAI( api_key=os.environ["NEON_AI_GATEWAY_TOKEN"], base_url=f"{os.environ['NEON_AI_GATEWAY_BASE_URL']}/openai/v1", ) with client.responses.stream( model="gpt-5-6-luna", input="A red apple on a wooden table.", tools=[{"type": "image_generation", "model": "gpt-image-2"}], ) as stream: for _ in stream: pass response = stream.get_final_response() sizes = [ len(item.result) for item in response.output if item.type == "image_generation_call" and getattr(item, "result", None) ] print(sizes) ``` **Environment variables** ```bash # Injected by `neon env pull` when AI Gateway is enabled on the branch (neon.ts preview.aiGateway). # Neon injects ONLY the NEON_AI_GATEWAY_* vars (not OPENAI_*). Build the OpenAI SDK / curl # apiKey + baseURL from them: apiKey = NEON_AI_GATEWAY_TOKEN (the bearer, nt_live_...). # # NEON_AI_GATEWAY_BASE_URL is the bare gateway host (no path). Append the route you need: # - `/v1` - unified Chat Completions and `/v1/embeddings` # - `/openai/v1` - OpenAI Responses API # - `/typesafe` - TypeSafe SDK base URL for System One decisions (`/typesafe/v1/systemone`) # @neon/ai-sdk-provider and Mastra route requests automatically. NEON_AI_GATEWAY_TOKEN=nt_live_... NEON_AI_GATEWAY_BASE_URL=https://-api.ai....neon.tech ``` ## Model ID gpt-5-6-luna ## Lab OpenAI makes GPT-5.6 Luna. Access the model through the Neon AI Gateway using chat/completions and openai/responses. ## Provider Databricks ## Inputs Text, image, pdf ## Context 1.1M ## Released Jul 2026 ## Input /M $0.20 ## Output /M $1.20 --- [Document source](https://neon.com/docs/ai-gateway/models/gpt-5-6-sol.md) --- # GPT-5.6 Sol ## About Neon AI Gateway provides GPT-5.6 Sol by OpenAI. The model supports text, image, pdf inputs and a 1.1M context window. ## Command ### Text generation #### AI SDK Install: ```bash npm i ai @neon/ai-sdk-provider ``` ```typescript import { generateText } from "ai"; import { neon } from "@neon/ai-sdk-provider"; const { text } = await generateText({ model: neon("gpt-5-6-sol"), prompt: "Explain Serverless Postgres.", }); console.log(text); ``` #### Mastra Install: ```bash npm i @mastra/core ``` ```typescript import { Agent } from "@mastra/core/agent"; const agent = new Agent({ id: "neon-demo", name: "neon-demo", instructions: "You are a helpful assistant.", model: "neon/gpt-5-6-sol", }); const { text } = await agent.generate("Explain Serverless Postgres."); console.log(text); ``` #### TypeScript Install: ```bash npm i openai ``` ```typescript import OpenAI from "openai"; const client = new OpenAI({ apiKey: process.env.NEON_AI_GATEWAY_TOKEN, baseURL: `${process.env.NEON_AI_GATEWAY_BASE_URL}/v1`, }); const resp = await client.chat.completions.create({ model: "gpt-5-6-sol", messages: [{ role: "user", content: "Explain Serverless Postgres." }], }); console.log(resp.choices[0].message.content); ``` #### Python Install: ```bash pip install openai ``` ```python import os from openai import OpenAI client = OpenAI( api_key=os.environ["NEON_AI_GATEWAY_TOKEN"], base_url=f"{os.environ['NEON_AI_GATEWAY_BASE_URL']}/v1", ) resp = client.chat.completions.create( model="gpt-5-6-sol", messages=[{"role": "user", "content": "Explain Serverless Postgres."}], ) print(resp.choices[0].message.content) ``` #### cURL ```bash curl "${NEON_AI_GATEWAY_BASE_URL}/v1/chat/completions" \ -H "Authorization: Bearer ${NEON_AI_GATEWAY_TOKEN}" \ -H "Content-Type: application/json" \ -d '{ "model": "gpt-5-6-sol", "messages": [{"role": "user", "content": "Explain Serverless Postgres."}] }' ``` ### Image generation #### AI SDK Install: ```bash npm i ai @neon/ai-sdk-provider ``` ```typescript import { streamText } from "ai"; import { neon } from "@neon/ai-sdk-provider"; const result = streamText({ model: neon("gpt-5-6-sol"), prompt: "A red apple on a wooden table.", tools: { image_generation: neon.tools.imageGeneration({ model: "gpt-image-2", outputFormat: "jpeg", }), }, }); for await (const _ of result.textStream) {} const images = (await result.toolResults).filter((r) => r.toolName === "image_generation"); console.log(images.length); ``` #### Mastra Install: ```bash npm i @mastra/core ai @neon/ai-sdk-provider ``` ```typescript import { Agent } from "@mastra/core/agent"; import { neon } from "@neon/ai-sdk-provider"; const agent = new Agent({ id: "neon-demo", name: "neon-demo", instructions: "Generate the image the user asks for.", model: "neon/gpt-5-6-sol", tools: { image_generation: neon.tools.imageGeneration({ model: "gpt-image-2", outputFormat: "jpeg", }), }, }); const { toolResults } = await agent.generate("A red apple on a wooden table."); const images = toolResults.filter((r) => r.payload.toolName === "image_generation"); console.log(images.map((r) => r.payload.result.result.length)); ``` #### TypeScript Install: ```bash npm i openai ``` ```typescript import OpenAI from "openai"; const client = new OpenAI({ apiKey: process.env.NEON_AI_GATEWAY_TOKEN, baseURL: `${process.env.NEON_AI_GATEWAY_BASE_URL}/openai/v1`, }); const stream = client.responses.stream({ model: "gpt-5-6-sol", input: "A red apple on a wooden table.", tools: [{ type: "image_generation", model: "gpt-image-2" }], }); const response = await stream.finalResponse(); const sizes = response.output.flatMap((item) => { if (item.type !== "image_generation_call") return []; if (!("result" in item) || typeof item.result !== "string") return []; return [item.result.length]; }); console.log(sizes); ``` #### Python Install: ```bash pip install openai ``` ```python import os from openai import OpenAI client = OpenAI( api_key=os.environ["NEON_AI_GATEWAY_TOKEN"], base_url=f"{os.environ['NEON_AI_GATEWAY_BASE_URL']}/openai/v1", ) with client.responses.stream( model="gpt-5-6-sol", input="A red apple on a wooden table.", tools=[{"type": "image_generation", "model": "gpt-image-2"}], ) as stream: for _ in stream: pass response = stream.get_final_response() sizes = [ len(item.result) for item in response.output if item.type == "image_generation_call" and getattr(item, "result", None) ] print(sizes) ``` **Environment variables** ```bash # Injected by `neon env pull` when AI Gateway is enabled on the branch (neon.ts preview.aiGateway). # Neon injects ONLY the NEON_AI_GATEWAY_* vars (not OPENAI_*). Build the OpenAI SDK / curl # apiKey + baseURL from them: apiKey = NEON_AI_GATEWAY_TOKEN (the bearer, nt_live_...). # # NEON_AI_GATEWAY_BASE_URL is the bare gateway host (no path). Append the route you need: # - `/v1` - unified Chat Completions and `/v1/embeddings` # - `/openai/v1` - OpenAI Responses API # - `/typesafe` - TypeSafe SDK base URL for System One decisions (`/typesafe/v1/systemone`) # @neon/ai-sdk-provider and Mastra route requests automatically. NEON_AI_GATEWAY_TOKEN=nt_live_... NEON_AI_GATEWAY_BASE_URL=https://-api.ai....neon.tech ``` ## Model ID gpt-5-6-sol ## Lab OpenAI makes GPT-5.6 Sol. Access the model through the Neon AI Gateway using chat/completions and openai/responses. ## Provider Databricks ## Inputs Text, image, pdf ## Context 1.1M ## Released Jul 2026 ## Input /M $5 ## Output /M $30 --- [Document source](https://neon.com/docs/ai-gateway/models/gpt-5-6-terra.md) --- # GPT-5.6 Terra ## About Neon AI Gateway provides GPT-5.6 Terra by OpenAI. The model supports text, image, pdf inputs and a 1.1M context window. ## Command ### Text generation #### AI SDK Install: ```bash npm i ai @neon/ai-sdk-provider ``` ```typescript import { generateText } from "ai"; import { neon } from "@neon/ai-sdk-provider"; const { text } = await generateText({ model: neon("gpt-5-6-terra"), prompt: "Explain Serverless Postgres.", }); console.log(text); ``` #### Mastra Install: ```bash npm i @mastra/core ``` ```typescript import { Agent } from "@mastra/core/agent"; const agent = new Agent({ id: "neon-demo", name: "neon-demo", instructions: "You are a helpful assistant.", model: "neon/gpt-5-6-terra", }); const { text } = await agent.generate("Explain Serverless Postgres."); console.log(text); ``` #### TypeScript Install: ```bash npm i openai ``` ```typescript import OpenAI from "openai"; const client = new OpenAI({ apiKey: process.env.NEON_AI_GATEWAY_TOKEN, baseURL: `${process.env.NEON_AI_GATEWAY_BASE_URL}/v1`, }); const resp = await client.chat.completions.create({ model: "gpt-5-6-terra", messages: [{ role: "user", content: "Explain Serverless Postgres." }], }); console.log(resp.choices[0].message.content); ``` #### Python Install: ```bash pip install openai ``` ```python import os from openai import OpenAI client = OpenAI( api_key=os.environ["NEON_AI_GATEWAY_TOKEN"], base_url=f"{os.environ['NEON_AI_GATEWAY_BASE_URL']}/v1", ) resp = client.chat.completions.create( model="gpt-5-6-terra", messages=[{"role": "user", "content": "Explain Serverless Postgres."}], ) print(resp.choices[0].message.content) ``` #### cURL ```bash curl "${NEON_AI_GATEWAY_BASE_URL}/v1/chat/completions" \ -H "Authorization: Bearer ${NEON_AI_GATEWAY_TOKEN}" \ -H "Content-Type: application/json" \ -d '{ "model": "gpt-5-6-terra", "messages": [{"role": "user", "content": "Explain Serverless Postgres."}] }' ``` ### Image generation #### AI SDK Install: ```bash npm i ai @neon/ai-sdk-provider ``` ```typescript import { streamText } from "ai"; import { neon } from "@neon/ai-sdk-provider"; const result = streamText({ model: neon("gpt-5-6-terra"), prompt: "A red apple on a wooden table.", tools: { image_generation: neon.tools.imageGeneration({ model: "gpt-image-2", outputFormat: "jpeg", }), }, }); for await (const _ of result.textStream) {} const images = (await result.toolResults).filter((r) => r.toolName === "image_generation"); console.log(images.length); ``` #### Mastra Install: ```bash npm i @mastra/core ai @neon/ai-sdk-provider ``` ```typescript import { Agent } from "@mastra/core/agent"; import { neon } from "@neon/ai-sdk-provider"; const agent = new Agent({ id: "neon-demo", name: "neon-demo", instructions: "Generate the image the user asks for.", model: "neon/gpt-5-6-terra", tools: { image_generation: neon.tools.imageGeneration({ model: "gpt-image-2", outputFormat: "jpeg", }), }, }); const { toolResults } = await agent.generate("A red apple on a wooden table."); const images = toolResults.filter((r) => r.payload.toolName === "image_generation"); console.log(images.map((r) => r.payload.result.result.length)); ``` #### TypeScript Install: ```bash npm i openai ``` ```typescript import OpenAI from "openai"; const client = new OpenAI({ apiKey: process.env.NEON_AI_GATEWAY_TOKEN, baseURL: `${process.env.NEON_AI_GATEWAY_BASE_URL}/openai/v1`, }); const stream = client.responses.stream({ model: "gpt-5-6-terra", input: "A red apple on a wooden table.", tools: [{ type: "image_generation", model: "gpt-image-2" }], }); const response = await stream.finalResponse(); const sizes = response.output.flatMap((item) => { if (item.type !== "image_generation_call") return []; if (!("result" in item) || typeof item.result !== "string") return []; return [item.result.length]; }); console.log(sizes); ``` #### Python Install: ```bash pip install openai ``` ```python import os from openai import OpenAI client = OpenAI( api_key=os.environ["NEON_AI_GATEWAY_TOKEN"], base_url=f"{os.environ['NEON_AI_GATEWAY_BASE_URL']}/openai/v1", ) with client.responses.stream( model="gpt-5-6-terra", input="A red apple on a wooden table.", tools=[{"type": "image_generation", "model": "gpt-image-2"}], ) as stream: for _ in stream: pass response = stream.get_final_response() sizes = [ len(item.result) for item in response.output if item.type == "image_generation_call" and getattr(item, "result", None) ] print(sizes) ``` **Environment variables** ```bash # Injected by `neon env pull` when AI Gateway is enabled on the branch (neon.ts preview.aiGateway). # Neon injects ONLY the NEON_AI_GATEWAY_* vars (not OPENAI_*). Build the OpenAI SDK / curl # apiKey + baseURL from them: apiKey = NEON_AI_GATEWAY_TOKEN (the bearer, nt_live_...). # # NEON_AI_GATEWAY_BASE_URL is the bare gateway host (no path). Append the route you need: # - `/v1` - unified Chat Completions and `/v1/embeddings` # - `/openai/v1` - OpenAI Responses API # - `/typesafe` - TypeSafe SDK base URL for System One decisions (`/typesafe/v1/systemone`) # @neon/ai-sdk-provider and Mastra route requests automatically. NEON_AI_GATEWAY_TOKEN=nt_live_... NEON_AI_GATEWAY_BASE_URL=https://-api.ai....neon.tech ``` ## Model ID gpt-5-6-terra ## Lab OpenAI makes GPT-5.6 Terra. Access the model through the Neon AI Gateway using chat/completions and openai/responses. ## Provider Databricks ## Inputs Text, image, pdf ## Context 1.1M ## Released Jul 2026 ## Input /M $2 ## Output /M $12 --- [Document source](https://neon.com/docs/ai-gateway/models/gpt-5-mini.md) --- # GPT-5 Mini ## About Neon AI Gateway provides GPT-5 Mini by OpenAI. The model supports text, image inputs and a 400K context window. ## Command ### Text generation #### AI SDK Install: ```bash npm i ai @neon/ai-sdk-provider ``` ```typescript import { generateText } from "ai"; import { neon } from "@neon/ai-sdk-provider"; const { text } = await generateText({ model: neon("gpt-5-mini"), prompt: "Explain Serverless Postgres.", }); console.log(text); ``` #### Mastra Install: ```bash npm i @mastra/core ``` ```typescript import { Agent } from "@mastra/core/agent"; const agent = new Agent({ id: "neon-demo", name: "neon-demo", instructions: "You are a helpful assistant.", model: "neon/gpt-5-mini", }); const { text } = await agent.generate("Explain Serverless Postgres."); console.log(text); ``` #### TypeScript Install: ```bash npm i openai ``` ```typescript import OpenAI from "openai"; const client = new OpenAI({ apiKey: process.env.NEON_AI_GATEWAY_TOKEN, baseURL: `${process.env.NEON_AI_GATEWAY_BASE_URL}/v1`, }); const resp = await client.chat.completions.create({ model: "gpt-5-mini", messages: [{ role: "user", content: "Explain Serverless Postgres." }], }); console.log(resp.choices[0].message.content); ``` #### Python Install: ```bash pip install openai ``` ```python import os from openai import OpenAI client = OpenAI( api_key=os.environ["NEON_AI_GATEWAY_TOKEN"], base_url=f"{os.environ['NEON_AI_GATEWAY_BASE_URL']}/v1", ) resp = client.chat.completions.create( model="gpt-5-mini", messages=[{"role": "user", "content": "Explain Serverless Postgres."}], ) print(resp.choices[0].message.content) ``` #### cURL ```bash curl "${NEON_AI_GATEWAY_BASE_URL}/v1/chat/completions" \ -H "Authorization: Bearer ${NEON_AI_GATEWAY_TOKEN}" \ -H "Content-Type: application/json" \ -d '{ "model": "gpt-5-mini", "messages": [{"role": "user", "content": "Explain Serverless Postgres."}] }' ``` ### Image generation #### AI SDK Install: ```bash npm i ai @neon/ai-sdk-provider ``` ```typescript import { streamText } from "ai"; import { neon } from "@neon/ai-sdk-provider"; const result = streamText({ model: neon("gpt-5-mini"), prompt: "A red apple on a wooden table.", tools: { image_generation: neon.tools.imageGeneration({ model: "gpt-image-2", outputFormat: "jpeg", }), }, }); for await (const _ of result.textStream) {} const images = (await result.toolResults).filter((r) => r.toolName === "image_generation"); console.log(images.length); ``` #### Mastra Install: ```bash npm i @mastra/core ai @neon/ai-sdk-provider ``` ```typescript import { Agent } from "@mastra/core/agent"; import { neon } from "@neon/ai-sdk-provider"; const agent = new Agent({ id: "neon-demo", name: "neon-demo", instructions: "Generate the image the user asks for.", model: "neon/gpt-5-mini", tools: { image_generation: neon.tools.imageGeneration({ model: "gpt-image-2", outputFormat: "jpeg", }), }, }); const { toolResults } = await agent.generate("A red apple on a wooden table."); const images = toolResults.filter((r) => r.payload.toolName === "image_generation"); console.log(images.map((r) => r.payload.result.result.length)); ``` #### TypeScript Install: ```bash npm i openai ``` ```typescript import OpenAI from "openai"; const client = new OpenAI({ apiKey: process.env.NEON_AI_GATEWAY_TOKEN, baseURL: `${process.env.NEON_AI_GATEWAY_BASE_URL}/openai/v1`, }); const stream = client.responses.stream({ model: "gpt-5-mini", input: "A red apple on a wooden table.", tools: [{ type: "image_generation", model: "gpt-image-2" }], }); const response = await stream.finalResponse(); const sizes = response.output.flatMap((item) => { if (item.type !== "image_generation_call") return []; if (!("result" in item) || typeof item.result !== "string") return []; return [item.result.length]; }); console.log(sizes); ``` #### Python Install: ```bash pip install openai ``` ```python import os from openai import OpenAI client = OpenAI( api_key=os.environ["NEON_AI_GATEWAY_TOKEN"], base_url=f"{os.environ['NEON_AI_GATEWAY_BASE_URL']}/openai/v1", ) with client.responses.stream( model="gpt-5-mini", input="A red apple on a wooden table.", tools=[{"type": "image_generation", "model": "gpt-image-2"}], ) as stream: for _ in stream: pass response = stream.get_final_response() sizes = [ len(item.result) for item in response.output if item.type == "image_generation_call" and getattr(item, "result", None) ] print(sizes) ``` **Environment variables** ```bash # Injected by `neon env pull` when AI Gateway is enabled on the branch (neon.ts preview.aiGateway). # Neon injects ONLY the NEON_AI_GATEWAY_* vars (not OPENAI_*). Build the OpenAI SDK / curl # apiKey + baseURL from them: apiKey = NEON_AI_GATEWAY_TOKEN (the bearer, nt_live_...). # # NEON_AI_GATEWAY_BASE_URL is the bare gateway host (no path). Append the route you need: # - `/v1` - unified Chat Completions and `/v1/embeddings` # - `/openai/v1` - OpenAI Responses API # - `/typesafe` - TypeSafe SDK base URL for System One decisions (`/typesafe/v1/systemone`) # @neon/ai-sdk-provider and Mastra route requests automatically. NEON_AI_GATEWAY_TOKEN=nt_live_... NEON_AI_GATEWAY_BASE_URL=https://-api.ai....neon.tech ``` ## Model ID gpt-5-mini ## Lab OpenAI makes GPT-5 Mini. Access the model through the Neon AI Gateway using chat/completions and openai/responses. ## Provider Databricks ## Inputs Text, image ## Context 400K ## Released Aug 2025 ## Input /M $0.25 ## Output /M $2 --- [Document source](https://neon.com/docs/ai-gateway/models/gpt-5-nano.md) --- # GPT-5 Nano ## About Neon AI Gateway provides GPT-5 Nano by OpenAI. The model supports text, image inputs and a 400K context window. ## Command ### Text generation #### AI SDK Install: ```bash npm i ai @neon/ai-sdk-provider ``` ```typescript import { generateText } from "ai"; import { neon } from "@neon/ai-sdk-provider"; const { text } = await generateText({ model: neon("gpt-5-nano"), prompt: "Explain Serverless Postgres.", }); console.log(text); ``` #### Mastra Install: ```bash npm i @mastra/core ``` ```typescript import { Agent } from "@mastra/core/agent"; const agent = new Agent({ id: "neon-demo", name: "neon-demo", instructions: "You are a helpful assistant.", model: "neon/gpt-5-nano", }); const { text } = await agent.generate("Explain Serverless Postgres."); console.log(text); ``` #### TypeScript Install: ```bash npm i openai ``` ```typescript import OpenAI from "openai"; const client = new OpenAI({ apiKey: process.env.NEON_AI_GATEWAY_TOKEN, baseURL: `${process.env.NEON_AI_GATEWAY_BASE_URL}/v1`, }); const resp = await client.chat.completions.create({ model: "gpt-5-nano", messages: [{ role: "user", content: "Explain Serverless Postgres." }], }); console.log(resp.choices[0].message.content); ``` #### Python Install: ```bash pip install openai ``` ```python import os from openai import OpenAI client = OpenAI( api_key=os.environ["NEON_AI_GATEWAY_TOKEN"], base_url=f"{os.environ['NEON_AI_GATEWAY_BASE_URL']}/v1", ) resp = client.chat.completions.create( model="gpt-5-nano", messages=[{"role": "user", "content": "Explain Serverless Postgres."}], ) print(resp.choices[0].message.content) ``` #### cURL ```bash curl "${NEON_AI_GATEWAY_BASE_URL}/v1/chat/completions" \ -H "Authorization: Bearer ${NEON_AI_GATEWAY_TOKEN}" \ -H "Content-Type: application/json" \ -d '{ "model": "gpt-5-nano", "messages": [{"role": "user", "content": "Explain Serverless Postgres."}] }' ``` ### Image generation #### AI SDK Install: ```bash npm i ai @neon/ai-sdk-provider ``` ```typescript import { streamText } from "ai"; import { neon } from "@neon/ai-sdk-provider"; const result = streamText({ model: neon("gpt-5-nano"), prompt: "A red apple on a wooden table.", tools: { image_generation: neon.tools.imageGeneration({ model: "gpt-image-2", outputFormat: "jpeg", }), }, }); for await (const _ of result.textStream) {} const images = (await result.toolResults).filter((r) => r.toolName === "image_generation"); console.log(images.length); ``` #### Mastra Install: ```bash npm i @mastra/core ai @neon/ai-sdk-provider ``` ```typescript import { Agent } from "@mastra/core/agent"; import { neon } from "@neon/ai-sdk-provider"; const agent = new Agent({ id: "neon-demo", name: "neon-demo", instructions: "Generate the image the user asks for.", model: "neon/gpt-5-nano", tools: { image_generation: neon.tools.imageGeneration({ model: "gpt-image-2", outputFormat: "jpeg", }), }, }); const { toolResults } = await agent.generate("A red apple on a wooden table."); const images = toolResults.filter((r) => r.payload.toolName === "image_generation"); console.log(images.map((r) => r.payload.result.result.length)); ``` #### TypeScript Install: ```bash npm i openai ``` ```typescript import OpenAI from "openai"; const client = new OpenAI({ apiKey: process.env.NEON_AI_GATEWAY_TOKEN, baseURL: `${process.env.NEON_AI_GATEWAY_BASE_URL}/openai/v1`, }); const stream = client.responses.stream({ model: "gpt-5-nano", input: "A red apple on a wooden table.", tools: [{ type: "image_generation", model: "gpt-image-2" }], }); const response = await stream.finalResponse(); const sizes = response.output.flatMap((item) => { if (item.type !== "image_generation_call") return []; if (!("result" in item) || typeof item.result !== "string") return []; return [item.result.length]; }); console.log(sizes); ``` #### Python Install: ```bash pip install openai ``` ```python import os from openai import OpenAI client = OpenAI( api_key=os.environ["NEON_AI_GATEWAY_TOKEN"], base_url=f"{os.environ['NEON_AI_GATEWAY_BASE_URL']}/openai/v1", ) with client.responses.stream( model="gpt-5-nano", input="A red apple on a wooden table.", tools=[{"type": "image_generation", "model": "gpt-image-2"}], ) as stream: for _ in stream: pass response = stream.get_final_response() sizes = [ len(item.result) for item in response.output if item.type == "image_generation_call" and getattr(item, "result", None) ] print(sizes) ``` **Environment variables** ```bash # Injected by `neon env pull` when AI Gateway is enabled on the branch (neon.ts preview.aiGateway). # Neon injects ONLY the NEON_AI_GATEWAY_* vars (not OPENAI_*). Build the OpenAI SDK / curl # apiKey + baseURL from them: apiKey = NEON_AI_GATEWAY_TOKEN (the bearer, nt_live_...). # # NEON_AI_GATEWAY_BASE_URL is the bare gateway host (no path). Append the route you need: # - `/v1` - unified Chat Completions and `/v1/embeddings` # - `/openai/v1` - OpenAI Responses API # - `/typesafe` - TypeSafe SDK base URL for System One decisions (`/typesafe/v1/systemone`) # @neon/ai-sdk-provider and Mastra route requests automatically. NEON_AI_GATEWAY_TOKEN=nt_live_... NEON_AI_GATEWAY_BASE_URL=https://-api.ai....neon.tech ``` ## Model ID gpt-5-nano ## Lab OpenAI makes GPT-5 Nano. Access the model through the Neon AI Gateway using chat/completions and openai/responses. ## Provider Databricks ## Inputs Text, image ## Context 400K ## Released Aug 2025 ## Input /M $0.05 ## Output /M $0.40 --- [Document source](https://neon.com/docs/ai-gateway/models/gpt-5.md) --- # GPT-5 ## About Neon AI Gateway provides GPT-5 by OpenAI. The model supports text, image inputs and a 400K context window. ## Command ### Text generation #### AI SDK Install: ```bash npm i ai @neon/ai-sdk-provider ``` ```typescript import { generateText } from "ai"; import { neon } from "@neon/ai-sdk-provider"; const { text } = await generateText({ model: neon("gpt-5"), prompt: "Explain Serverless Postgres.", }); console.log(text); ``` #### Mastra Install: ```bash npm i @mastra/core ``` ```typescript import { Agent } from "@mastra/core/agent"; const agent = new Agent({ id: "neon-demo", name: "neon-demo", instructions: "You are a helpful assistant.", model: "neon/gpt-5", }); const { text } = await agent.generate("Explain Serverless Postgres."); console.log(text); ``` #### TypeScript Install: ```bash npm i openai ``` ```typescript import OpenAI from "openai"; const client = new OpenAI({ apiKey: process.env.NEON_AI_GATEWAY_TOKEN, baseURL: `${process.env.NEON_AI_GATEWAY_BASE_URL}/v1`, }); const resp = await client.chat.completions.create({ model: "gpt-5", messages: [{ role: "user", content: "Explain Serverless Postgres." }], }); console.log(resp.choices[0].message.content); ``` #### Python Install: ```bash pip install openai ``` ```python import os from openai import OpenAI client = OpenAI( api_key=os.environ["NEON_AI_GATEWAY_TOKEN"], base_url=f"{os.environ['NEON_AI_GATEWAY_BASE_URL']}/v1", ) resp = client.chat.completions.create( model="gpt-5", messages=[{"role": "user", "content": "Explain Serverless Postgres."}], ) print(resp.choices[0].message.content) ``` #### cURL ```bash curl "${NEON_AI_GATEWAY_BASE_URL}/v1/chat/completions" \ -H "Authorization: Bearer ${NEON_AI_GATEWAY_TOKEN}" \ -H "Content-Type: application/json" \ -d '{ "model": "gpt-5", "messages": [{"role": "user", "content": "Explain Serverless Postgres."}] }' ``` ### Image generation #### AI SDK Install: ```bash npm i ai @neon/ai-sdk-provider ``` ```typescript import { streamText } from "ai"; import { neon } from "@neon/ai-sdk-provider"; const result = streamText({ model: neon("gpt-5"), prompt: "A red apple on a wooden table.", tools: { image_generation: neon.tools.imageGeneration({ model: "gpt-image-2", outputFormat: "jpeg", }), }, }); for await (const _ of result.textStream) {} const images = (await result.toolResults).filter((r) => r.toolName === "image_generation"); console.log(images.length); ``` #### Mastra Install: ```bash npm i @mastra/core ai @neon/ai-sdk-provider ``` ```typescript import { Agent } from "@mastra/core/agent"; import { neon } from "@neon/ai-sdk-provider"; const agent = new Agent({ id: "neon-demo", name: "neon-demo", instructions: "Generate the image the user asks for.", model: "neon/gpt-5", tools: { image_generation: neon.tools.imageGeneration({ model: "gpt-image-2", outputFormat: "jpeg", }), }, }); const { toolResults } = await agent.generate("A red apple on a wooden table."); const images = toolResults.filter((r) => r.payload.toolName === "image_generation"); console.log(images.map((r) => r.payload.result.result.length)); ``` #### TypeScript Install: ```bash npm i openai ``` ```typescript import OpenAI from "openai"; const client = new OpenAI({ apiKey: process.env.NEON_AI_GATEWAY_TOKEN, baseURL: `${process.env.NEON_AI_GATEWAY_BASE_URL}/openai/v1`, }); const stream = client.responses.stream({ model: "gpt-5", input: "A red apple on a wooden table.", tools: [{ type: "image_generation", model: "gpt-image-2" }], }); const response = await stream.finalResponse(); const sizes = response.output.flatMap((item) => { if (item.type !== "image_generation_call") return []; if (!("result" in item) || typeof item.result !== "string") return []; return [item.result.length]; }); console.log(sizes); ``` #### Python Install: ```bash pip install openai ``` ```python import os from openai import OpenAI client = OpenAI( api_key=os.environ["NEON_AI_GATEWAY_TOKEN"], base_url=f"{os.environ['NEON_AI_GATEWAY_BASE_URL']}/openai/v1", ) with client.responses.stream( model="gpt-5", input="A red apple on a wooden table.", tools=[{"type": "image_generation", "model": "gpt-image-2"}], ) as stream: for _ in stream: pass response = stream.get_final_response() sizes = [ len(item.result) for item in response.output if item.type == "image_generation_call" and getattr(item, "result", None) ] print(sizes) ``` **Environment variables** ```bash # Injected by `neon env pull` when AI Gateway is enabled on the branch (neon.ts preview.aiGateway). # Neon injects ONLY the NEON_AI_GATEWAY_* vars (not OPENAI_*). Build the OpenAI SDK / curl # apiKey + baseURL from them: apiKey = NEON_AI_GATEWAY_TOKEN (the bearer, nt_live_...). # # NEON_AI_GATEWAY_BASE_URL is the bare gateway host (no path). Append the route you need: # - `/v1` - unified Chat Completions and `/v1/embeddings` # - `/openai/v1` - OpenAI Responses API # - `/typesafe` - TypeSafe SDK base URL for System One decisions (`/typesafe/v1/systemone`) # @neon/ai-sdk-provider and Mastra route requests automatically. NEON_AI_GATEWAY_TOKEN=nt_live_... NEON_AI_GATEWAY_BASE_URL=https://-api.ai....neon.tech ``` ## Model ID gpt-5 ## Lab OpenAI makes GPT-5. Access the model through the Neon AI Gateway using chat/completions and openai/responses. ## Provider Databricks ## Inputs Text, image ## Context 400K ## Released Aug 2025 ## Input /M $1.25 ## Output /M $10 --- [Document source](https://neon.com/docs/ai-gateway/models/gpt-6-1-sol.md) --- # GPT-6.1 Sol ## About Neon AI Gateway provides GPT-6.1 Sol by OpenAI. The model supports text, image, pdf inputs and a 1.1M context window. ## Command ### Text generation #### AI SDK Install: ```bash npm i ai @neon/ai-sdk-provider ``` ```typescript import { generateText } from "ai"; import { neon } from "@neon/ai-sdk-provider"; const { text } = await generateText({ model: neon("gpt-6-1-sol"), prompt: "Explain Serverless Postgres.", }); console.log(text); ``` #### Mastra Install: ```bash npm i @mastra/core ``` ```typescript import { Agent } from "@mastra/core/agent"; const agent = new Agent({ id: "neon-demo", name: "neon-demo", instructions: "You are a helpful assistant.", model: "neon/gpt-6-1-sol", }); const { text } = await agent.generate("Explain Serverless Postgres."); console.log(text); ``` #### TypeScript Install: ```bash npm i openai ``` ```typescript import OpenAI from "openai"; const client = new OpenAI({ apiKey: process.env.NEON_AI_GATEWAY_TOKEN, baseURL: `${process.env.NEON_AI_GATEWAY_BASE_URL}/v1`, }); const resp = await client.chat.completions.create({ model: "gpt-6-1-sol", messages: [{ role: "user", content: "Explain Serverless Postgres." }], }); console.log(resp.choices[0].message.content); ``` #### Python Install: ```bash pip install openai ``` ```python import os from openai import OpenAI client = OpenAI( api_key=os.environ["NEON_AI_GATEWAY_TOKEN"], base_url=f"{os.environ['NEON_AI_GATEWAY_BASE_URL']}/v1", ) resp = client.chat.completions.create( model="gpt-6-1-sol", messages=[{"role": "user", "content": "Explain Serverless Postgres."}], ) print(resp.choices[0].message.content) ``` #### cURL ```bash curl "${NEON_AI_GATEWAY_BASE_URL}/v1/chat/completions" \ -H "Authorization: Bearer ${NEON_AI_GATEWAY_TOKEN}" \ -H "Content-Type: application/json" \ -d '{ "model": "gpt-6-1-sol", "messages": [{"role": "user", "content": "Explain Serverless Postgres."}] }' ``` ### Image generation #### AI SDK Install: ```bash npm i ai @neon/ai-sdk-provider ``` ```typescript import { streamText } from "ai"; import { neon } from "@neon/ai-sdk-provider"; const result = streamText({ model: neon("gpt-6-1-sol"), prompt: "A red apple on a wooden table.", tools: { image_generation: neon.tools.imageGeneration({ model: "gpt-image-2", outputFormat: "jpeg", }), }, }); for await (const _ of result.textStream) {} const images = (await result.toolResults).filter((r) => r.toolName === "image_generation"); console.log(images.length); ``` #### Mastra Install: ```bash npm i @mastra/core ai @neon/ai-sdk-provider ``` ```typescript import { Agent } from "@mastra/core/agent"; import { neon } from "@neon/ai-sdk-provider"; const agent = new Agent({ id: "neon-demo", name: "neon-demo", instructions: "Generate the image the user asks for.", model: "neon/gpt-6-1-sol", tools: { image_generation: neon.tools.imageGeneration({ model: "gpt-image-2", outputFormat: "jpeg", }), }, }); const { toolResults } = await agent.generate("A red apple on a wooden table."); const images = toolResults.filter((r) => r.payload.toolName === "image_generation"); console.log(images.map((r) => r.payload.result.result.length)); ``` #### TypeScript Install: ```bash npm i openai ``` ```typescript import OpenAI from "openai"; const client = new OpenAI({ apiKey: process.env.NEON_AI_GATEWAY_TOKEN, baseURL: `${process.env.NEON_AI_GATEWAY_BASE_URL}/openai/v1`, }); const stream = client.responses.stream({ model: "gpt-6-1-sol", input: "A red apple on a wooden table.", tools: [{ type: "image_generation", model: "gpt-image-2" }], }); const response = await stream.finalResponse(); const sizes = response.output.flatMap((item) => { if (item.type !== "image_generation_call") return []; if (!("result" in item) || typeof item.result !== "string") return []; return [item.result.length]; }); console.log(sizes); ``` #### Python Install: ```bash pip install openai ``` ```python import os from openai import OpenAI client = OpenAI( api_key=os.environ["NEON_AI_GATEWAY_TOKEN"], base_url=f"{os.environ['NEON_AI_GATEWAY_BASE_URL']}/openai/v1", ) with client.responses.stream( model="gpt-6-1-sol", input="A red apple on a wooden table.", tools=[{"type": "image_generation", "model": "gpt-image-2"}], ) as stream: for _ in stream: pass response = stream.get_final_response() sizes = [ len(item.result) for item in response.output if item.type == "image_generation_call" and getattr(item, "result", None) ] print(sizes) ``` **Environment variables** ```bash # Injected by `neon env pull` when AI Gateway is enabled on the branch (neon.ts preview.aiGateway). # Neon injects ONLY the NEON_AI_GATEWAY_* vars (not OPENAI_*). Build the OpenAI SDK / curl # apiKey + baseURL from them: apiKey = NEON_AI_GATEWAY_TOKEN (the bearer, nt_live_...). # # NEON_AI_GATEWAY_BASE_URL is the bare gateway host (no path). Append the route you need: # - `/v1` - unified Chat Completions and `/v1/embeddings` # - `/openai/v1` - OpenAI Responses API # - `/typesafe` - TypeSafe SDK base URL for System One decisions (`/typesafe/v1/systemone`) # @neon/ai-sdk-provider and Mastra route requests automatically. NEON_AI_GATEWAY_TOKEN=nt_live_... NEON_AI_GATEWAY_BASE_URL=https://-api.ai....neon.tech ``` ## Model ID gpt-6-1-sol ## Lab OpenAI makes GPT-6.1 Sol. Access the model through the Neon AI Gateway using chat/completions and openai/responses. ## Provider Databricks ## Inputs Text, image, pdf ## Context 1.1M ## Released Sep 2026 ## Input /M $2 ## Output /M $10 --- [Document source](https://neon.com/docs/ai-gateway/models/gpt-6-astra.md) --- # GPT-6 Astra ## About Neon AI Gateway provides GPT-6 Astra by OpenAI. The model supports text, image, pdf inputs and a 1.1M context window. ## Command ### Text generation #### AI SDK Install: ```bash npm i ai @neon/ai-sdk-provider ``` ```typescript import { generateText } from "ai"; import { neon } from "@neon/ai-sdk-provider"; const { text } = await generateText({ model: neon("gpt-6-astra"), prompt: "Explain Serverless Postgres.", }); console.log(text); ``` #### Mastra Install: ```bash npm i @mastra/core ``` ```typescript import { Agent } from "@mastra/core/agent"; const agent = new Agent({ id: "neon-demo", name: "neon-demo", instructions: "You are a helpful assistant.", model: "neon/gpt-6-astra", }); const { text } = await agent.generate("Explain Serverless Postgres."); console.log(text); ``` #### TypeScript Install: ```bash npm i openai ``` ```typescript import OpenAI from "openai"; const client = new OpenAI({ apiKey: process.env.NEON_AI_GATEWAY_TOKEN, baseURL: `${process.env.NEON_AI_GATEWAY_BASE_URL}/v1`, }); const resp = await client.chat.completions.create({ model: "gpt-6-astra", messages: [{ role: "user", content: "Explain Serverless Postgres." }], }); console.log(resp.choices[0].message.content); ``` #### Python Install: ```bash pip install openai ``` ```python import os from openai import OpenAI client = OpenAI( api_key=os.environ["NEON_AI_GATEWAY_TOKEN"], base_url=f"{os.environ['NEON_AI_GATEWAY_BASE_URL']}/v1", ) resp = client.chat.completions.create( model="gpt-6-astra", messages=[{"role": "user", "content": "Explain Serverless Postgres."}], ) print(resp.choices[0].message.content) ``` #### cURL ```bash curl "${NEON_AI_GATEWAY_BASE_URL}/v1/chat/completions" \ -H "Authorization: Bearer ${NEON_AI_GATEWAY_TOKEN}" \ -H "Content-Type: application/json" \ -d '{ "model": "gpt-6-astra", "messages": [{"role": "user", "content": "Explain Serverless Postgres."}] }' ``` ### Image generation #### AI SDK Install: ```bash npm i ai @neon/ai-sdk-provider ``` ```typescript import { streamText } from "ai"; import { neon } from "@neon/ai-sdk-provider"; const result = streamText({ model: neon("gpt-6-astra"), prompt: "A red apple on a wooden table.", tools: { image_generation: neon.tools.imageGeneration({ model: "gpt-image-2", outputFormat: "jpeg", }), }, }); for await (const _ of result.textStream) {} const images = (await result.toolResults).filter((r) => r.toolName === "image_generation"); console.log(images.length); ``` #### Mastra Install: ```bash npm i @mastra/core ai @neon/ai-sdk-provider ``` ```typescript import { Agent } from "@mastra/core/agent"; import { neon } from "@neon/ai-sdk-provider"; const agent = new Agent({ id: "neon-demo", name: "neon-demo", instructions: "Generate the image the user asks for.", model: "neon/gpt-6-astra", tools: { image_generation: neon.tools.imageGeneration({ model: "gpt-image-2", outputFormat: "jpeg", }), }, }); const { toolResults } = await agent.generate("A red apple on a wooden table."); const images = toolResults.filter((r) => r.payload.toolName === "image_generation"); console.log(images.map((r) => r.payload.result.result.length)); ``` #### TypeScript Install: ```bash npm i openai ``` ```typescript import OpenAI from "openai"; const client = new OpenAI({ apiKey: process.env.NEON_AI_GATEWAY_TOKEN, baseURL: `${process.env.NEON_AI_GATEWAY_BASE_URL}/openai/v1`, }); const stream = client.responses.stream({ model: "gpt-6-astra", input: "A red apple on a wooden table.", tools: [{ type: "image_generation", model: "gpt-image-2" }], }); const response = await stream.finalResponse(); const sizes = response.output.flatMap((item) => { if (item.type !== "image_generation_call") return []; if (!("result" in item) || typeof item.result !== "string") return []; return [item.result.length]; }); console.log(sizes); ``` #### Python Install: ```bash pip install openai ``` ```python import os from openai import OpenAI client = OpenAI( api_key=os.environ["NEON_AI_GATEWAY_TOKEN"], base_url=f"{os.environ['NEON_AI_GATEWAY_BASE_URL']}/openai/v1", ) with client.responses.stream( model="gpt-6-astra", input="A red apple on a wooden table.", tools=[{"type": "image_generation", "model": "gpt-image-2"}], ) as stream: for _ in stream: pass response = stream.get_final_response() sizes = [ len(item.result) for item in response.output if item.type == "image_generation_call" and getattr(item, "result", None) ] print(sizes) ``` **Environment variables** ```bash # Injected by `neon env pull` when AI Gateway is enabled on the branch (neon.ts preview.aiGateway). # Neon injects ONLY the NEON_AI_GATEWAY_* vars (not OPENAI_*). Build the OpenAI SDK / curl # apiKey + baseURL from them: apiKey = NEON_AI_GATEWAY_TOKEN (the bearer, nt_live_...). # # NEON_AI_GATEWAY_BASE_URL is the bare gateway host (no path). Append the route you need: # - `/v1` - unified Chat Completions and `/v1/embeddings` # - `/openai/v1` - OpenAI Responses API # - `/typesafe` - TypeSafe SDK base URL for System One decisions (`/typesafe/v1/systemone`) # @neon/ai-sdk-provider and Mastra route requests automatically. NEON_AI_GATEWAY_TOKEN=nt_live_... NEON_AI_GATEWAY_BASE_URL=https://-api.ai....neon.tech ``` ## Model ID gpt-6-astra ## Lab OpenAI makes GPT-6 Astra. Access the model through the Neon AI Gateway using chat/completions and openai/responses. ## Provider Databricks ## Inputs Text, image, pdf ## Context 1.1M ## Released Sep 2026 ## Input /M $10 ## Output /M $50 --- [Document source](https://neon.com/docs/ai-gateway/models/gpt-6-luna.md) --- # GPT-6 Luna ## About Neon AI Gateway provides GPT-6 Luna by OpenAI. The model supports text, image, pdf inputs and a 1.1M context window. ## Command ### Text generation #### AI SDK Install: ```bash npm i ai @neon/ai-sdk-provider ``` ```typescript import { generateText } from "ai"; import { neon } from "@neon/ai-sdk-provider"; const { text } = await generateText({ model: neon("gpt-6-luna"), prompt: "Explain Serverless Postgres.", }); console.log(text); ``` #### Mastra Install: ```bash npm i @mastra/core ``` ```typescript import { Agent } from "@mastra/core/agent"; const agent = new Agent({ id: "neon-demo", name: "neon-demo", instructions: "You are a helpful assistant.", model: "neon/gpt-6-luna", }); const { text } = await agent.generate("Explain Serverless Postgres."); console.log(text); ``` #### TypeScript Install: ```bash npm i openai ``` ```typescript import OpenAI from "openai"; const client = new OpenAI({ apiKey: process.env.NEON_AI_GATEWAY_TOKEN, baseURL: `${process.env.NEON_AI_GATEWAY_BASE_URL}/v1`, }); const resp = await client.chat.completions.create({ model: "gpt-6-luna", messages: [{ role: "user", content: "Explain Serverless Postgres." }], }); console.log(resp.choices[0].message.content); ``` #### Python Install: ```bash pip install openai ``` ```python import os from openai import OpenAI client = OpenAI( api_key=os.environ["NEON_AI_GATEWAY_TOKEN"], base_url=f"{os.environ['NEON_AI_GATEWAY_BASE_URL']}/v1", ) resp = client.chat.completions.create( model="gpt-6-luna", messages=[{"role": "user", "content": "Explain Serverless Postgres."}], ) print(resp.choices[0].message.content) ``` #### cURL ```bash curl "${NEON_AI_GATEWAY_BASE_URL}/v1/chat/completions" \ -H "Authorization: Bearer ${NEON_AI_GATEWAY_TOKEN}" \ -H "Content-Type: application/json" \ -d '{ "model": "gpt-6-luna", "messages": [{"role": "user", "content": "Explain Serverless Postgres."}] }' ``` ### Image generation #### AI SDK Install: ```bash npm i ai @neon/ai-sdk-provider ``` ```typescript import { streamText } from "ai"; import { neon } from "@neon/ai-sdk-provider"; const result = streamText({ model: neon("gpt-6-luna"), prompt: "A red apple on a wooden table.", tools: { image_generation: neon.tools.imageGeneration({ model: "gpt-image-2", outputFormat: "jpeg", }), }, }); for await (const _ of result.textStream) {} const images = (await result.toolResults).filter((r) => r.toolName === "image_generation"); console.log(images.length); ``` #### Mastra Install: ```bash npm i @mastra/core ai @neon/ai-sdk-provider ``` ```typescript import { Agent } from "@mastra/core/agent"; import { neon } from "@neon/ai-sdk-provider"; const agent = new Agent({ id: "neon-demo", name: "neon-demo", instructions: "Generate the image the user asks for.", model: "neon/gpt-6-luna", tools: { image_generation: neon.tools.imageGeneration({ model: "gpt-image-2", outputFormat: "jpeg", }), }, }); const { toolResults } = await agent.generate("A red apple on a wooden table."); const images = toolResults.filter((r) => r.payload.toolName === "image_generation"); console.log(images.map((r) => r.payload.result.result.length)); ``` #### TypeScript Install: ```bash npm i openai ``` ```typescript import OpenAI from "openai"; const client = new OpenAI({ apiKey: process.env.NEON_AI_GATEWAY_TOKEN, baseURL: `${process.env.NEON_AI_GATEWAY_BASE_URL}/openai/v1`, }); const stream = client.responses.stream({ model: "gpt-6-luna", input: "A red apple on a wooden table.", tools: [{ type: "image_generation", model: "gpt-image-2" }], }); const response = await stream.finalResponse(); const sizes = response.output.flatMap((item) => { if (item.type !== "image_generation_call") return []; if (!("result" in item) || typeof item.result !== "string") return []; return [item.result.length]; }); console.log(sizes); ``` #### Python Install: ```bash pip install openai ``` ```python import os from openai import OpenAI client = OpenAI( api_key=os.environ["NEON_AI_GATEWAY_TOKEN"], base_url=f"{os.environ['NEON_AI_GATEWAY_BASE_URL']}/openai/v1", ) with client.responses.stream( model="gpt-6-luna", input="A red apple on a wooden table.", tools=[{"type": "image_generation", "model": "gpt-image-2"}], ) as stream: for _ in stream: pass response = stream.get_final_response() sizes = [ len(item.result) for item in response.output if item.type == "image_generation_call" and getattr(item, "result", None) ] print(sizes) ``` **Environment variables** ```bash # Injected by `neon env pull` when AI Gateway is enabled on the branch (neon.ts preview.aiGateway). # Neon injects ONLY the NEON_AI_GATEWAY_* vars (not OPENAI_*). Build the OpenAI SDK / curl # apiKey + baseURL from them: apiKey = NEON_AI_GATEWAY_TOKEN (the bearer, nt_live_...). # # NEON_AI_GATEWAY_BASE_URL is the bare gateway host (no path). Append the route you need: # - `/v1` - unified Chat Completions and `/v1/embeddings` # - `/openai/v1` - OpenAI Responses API # - `/typesafe` - TypeSafe SDK base URL for System One decisions (`/typesafe/v1/systemone`) # @neon/ai-sdk-provider and Mastra route requests automatically. NEON_AI_GATEWAY_TOKEN=nt_live_... NEON_AI_GATEWAY_BASE_URL=https://-api.ai....neon.tech ``` ## Model ID gpt-6-luna ## Lab OpenAI makes GPT-6 Luna. Access the model through the Neon AI Gateway using chat/completions and openai/responses. ## Provider Databricks ## Inputs Text, image, pdf ## Context 1.1M ## Released Sep 2026 ## Input /M $0.10 ## Output /M $0.50 --- [Document source](https://neon.com/docs/ai-gateway/models/gpt-6-sol.md) --- # GPT-6 Sol ## About Neon AI Gateway provides GPT-6 Sol by OpenAI. The model supports text, image, pdf inputs and a 1.1M context window. ## Command ### Text generation #### AI SDK Install: ```bash npm i ai @neon/ai-sdk-provider ``` ```typescript import { generateText } from "ai"; import { neon } from "@neon/ai-sdk-provider"; const { text } = await generateText({ model: neon("gpt-6-sol"), prompt: "Explain Serverless Postgres.", }); console.log(text); ``` #### Mastra Install: ```bash npm i @mastra/core ``` ```typescript import { Agent } from "@mastra/core/agent"; const agent = new Agent({ id: "neon-demo", name: "neon-demo", instructions: "You are a helpful assistant.", model: "neon/gpt-6-sol", }); const { text } = await agent.generate("Explain Serverless Postgres."); console.log(text); ``` #### TypeScript Install: ```bash npm i openai ``` ```typescript import OpenAI from "openai"; const client = new OpenAI({ apiKey: process.env.NEON_AI_GATEWAY_TOKEN, baseURL: `${process.env.NEON_AI_GATEWAY_BASE_URL}/v1`, }); const resp = await client.chat.completions.create({ model: "gpt-6-sol", messages: [{ role: "user", content: "Explain Serverless Postgres." }], }); console.log(resp.choices[0].message.content); ``` #### Python Install: ```bash pip install openai ``` ```python import os from openai import OpenAI client = OpenAI( api_key=os.environ["NEON_AI_GATEWAY_TOKEN"], base_url=f"{os.environ['NEON_AI_GATEWAY_BASE_URL']}/v1", ) resp = client.chat.completions.create( model="gpt-6-sol", messages=[{"role": "user", "content": "Explain Serverless Postgres."}], ) print(resp.choices[0].message.content) ``` #### cURL ```bash curl "${NEON_AI_GATEWAY_BASE_URL}/v1/chat/completions" \ -H "Authorization: Bearer ${NEON_AI_GATEWAY_TOKEN}" \ -H "Content-Type: application/json" \ -d '{ "model": "gpt-6-sol", "messages": [{"role": "user", "content": "Explain Serverless Postgres."}] }' ``` ### Image generation #### AI SDK Install: ```bash npm i ai @neon/ai-sdk-provider ``` ```typescript import { streamText } from "ai"; import { neon } from "@neon/ai-sdk-provider"; const result = streamText({ model: neon("gpt-6-sol"), prompt: "A red apple on a wooden table.", tools: { image_generation: neon.tools.imageGeneration({ model: "gpt-image-2", outputFormat: "jpeg", }), }, }); for await (const _ of result.textStream) {} const images = (await result.toolResults).filter((r) => r.toolName === "image_generation"); console.log(images.length); ``` #### Mastra Install: ```bash npm i @mastra/core ai @neon/ai-sdk-provider ``` ```typescript import { Agent } from "@mastra/core/agent"; import { neon } from "@neon/ai-sdk-provider"; const agent = new Agent({ id: "neon-demo", name: "neon-demo", instructions: "Generate the image the user asks for.", model: "neon/gpt-6-sol", tools: { image_generation: neon.tools.imageGeneration({ model: "gpt-image-2", outputFormat: "jpeg", }), }, }); const { toolResults } = await agent.generate("A red apple on a wooden table."); const images = toolResults.filter((r) => r.payload.toolName === "image_generation"); console.log(images.map((r) => r.payload.result.result.length)); ``` #### TypeScript Install: ```bash npm i openai ``` ```typescript import OpenAI from "openai"; const client = new OpenAI({ apiKey: process.env.NEON_AI_GATEWAY_TOKEN, baseURL: `${process.env.NEON_AI_GATEWAY_BASE_URL}/openai/v1`, }); const stream = client.responses.stream({ model: "gpt-6-sol", input: "A red apple on a wooden table.", tools: [{ type: "image_generation", model: "gpt-image-2" }], }); const response = await stream.finalResponse(); const sizes = response.output.flatMap((item) => { if (item.type !== "image_generation_call") return []; if (!("result" in item) || typeof item.result !== "string") return []; return [item.result.length]; }); console.log(sizes); ``` #### Python Install: ```bash pip install openai ``` ```python import os from openai import OpenAI client = OpenAI( api_key=os.environ["NEON_AI_GATEWAY_TOKEN"], base_url=f"{os.environ['NEON_AI_GATEWAY_BASE_URL']}/openai/v1", ) with client.responses.stream( model="gpt-6-sol", input="A red apple on a wooden table.", tools=[{"type": "image_generation", "model": "gpt-image-2"}], ) as stream: for _ in stream: pass response = stream.get_final_response() sizes = [ len(item.result) for item in response.output if item.type == "image_generation_call" and getattr(item, "result", None) ] print(sizes) ``` **Environment variables** ```bash # Injected by `neon env pull` when AI Gateway is enabled on the branch (neon.ts preview.aiGateway). # Neon injects ONLY the NEON_AI_GATEWAY_* vars (not OPENAI_*). Build the OpenAI SDK / curl # apiKey + baseURL from them: apiKey = NEON_AI_GATEWAY_TOKEN (the bearer, nt_live_...). # # NEON_AI_GATEWAY_BASE_URL is the bare gateway host (no path). Append the route you need: # - `/v1` - unified Chat Completions and `/v1/embeddings` # - `/openai/v1` - OpenAI Responses API # - `/typesafe` - TypeSafe SDK base URL for System One decisions (`/typesafe/v1/systemone`) # @neon/ai-sdk-provider and Mastra route requests automatically. NEON_AI_GATEWAY_TOKEN=nt_live_... NEON_AI_GATEWAY_BASE_URL=https://-api.ai....neon.tech ``` ## Model ID gpt-6-sol ## Lab OpenAI makes GPT-6 Sol. Access the model through the Neon AI Gateway using chat/completions and openai/responses. ## Provider Databricks ## Inputs Text, image, pdf ## Context 1.1M ## Released Sep 2026 ## Input /M $2 ## Output /M $10 --- [Document source](https://neon.com/docs/ai-gateway/models/gpt-oss-120b.md) --- # GPT OSS 120B ## About Neon AI Gateway provides GPT OSS 120B by OpenAI. The model supports text inputs and a 131K context window. ## Command ### Text generation #### AI SDK Install: ```bash npm i ai @neon/ai-sdk-provider ``` ```typescript import { generateText } from "ai"; import { neon } from "@neon/ai-sdk-provider"; const { text } = await generateText({ model: neon("gpt-oss-120b"), prompt: "Explain Serverless Postgres.", }); console.log(text); ``` #### Mastra Install: ```bash npm i @mastra/core ``` ```typescript import { Agent } from "@mastra/core/agent"; const agent = new Agent({ id: "neon-demo", name: "neon-demo", instructions: "You are a helpful assistant.", model: "neon/gpt-oss-120b", }); const { text } = await agent.generate("Explain Serverless Postgres."); console.log(text); ``` #### TypeScript Install: ```bash npm i openai ``` ```typescript import OpenAI from "openai"; const client = new OpenAI({ apiKey: process.env.NEON_AI_GATEWAY_TOKEN, baseURL: `${process.env.NEON_AI_GATEWAY_BASE_URL}/v1`, }); const resp = await client.chat.completions.create({ model: "gpt-oss-120b", messages: [{ role: "user", content: "Explain Serverless Postgres." }], }); console.log(resp.choices[0].message.content); ``` #### Python Install: ```bash pip install openai ``` ```python import os from openai import OpenAI client = OpenAI( api_key=os.environ["NEON_AI_GATEWAY_TOKEN"], base_url=f"{os.environ['NEON_AI_GATEWAY_BASE_URL']}/v1", ) resp = client.chat.completions.create( model="gpt-oss-120b", messages=[{"role": "user", "content": "Explain Serverless Postgres."}], ) print(resp.choices[0].message.content) ``` #### cURL ```bash curl "${NEON_AI_GATEWAY_BASE_URL}/v1/chat/completions" \ -H "Authorization: Bearer ${NEON_AI_GATEWAY_TOKEN}" \ -H "Content-Type: application/json" \ -d '{ "model": "gpt-oss-120b", "messages": [{"role": "user", "content": "Explain Serverless Postgres."}] }' ``` **Environment variables** ```bash # Injected by `neon env pull` when AI Gateway is enabled on the branch (neon.ts preview.aiGateway). # Neon injects ONLY the NEON_AI_GATEWAY_* vars (not OPENAI_*). Build the OpenAI SDK / curl # apiKey + baseURL from them: apiKey = NEON_AI_GATEWAY_TOKEN (the bearer, nt_live_...). # # NEON_AI_GATEWAY_BASE_URL is the bare gateway host (no path). Append the route you need: # - `/v1` - unified Chat Completions and `/v1/embeddings` # - `/openai/v1` - OpenAI Responses API # - `/typesafe` - TypeSafe SDK base URL for System One decisions (`/typesafe/v1/systemone`) # @neon/ai-sdk-provider and Mastra route requests automatically. NEON_AI_GATEWAY_TOKEN=nt_live_... NEON_AI_GATEWAY_BASE_URL=https://-api.ai....neon.tech ``` ## Model ID gpt-oss-120b ## Lab OpenAI makes GPT OSS 120B. Access the model through the Neon AI Gateway using chat/completions. ## Provider Databricks ## Inputs Text ## Context 131K ## Released Aug 2025 ## Input /M $0.15 ## Output /M $0.60 --- [Document source](https://neon.com/docs/ai-gateway/models/gpt-oss-20b.md) --- # GPT OSS 20B ## About Neon AI Gateway provides GPT OSS 20B by OpenAI. The model supports text inputs and a 131K context window. ## Command ### Text generation #### AI SDK Install: ```bash npm i ai @neon/ai-sdk-provider ``` ```typescript import { generateText } from "ai"; import { neon } from "@neon/ai-sdk-provider"; const { text } = await generateText({ model: neon("gpt-oss-20b"), prompt: "Explain Serverless Postgres.", }); console.log(text); ``` #### Mastra Install: ```bash npm i @mastra/core ``` ```typescript import { Agent } from "@mastra/core/agent"; const agent = new Agent({ id: "neon-demo", name: "neon-demo", instructions: "You are a helpful assistant.", model: "neon/gpt-oss-20b", }); const { text } = await agent.generate("Explain Serverless Postgres."); console.log(text); ``` #### TypeScript Install: ```bash npm i openai ``` ```typescript import OpenAI from "openai"; const client = new OpenAI({ apiKey: process.env.NEON_AI_GATEWAY_TOKEN, baseURL: `${process.env.NEON_AI_GATEWAY_BASE_URL}/v1`, }); const resp = await client.chat.completions.create({ model: "gpt-oss-20b", messages: [{ role: "user", content: "Explain Serverless Postgres." }], }); console.log(resp.choices[0].message.content); ``` #### Python Install: ```bash pip install openai ``` ```python import os from openai import OpenAI client = OpenAI( api_key=os.environ["NEON_AI_GATEWAY_TOKEN"], base_url=f"{os.environ['NEON_AI_GATEWAY_BASE_URL']}/v1", ) resp = client.chat.completions.create( model="gpt-oss-20b", messages=[{"role": "user", "content": "Explain Serverless Postgres."}], ) print(resp.choices[0].message.content) ``` #### cURL ```bash curl "${NEON_AI_GATEWAY_BASE_URL}/v1/chat/completions" \ -H "Authorization: Bearer ${NEON_AI_GATEWAY_TOKEN}" \ -H "Content-Type: application/json" \ -d '{ "model": "gpt-oss-20b", "messages": [{"role": "user", "content": "Explain Serverless Postgres."}] }' ``` **Environment variables** ```bash # Injected by `neon env pull` when AI Gateway is enabled on the branch (neon.ts preview.aiGateway). # Neon injects ONLY the NEON_AI_GATEWAY_* vars (not OPENAI_*). Build the OpenAI SDK / curl # apiKey + baseURL from them: apiKey = NEON_AI_GATEWAY_TOKEN (the bearer, nt_live_...). # # NEON_AI_GATEWAY_BASE_URL is the bare gateway host (no path). Append the route you need: # - `/v1` - unified Chat Completions and `/v1/embeddings` # - `/openai/v1` - OpenAI Responses API # - `/typesafe` - TypeSafe SDK base URL for System One decisions (`/typesafe/v1/systemone`) # @neon/ai-sdk-provider and Mastra route requests automatically. NEON_AI_GATEWAY_TOKEN=nt_live_... NEON_AI_GATEWAY_BASE_URL=https://-api.ai....neon.tech ``` ## Model ID gpt-oss-20b ## Lab OpenAI makes GPT OSS 20B. Access the model through the Neon AI Gateway using chat/completions. ## Provider Databricks ## Inputs Text ## Context 131K ## Released Aug 2025 ## Input /M $0.07 ## Output /M $0.30 --- [Document source](https://neon.com/docs/ai-gateway/models/grok-4-6.md) --- # Grok 4.6 ## About Neon AI Gateway provides Grok 4.6 by xAI. The model supports text, image inputs and a 500K context window. ## Command ### Text generation #### AI SDK Install: ```bash npm i ai @neon/ai-sdk-provider ``` ```typescript import { generateText } from "ai"; import { neon } from "@neon/ai-sdk-provider"; const { text } = await generateText({ model: neon("grok-4-6"), prompt: "Explain Serverless Postgres.", }); console.log(text); ``` #### Mastra Install: ```bash npm i @mastra/core ``` ```typescript import { Agent } from "@mastra/core/agent"; const agent = new Agent({ id: "neon-demo", name: "neon-demo", instructions: "You are a helpful assistant.", model: "neon/grok-4-6", }); const { text } = await agent.generate("Explain Serverless Postgres."); console.log(text); ``` #### TypeScript Install: ```bash npm i openai ``` ```typescript import OpenAI from "openai"; const client = new OpenAI({ apiKey: process.env.NEON_AI_GATEWAY_TOKEN, baseURL: `${process.env.NEON_AI_GATEWAY_BASE_URL}/v1`, }); const resp = await client.chat.completions.create({ model: "grok-4-6", messages: [{ role: "user", content: "Explain Serverless Postgres." }], }); console.log(resp.choices[0].message.content); ``` #### Python Install: ```bash pip install openai ``` ```python import os from openai import OpenAI client = OpenAI( api_key=os.environ["NEON_AI_GATEWAY_TOKEN"], base_url=f"{os.environ['NEON_AI_GATEWAY_BASE_URL']}/v1", ) resp = client.chat.completions.create( model="grok-4-6", messages=[{"role": "user", "content": "Explain Serverless Postgres."}], ) print(resp.choices[0].message.content) ``` #### cURL ```bash curl "${NEON_AI_GATEWAY_BASE_URL}/v1/chat/completions" \ -H "Authorization: Bearer ${NEON_AI_GATEWAY_TOKEN}" \ -H "Content-Type: application/json" \ -d '{ "model": "grok-4-6", "messages": [{"role": "user", "content": "Explain Serverless Postgres."}] }' ``` **Environment variables** ```bash # Injected by `neon env pull` when AI Gateway is enabled on the branch (neon.ts preview.aiGateway). # Neon injects ONLY the NEON_AI_GATEWAY_* vars (not OPENAI_*). Build the OpenAI SDK / curl # apiKey + baseURL from them: apiKey = NEON_AI_GATEWAY_TOKEN (the bearer, nt_live_...). # # NEON_AI_GATEWAY_BASE_URL is the bare gateway host (no path). Append the route you need: # - `/v1` - unified Chat Completions and `/v1/embeddings` # - `/openai/v1` - OpenAI Responses API # - `/typesafe` - TypeSafe SDK base URL for System One decisions (`/typesafe/v1/systemone`) # @neon/ai-sdk-provider and Mastra route requests automatically. NEON_AI_GATEWAY_TOKEN=nt_live_... NEON_AI_GATEWAY_BASE_URL=https://-api.ai....neon.tech ``` ## Model ID grok-4-6 ## Lab xAI makes Grok 4.6. Access the model through the Neon AI Gateway using chat/completions and openai/responses. ## Provider Databricks ## Inputs Text, image ## Context 500K ## Released Aug 2026 ## Input /M $2 ## Output /M $6 --- [Document source](https://neon.com/docs/ai-gateway/models/grok-4-7.md) --- # Grok 4.7 ## About Neon AI Gateway provides Grok 4.7 by xAI. The model supports text inputs and a 500K context window. ## Command ### Text generation #### AI SDK Install: ```bash npm i ai @neon/ai-sdk-provider ``` ```typescript import { generateText } from "ai"; import { neon } from "@neon/ai-sdk-provider"; const { text } = await generateText({ model: neon("grok-4-7"), prompt: "Explain Serverless Postgres.", }); console.log(text); ``` #### Mastra Install: ```bash npm i @mastra/core ``` ```typescript import { Agent } from "@mastra/core/agent"; const agent = new Agent({ id: "neon-demo", name: "neon-demo", instructions: "You are a helpful assistant.", model: "neon/grok-4-7", }); const { text } = await agent.generate("Explain Serverless Postgres."); console.log(text); ``` #### TypeScript Install: ```bash npm i openai ``` ```typescript import OpenAI from "openai"; const client = new OpenAI({ apiKey: process.env.NEON_AI_GATEWAY_TOKEN, baseURL: `${process.env.NEON_AI_GATEWAY_BASE_URL}/v1`, }); const resp = await client.chat.completions.create({ model: "grok-4-7", messages: [{ role: "user", content: "Explain Serverless Postgres." }], }); console.log(resp.choices[0].message.content); ``` #### Python Install: ```bash pip install openai ``` ```python import os from openai import OpenAI client = OpenAI( api_key=os.environ["NEON_AI_GATEWAY_TOKEN"], base_url=f"{os.environ['NEON_AI_GATEWAY_BASE_URL']}/v1", ) resp = client.chat.completions.create( model="grok-4-7", messages=[{"role": "user", "content": "Explain Serverless Postgres."}], ) print(resp.choices[0].message.content) ``` #### cURL ```bash curl "${NEON_AI_GATEWAY_BASE_URL}/v1/chat/completions" \ -H "Authorization: Bearer ${NEON_AI_GATEWAY_TOKEN}" \ -H "Content-Type: application/json" \ -d '{ "model": "grok-4-7", "messages": [{"role": "user", "content": "Explain Serverless Postgres."}] }' ``` **Environment variables** ```bash # Injected by `neon env pull` when AI Gateway is enabled on the branch (neon.ts preview.aiGateway). # Neon injects ONLY the NEON_AI_GATEWAY_* vars (not OPENAI_*). Build the OpenAI SDK / curl # apiKey + baseURL from them: apiKey = NEON_AI_GATEWAY_TOKEN (the bearer, nt_live_...). # # NEON_AI_GATEWAY_BASE_URL is the bare gateway host (no path). Append the route you need: # - `/v1` - unified Chat Completions and `/v1/embeddings` # - `/openai/v1` - OpenAI Responses API # - `/typesafe` - TypeSafe SDK base URL for System One decisions (`/typesafe/v1/systemone`) # @neon/ai-sdk-provider and Mastra route requests automatically. NEON_AI_GATEWAY_TOKEN=nt_live_... NEON_AI_GATEWAY_BASE_URL=https://-api.ai....neon.tech ``` ## Model ID grok-4-7 ## Lab xAI makes Grok 4.7. Access the model through the Neon AI Gateway using chat/completions and openai/responses. ## Provider Databricks ## Inputs Text ## Context 500K ## Released Sep 2026 ## Input /M $2.50 ## Output /M $7.50 --- [Document source](https://neon.com/docs/ai-gateway/models/gte-large-en.md) --- # GTE Large (En) ## About Neon AI Gateway provides GTE Large (En) by Alibaba. It returns 1024-dimensional embeddings on `POST /v1/embeddings`. ## Command ### Embeddings #### TypeScript Install: ```bash npm i openai ``` ```typescript import OpenAI from "openai"; const client = new OpenAI({ apiKey: process.env.NEON_AI_GATEWAY_TOKEN, baseURL: `${process.env.NEON_AI_GATEWAY_BASE_URL}/v1`, }); const resp = await client.embeddings.create({ model: "gte-large-en", input: ["Explain Serverless Postgres."], encoding_format: "float", }); console.log(resp.data[0].embedding.length, resp.usage); ``` #### Python Install: ```bash pip install openai ``` ```python import os from openai import OpenAI client = OpenAI( api_key=os.environ["NEON_AI_GATEWAY_TOKEN"], base_url=f"{os.environ['NEON_AI_GATEWAY_BASE_URL']}/v1", ) resp = client.embeddings.create( model="gte-large-en", input=["Explain Serverless Postgres."], encoding_format="float", ) print(len(resp.data[0].embedding), resp.usage) ``` #### cURL ```bash curl "${NEON_AI_GATEWAY_BASE_URL}/v1/embeddings" \ -H "Authorization: Bearer ${NEON_AI_GATEWAY_TOKEN}" \ -H "Content-Type: application/json" \ -d '{ "model": "gte-large-en", "input": ["Explain Serverless Postgres."], "encoding_format": "float" }' ``` **Environment variables** ```bash # Injected by `neon env pull` when AI Gateway is enabled on the branch (neon.ts preview.aiGateway). # Neon injects ONLY the NEON_AI_GATEWAY_* vars (not OPENAI_*). Build the OpenAI SDK / curl # apiKey + baseURL from them: apiKey = NEON_AI_GATEWAY_TOKEN (the bearer, nt_live_...). # # NEON_AI_GATEWAY_BASE_URL is the bare gateway host (no path). Append the route you need: # - `/v1` - unified Chat Completions and `/v1/embeddings` # - `/openai/v1` - OpenAI Responses API # - `/typesafe` - TypeSafe SDK base URL for System One decisions (`/typesafe/v1/systemone`) # @neon/ai-sdk-provider and Mastra route requests automatically. NEON_AI_GATEWAY_TOKEN=nt_live_... NEON_AI_GATEWAY_BASE_URL=https://-api.ai....neon.tech ``` ## Model ID gte-large-en ## Lab Alibaba makes GTE Large (En). Access it through the Neon AI Gateway's `POST /v1/embeddings` endpoint. ## Provider Databricks ## Dimensions 1024 ## Released Jul 2023 ## Input /M $0.13 --- [Document source](https://neon.com/docs/ai-gateway/models/kimi-k3-1-pro.md) --- # Kimi K3.1 Pro ## About Neon AI Gateway provides Kimi K3.1 Pro by Moonshot AI. The model supports text, image inputs and a 1M context window. ## Command ### Text generation #### AI SDK Install: ```bash npm i ai @neon/ai-sdk-provider ``` ```typescript import { generateText } from "ai"; import { neon } from "@neon/ai-sdk-provider"; const { text } = await generateText({ model: neon("kimi-k3-1-pro"), prompt: "Explain Serverless Postgres.", }); console.log(text); ``` #### Mastra Install: ```bash npm i @mastra/core ``` ```typescript import { Agent } from "@mastra/core/agent"; const agent = new Agent({ id: "neon-demo", name: "neon-demo", instructions: "You are a helpful assistant.", model: "neon/kimi-k3-1-pro", }); const { text } = await agent.generate("Explain Serverless Postgres."); console.log(text); ``` #### TypeScript Install: ```bash npm i openai ``` ```typescript import OpenAI from "openai"; const client = new OpenAI({ apiKey: process.env.NEON_AI_GATEWAY_TOKEN, baseURL: `${process.env.NEON_AI_GATEWAY_BASE_URL}/v1`, }); const resp = await client.chat.completions.create({ model: "kimi-k3-1-pro", messages: [{ role: "user", content: "Explain Serverless Postgres." }], }); console.log(resp.choices[0].message.content); ``` #### Python Install: ```bash pip install openai ``` ```python import os from openai import OpenAI client = OpenAI( api_key=os.environ["NEON_AI_GATEWAY_TOKEN"], base_url=f"{os.environ['NEON_AI_GATEWAY_BASE_URL']}/v1", ) resp = client.chat.completions.create( model="kimi-k3-1-pro", messages=[{"role": "user", "content": "Explain Serverless Postgres."}], ) print(resp.choices[0].message.content) ``` #### cURL ```bash curl "${NEON_AI_GATEWAY_BASE_URL}/v1/chat/completions" \ -H "Authorization: Bearer ${NEON_AI_GATEWAY_TOKEN}" \ -H "Content-Type: application/json" \ -d '{ "model": "kimi-k3-1-pro", "messages": [{"role": "user", "content": "Explain Serverless Postgres."}] }' ``` **Environment variables** ```bash # Injected by `neon env pull` when AI Gateway is enabled on the branch (neon.ts preview.aiGateway). # Neon injects ONLY the NEON_AI_GATEWAY_* vars (not OPENAI_*). Build the OpenAI SDK / curl # apiKey + baseURL from them: apiKey = NEON_AI_GATEWAY_TOKEN (the bearer, nt_live_...). # # NEON_AI_GATEWAY_BASE_URL is the bare gateway host (no path). Append the route you need: # - `/v1` - unified Chat Completions and `/v1/embeddings` # - `/openai/v1` - OpenAI Responses API # - `/typesafe` - TypeSafe SDK base URL for System One decisions (`/typesafe/v1/systemone`) # @neon/ai-sdk-provider and Mastra route requests automatically. NEON_AI_GATEWAY_TOKEN=nt_live_... NEON_AI_GATEWAY_BASE_URL=https://-api.ai....neon.tech ``` ## Model ID kimi-k3-1-pro ## Lab Moonshot AI makes Kimi K3.1 Pro. Access the model through the Neon AI Gateway using chat/completions. ## Provider Databricks ## Inputs Text, image ## Context 1M ## Released Nov 2026 ## Input /M Free ## Output /M Free --- [Document source](https://neon.com/docs/ai-gateway/models/kimi-k3.md) --- # Kimi K3 ## About Neon AI Gateway provides Kimi K3 by Moonshot AI. The model supports text, image, video inputs and a 1M context window. ## Command ### Text generation #### AI SDK Install: ```bash npm i ai @neon/ai-sdk-provider ``` ```typescript import { generateText } from "ai"; import { neon } from "@neon/ai-sdk-provider"; const { text } = await generateText({ model: neon("kimi-k3"), prompt: "Explain Serverless Postgres.", }); console.log(text); ``` #### Mastra Install: ```bash npm i @mastra/core ``` ```typescript import { Agent } from "@mastra/core/agent"; const agent = new Agent({ id: "neon-demo", name: "neon-demo", instructions: "You are a helpful assistant.", model: "neon/kimi-k3", }); const { text } = await agent.generate("Explain Serverless Postgres."); console.log(text); ``` #### TypeScript Install: ```bash npm i openai ``` ```typescript import OpenAI from "openai"; const client = new OpenAI({ apiKey: process.env.NEON_AI_GATEWAY_TOKEN, baseURL: `${process.env.NEON_AI_GATEWAY_BASE_URL}/v1`, }); const resp = await client.chat.completions.create({ model: "kimi-k3", messages: [{ role: "user", content: "Explain Serverless Postgres." }], }); console.log(resp.choices[0].message.content); ``` #### Python Install: ```bash pip install openai ``` ```python import os from openai import OpenAI client = OpenAI( api_key=os.environ["NEON_AI_GATEWAY_TOKEN"], base_url=f"{os.environ['NEON_AI_GATEWAY_BASE_URL']}/v1", ) resp = client.chat.completions.create( model="kimi-k3", messages=[{"role": "user", "content": "Explain Serverless Postgres."}], ) print(resp.choices[0].message.content) ``` #### cURL ```bash curl "${NEON_AI_GATEWAY_BASE_URL}/v1/chat/completions" \ -H "Authorization: Bearer ${NEON_AI_GATEWAY_TOKEN}" \ -H "Content-Type: application/json" \ -d '{ "model": "kimi-k3", "messages": [{"role": "user", "content": "Explain Serverless Postgres."}] }' ``` **Environment variables** ```bash # Injected by `neon env pull` when AI Gateway is enabled on the branch (neon.ts preview.aiGateway). # Neon injects ONLY the NEON_AI_GATEWAY_* vars (not OPENAI_*). Build the OpenAI SDK / curl # apiKey + baseURL from them: apiKey = NEON_AI_GATEWAY_TOKEN (the bearer, nt_live_...). # # NEON_AI_GATEWAY_BASE_URL is the bare gateway host (no path). Append the route you need: # - `/v1` - unified Chat Completions and `/v1/embeddings` # - `/openai/v1` - OpenAI Responses API # - `/typesafe` - TypeSafe SDK base URL for System One decisions (`/typesafe/v1/systemone`) # @neon/ai-sdk-provider and Mastra route requests automatically. NEON_AI_GATEWAY_TOKEN=nt_live_... NEON_AI_GATEWAY_BASE_URL=https://-api.ai....neon.tech ``` ## Model ID kimi-k3 ## Lab Moonshot AI makes Kimi K3. Access the model through the Neon AI Gateway using chat/completions. ## Provider Databricks ## Inputs Text, image, video ## Context 1M ## Released Jul 2026 ## Input /M $3 ## Output /M $15 --- [Document source](https://neon.com/docs/ai-gateway/models/llama-4-maverick.md) --- # Llama 4 Maverick ## About Neon AI Gateway provides Llama 4 Maverick by Meta. The model supports text, image inputs and a 1M context window. ## Command ### Text generation #### AI SDK Install: ```bash npm i ai @neon/ai-sdk-provider ``` ```typescript import { generateText } from "ai"; import { neon } from "@neon/ai-sdk-provider"; const { text } = await generateText({ model: neon("llama-4-maverick"), prompt: "Explain Serverless Postgres.", }); console.log(text); ``` #### Mastra Install: ```bash npm i @mastra/core ``` ```typescript import { Agent } from "@mastra/core/agent"; const agent = new Agent({ id: "neon-demo", name: "neon-demo", instructions: "You are a helpful assistant.", model: "neon/llama-4-maverick", }); const { text } = await agent.generate("Explain Serverless Postgres."); console.log(text); ``` #### TypeScript Install: ```bash npm i openai ``` ```typescript import OpenAI from "openai"; const client = new OpenAI({ apiKey: process.env.NEON_AI_GATEWAY_TOKEN, baseURL: `${process.env.NEON_AI_GATEWAY_BASE_URL}/v1`, }); const resp = await client.chat.completions.create({ model: "llama-4-maverick", messages: [{ role: "user", content: "Explain Serverless Postgres." }], }); console.log(resp.choices[0].message.content); ``` #### Python Install: ```bash pip install openai ``` ```python import os from openai import OpenAI client = OpenAI( api_key=os.environ["NEON_AI_GATEWAY_TOKEN"], base_url=f"{os.environ['NEON_AI_GATEWAY_BASE_URL']}/v1", ) resp = client.chat.completions.create( model="llama-4-maverick", messages=[{"role": "user", "content": "Explain Serverless Postgres."}], ) print(resp.choices[0].message.content) ``` #### cURL ```bash curl "${NEON_AI_GATEWAY_BASE_URL}/v1/chat/completions" \ -H "Authorization: Bearer ${NEON_AI_GATEWAY_TOKEN}" \ -H "Content-Type: application/json" \ -d '{ "model": "llama-4-maverick", "messages": [{"role": "user", "content": "Explain Serverless Postgres."}] }' ``` **Environment variables** ```bash # Injected by `neon env pull` when AI Gateway is enabled on the branch (neon.ts preview.aiGateway). # Neon injects ONLY the NEON_AI_GATEWAY_* vars (not OPENAI_*). Build the OpenAI SDK / curl # apiKey + baseURL from them: apiKey = NEON_AI_GATEWAY_TOKEN (the bearer, nt_live_...). # # NEON_AI_GATEWAY_BASE_URL is the bare gateway host (no path). Append the route you need: # - `/v1` - unified Chat Completions and `/v1/embeddings` # - `/openai/v1` - OpenAI Responses API # - `/typesafe` - TypeSafe SDK base URL for System One decisions (`/typesafe/v1/systemone`) # @neon/ai-sdk-provider and Mastra route requests automatically. NEON_AI_GATEWAY_TOKEN=nt_live_... NEON_AI_GATEWAY_BASE_URL=https://-api.ai....neon.tech ``` ## Model ID llama-4-maverick ## Lab Meta makes Llama 4 Maverick. Access the model through the Neon AI Gateway using chat/completions. ## Provider Databricks ## Inputs Text, image ## Context 1M ## Released Apr 2025 ## Input /M $0.50 ## Output /M $1.50 --- [Document source](https://neon.com/docs/ai-gateway/models/meta-llama-3-1-8b-instruct.md) --- # Meta Llama 3.1 8B Instruct ## About Neon AI Gateway provides Meta Llama 3.1 8B Instruct by Meta. The model supports text inputs and a 131K context window. ## Command ### Text generation #### AI SDK Install: ```bash npm i ai @neon/ai-sdk-provider ``` ```typescript import { generateText } from "ai"; import { neon } from "@neon/ai-sdk-provider"; const { text } = await generateText({ model: neon("meta-llama-3-1-8b-instruct"), prompt: "Explain Serverless Postgres.", }); console.log(text); ``` #### Mastra Install: ```bash npm i @mastra/core ``` ```typescript import { Agent } from "@mastra/core/agent"; const agent = new Agent({ id: "neon-demo", name: "neon-demo", instructions: "You are a helpful assistant.", model: "neon/meta-llama-3-1-8b-instruct", }); const { text } = await agent.generate("Explain Serverless Postgres."); console.log(text); ``` #### TypeScript Install: ```bash npm i openai ``` ```typescript import OpenAI from "openai"; const client = new OpenAI({ apiKey: process.env.NEON_AI_GATEWAY_TOKEN, baseURL: `${process.env.NEON_AI_GATEWAY_BASE_URL}/v1`, }); const resp = await client.chat.completions.create({ model: "meta-llama-3-1-8b-instruct", messages: [{ role: "user", content: "Explain Serverless Postgres." }], }); console.log(resp.choices[0].message.content); ``` #### Python Install: ```bash pip install openai ``` ```python import os from openai import OpenAI client = OpenAI( api_key=os.environ["NEON_AI_GATEWAY_TOKEN"], base_url=f"{os.environ['NEON_AI_GATEWAY_BASE_URL']}/v1", ) resp = client.chat.completions.create( model="meta-llama-3-1-8b-instruct", messages=[{"role": "user", "content": "Explain Serverless Postgres."}], ) print(resp.choices[0].message.content) ``` #### cURL ```bash curl "${NEON_AI_GATEWAY_BASE_URL}/v1/chat/completions" \ -H "Authorization: Bearer ${NEON_AI_GATEWAY_TOKEN}" \ -H "Content-Type: application/json" \ -d '{ "model": "meta-llama-3-1-8b-instruct", "messages": [{"role": "user", "content": "Explain Serverless Postgres."}] }' ``` **Environment variables** ```bash # Injected by `neon env pull` when AI Gateway is enabled on the branch (neon.ts preview.aiGateway). # Neon injects ONLY the NEON_AI_GATEWAY_* vars (not OPENAI_*). Build the OpenAI SDK / curl # apiKey + baseURL from them: apiKey = NEON_AI_GATEWAY_TOKEN (the bearer, nt_live_...). # # NEON_AI_GATEWAY_BASE_URL is the bare gateway host (no path). Append the route you need: # - `/v1` - unified Chat Completions and `/v1/embeddings` # - `/openai/v1` - OpenAI Responses API # - `/typesafe` - TypeSafe SDK base URL for System One decisions (`/typesafe/v1/systemone`) # @neon/ai-sdk-provider and Mastra route requests automatically. NEON_AI_GATEWAY_TOKEN=nt_live_... NEON_AI_GATEWAY_BASE_URL=https://-api.ai....neon.tech ``` ## Model ID meta-llama-3-1-8b-instruct ## Lab Meta makes Meta Llama 3.1 8B Instruct. Access the model through the Neon AI Gateway using chat/completions. ## Provider Databricks ## Inputs Text ## Context 131K ## Released Jul 2024 ## Input /M $0.15 ## Output /M $0.45 --- [Document source](https://neon.com/docs/ai-gateway/models/meta-llama-3-3-70b-instruct.md) --- # Meta Llama 3.3 70B Instruct ## About Neon AI Gateway provides Meta Llama 3.3 70B Instruct by Meta. The model supports text inputs and a 128K context window. ## Command ### Text generation #### AI SDK Install: ```bash npm i ai @neon/ai-sdk-provider ``` ```typescript import { generateText } from "ai"; import { neon } from "@neon/ai-sdk-provider"; const { text } = await generateText({ model: neon("meta-llama-3-3-70b-instruct"), prompt: "Explain Serverless Postgres.", }); console.log(text); ``` #### Mastra Install: ```bash npm i @mastra/core ``` ```typescript import { Agent } from "@mastra/core/agent"; const agent = new Agent({ id: "neon-demo", name: "neon-demo", instructions: "You are a helpful assistant.", model: "neon/meta-llama-3-3-70b-instruct", }); const { text } = await agent.generate("Explain Serverless Postgres."); console.log(text); ``` #### TypeScript Install: ```bash npm i openai ``` ```typescript import OpenAI from "openai"; const client = new OpenAI({ apiKey: process.env.NEON_AI_GATEWAY_TOKEN, baseURL: `${process.env.NEON_AI_GATEWAY_BASE_URL}/v1`, }); const resp = await client.chat.completions.create({ model: "meta-llama-3-3-70b-instruct", messages: [{ role: "user", content: "Explain Serverless Postgres." }], }); console.log(resp.choices[0].message.content); ``` #### Python Install: ```bash pip install openai ``` ```python import os from openai import OpenAI client = OpenAI( api_key=os.environ["NEON_AI_GATEWAY_TOKEN"], base_url=f"{os.environ['NEON_AI_GATEWAY_BASE_URL']}/v1", ) resp = client.chat.completions.create( model="meta-llama-3-3-70b-instruct", messages=[{"role": "user", "content": "Explain Serverless Postgres."}], ) print(resp.choices[0].message.content) ``` #### cURL ```bash curl "${NEON_AI_GATEWAY_BASE_URL}/v1/chat/completions" \ -H "Authorization: Bearer ${NEON_AI_GATEWAY_TOKEN}" \ -H "Content-Type: application/json" \ -d '{ "model": "meta-llama-3-3-70b-instruct", "messages": [{"role": "user", "content": "Explain Serverless Postgres."}] }' ``` **Environment variables** ```bash # Injected by `neon env pull` when AI Gateway is enabled on the branch (neon.ts preview.aiGateway). # Neon injects ONLY the NEON_AI_GATEWAY_* vars (not OPENAI_*). Build the OpenAI SDK / curl # apiKey + baseURL from them: apiKey = NEON_AI_GATEWAY_TOKEN (the bearer, nt_live_...). # # NEON_AI_GATEWAY_BASE_URL is the bare gateway host (no path). Append the route you need: # - `/v1` - unified Chat Completions and `/v1/embeddings` # - `/openai/v1` - OpenAI Responses API # - `/typesafe` - TypeSafe SDK base URL for System One decisions (`/typesafe/v1/systemone`) # @neon/ai-sdk-provider and Mastra route requests automatically. NEON_AI_GATEWAY_TOKEN=nt_live_... NEON_AI_GATEWAY_BASE_URL=https://-api.ai....neon.tech ``` ## Model ID meta-llama-3-3-70b-instruct ## Lab Meta makes Meta Llama 3.3 70B Instruct. Access the model through the Neon AI Gateway using chat/completions. ## Provider Databricks ## Inputs Text ## Context 128K ## Released Dec 2024 ## Input /M $0.50 ## Output /M $1.50 --- [Document source](https://neon.com/docs/ai-gateway/models/openjev-qwen35-4b.md) --- # OpenJev (Qwen 3.5 4B) ## About Neon AI Gateway provides OpenJev (Qwen 3.5 4B) by Alibaba, a System One decision model. It answers questions about a given state with a choice, a probability, or a score; it does not generate text. ## Command ### Decisions #### AI SDK Install: ```bash npm i ai@7 @neon/ai-sdk-provider ``` ```typescript import { experimental_decide as decide } from "ai"; import { neon } from "@neon/ai-sdk-provider"; const { answers, usage } = await decide({ model: neon.decisionModel("openjev-qwen35-4b"), state: "I was charged twice this month.", questions: { billing: { type: "boolean", instructions: "Is the user asking about billing?", criteria: { true: "Billing related", false: "Not billing" }, }, }, }); console.log(answers, usage); ``` #### TypeScript Install: ```bash npm i @typesafe-ai/sdk ``` ```typescript import { noul, TypeSafeClient } from "@typesafe-ai/sdk"; const client = new TypeSafeClient({ apiKey: process.env.NEON_AI_GATEWAY_TOKEN, baseURL: `${process.env.NEON_AI_GATEWAY_BASE_URL}/typesafe`, defaultModel: "openjev-qwen35-4b", }); const { answers, usage } = await client.systemOne({ state: "I was charged twice this month.", questions: { billing: noul("Is the user asking about billing?", { true: "Billing related", false: "Not billing", }), }, }); console.log(answers, usage); ``` #### Python Install: ```bash pip install typesafe-sdk ``` ```python import os from typesafe_sdk import Noul, TypeSafeClient with TypeSafeClient( api_key=os.environ["NEON_AI_GATEWAY_TOKEN"], base_url=f"{os.environ['NEON_AI_GATEWAY_BASE_URL']}/typesafe", model="openjev-qwen35-4b", ) as client: response = client.system_one( state="I was charged twice this month.", questions={ "billing": Noul( instructions="Is the user asking about billing?", criteria={"true": "Billing related", "false": "Not billing"}, ), }, ) print(response.answers, response.usage) ``` #### cURL ```bash curl "${NEON_AI_GATEWAY_BASE_URL}/typesafe/v1/systemone" \ -H "Authorization: Bearer ${NEON_AI_GATEWAY_TOKEN}" \ -H "Content-Type: application/json" \ -d '{ "model": "openjev-qwen35-4b", "state": "I was charged twice this month.", "questions": { "billing": { "type": "noul", "instructions": "Is the user asking about billing?", "criteria": {"true": "Billing related", "false": "Not billing"} } } }' ``` **Environment variables** ```bash # Injected by `neon env pull` when AI Gateway is enabled on the branch (neon.ts preview.aiGateway). # Neon injects ONLY the NEON_AI_GATEWAY_* vars (not OPENAI_*). Build the OpenAI SDK / curl # apiKey + baseURL from them: apiKey = NEON_AI_GATEWAY_TOKEN (the bearer, nt_live_...). # # NEON_AI_GATEWAY_BASE_URL is the bare gateway host (no path). Append the route you need: # - `/v1` - unified Chat Completions and `/v1/embeddings` # - `/openai/v1` - OpenAI Responses API # - `/typesafe` - TypeSafe SDK base URL for System One decisions (`/typesafe/v1/systemone`) # @neon/ai-sdk-provider and Mastra route requests automatically. NEON_AI_GATEWAY_TOKEN=nt_live_... NEON_AI_GATEWAY_BASE_URL=https://-api.ai....neon.tech ``` ## Model ID openjev-qwen35-4b ## Lab Alibaba makes OpenJev (Qwen 3.5 4B), a System One decision model. It answers questions about a given state with a choice, a probability, or a score; it does not generate text. ## Provider Databricks ## Context 131K ## Released Oct 2026 ## Input /M $0.042 --- [Document source](https://neon.com/docs/ai-gateway/models/qwen3-embedding-0-6b.md) --- # Qwen3 Embedding 0.6B ## About Neon AI Gateway provides Qwen3 Embedding 0.6B by Alibaba. It returns 1024-dimensional embeddings on `POST /v1/embeddings`. ## Command ### Embeddings #### TypeScript Install: ```bash npm i openai ``` ```typescript import OpenAI from "openai"; const client = new OpenAI({ apiKey: process.env.NEON_AI_GATEWAY_TOKEN, baseURL: `${process.env.NEON_AI_GATEWAY_BASE_URL}/v1`, }); const resp = await client.embeddings.create({ model: "qwen3-embedding-0-6b", input: ["Explain Serverless Postgres."], encoding_format: "float", }); console.log(resp.data[0].embedding.length, resp.usage); ``` #### Python Install: ```bash pip install openai ``` ```python import os from openai import OpenAI client = OpenAI( api_key=os.environ["NEON_AI_GATEWAY_TOKEN"], base_url=f"{os.environ['NEON_AI_GATEWAY_BASE_URL']}/v1", ) resp = client.embeddings.create( model="qwen3-embedding-0-6b", input=["Explain Serverless Postgres."], encoding_format="float", ) print(len(resp.data[0].embedding), resp.usage) ``` #### cURL ```bash curl "${NEON_AI_GATEWAY_BASE_URL}/v1/embeddings" \ -H "Authorization: Bearer ${NEON_AI_GATEWAY_TOKEN}" \ -H "Content-Type: application/json" \ -d '{ "model": "qwen3-embedding-0-6b", "input": ["Explain Serverless Postgres."], "encoding_format": "float" }' ``` **Environment variables** ```bash # Injected by `neon env pull` when AI Gateway is enabled on the branch (neon.ts preview.aiGateway). # Neon injects ONLY the NEON_AI_GATEWAY_* vars (not OPENAI_*). Build the OpenAI SDK / curl # apiKey + baseURL from them: apiKey = NEON_AI_GATEWAY_TOKEN (the bearer, nt_live_...). # # NEON_AI_GATEWAY_BASE_URL is the bare gateway host (no path). Append the route you need: # - `/v1` - unified Chat Completions and `/v1/embeddings` # - `/openai/v1` - OpenAI Responses API # - `/typesafe` - TypeSafe SDK base URL for System One decisions (`/typesafe/v1/systemone`) # @neon/ai-sdk-provider and Mastra route requests automatically. NEON_AI_GATEWAY_TOKEN=nt_live_... NEON_AI_GATEWAY_BASE_URL=https://-api.ai....neon.tech ``` ## Model ID qwen3-embedding-0-6b ## Lab Alibaba makes Qwen3 Embedding 0.6B. Access it through the Neon AI Gateway's `POST /v1/embeddings` endpoint. ## Provider Databricks ## Dimensions 1024 ## Released Jun 2025 ## Input /M $0.02 --- [Document source](https://neon.com/docs/ai-gateway/models/qwen3-next-80b-a3b-instruct.md) --- # Qwen3 Next Instruct ## About Neon AI Gateway provides Qwen3 Next Instruct by Alibaba. The model supports text inputs and a 131K context window. ## Command ### Text generation #### AI SDK Install: ```bash npm i ai @neon/ai-sdk-provider ``` ```typescript import { generateText } from "ai"; import { neon } from "@neon/ai-sdk-provider"; const { text } = await generateText({ model: neon("qwen3-next-80b-a3b-instruct"), prompt: "Explain Serverless Postgres.", }); console.log(text); ``` #### Mastra Install: ```bash npm i @mastra/core ``` ```typescript import { Agent } from "@mastra/core/agent"; const agent = new Agent({ id: "neon-demo", name: "neon-demo", instructions: "You are a helpful assistant.", model: "neon/qwen3-next-80b-a3b-instruct", }); const { text } = await agent.generate("Explain Serverless Postgres."); console.log(text); ``` #### TypeScript Install: ```bash npm i openai ``` ```typescript import OpenAI from "openai"; const client = new OpenAI({ apiKey: process.env.NEON_AI_GATEWAY_TOKEN, baseURL: `${process.env.NEON_AI_GATEWAY_BASE_URL}/v1`, }); const resp = await client.chat.completions.create({ model: "qwen3-next-80b-a3b-instruct", messages: [{ role: "user", content: "Explain Serverless Postgres." }], }); console.log(resp.choices[0].message.content); ``` #### Python Install: ```bash pip install openai ``` ```python import os from openai import OpenAI client = OpenAI( api_key=os.environ["NEON_AI_GATEWAY_TOKEN"], base_url=f"{os.environ['NEON_AI_GATEWAY_BASE_URL']}/v1", ) resp = client.chat.completions.create( model="qwen3-next-80b-a3b-instruct", messages=[{"role": "user", "content": "Explain Serverless Postgres."}], ) print(resp.choices[0].message.content) ``` #### cURL ```bash curl "${NEON_AI_GATEWAY_BASE_URL}/v1/chat/completions" \ -H "Authorization: Bearer ${NEON_AI_GATEWAY_TOKEN}" \ -H "Content-Type: application/json" \ -d '{ "model": "qwen3-next-80b-a3b-instruct", "messages": [{"role": "user", "content": "Explain Serverless Postgres."}] }' ``` **Environment variables** ```bash # Injected by `neon env pull` when AI Gateway is enabled on the branch (neon.ts preview.aiGateway). # Neon injects ONLY the NEON_AI_GATEWAY_* vars (not OPENAI_*). Build the OpenAI SDK / curl # apiKey + baseURL from them: apiKey = NEON_AI_GATEWAY_TOKEN (the bearer, nt_live_...). # # NEON_AI_GATEWAY_BASE_URL is the bare gateway host (no path). Append the route you need: # - `/v1` - unified Chat Completions and `/v1/embeddings` # - `/openai/v1` - OpenAI Responses API # - `/typesafe` - TypeSafe SDK base URL for System One decisions (`/typesafe/v1/systemone`) # @neon/ai-sdk-provider and Mastra route requests automatically. NEON_AI_GATEWAY_TOKEN=nt_live_... NEON_AI_GATEWAY_BASE_URL=https://-api.ai....neon.tech ``` ## Model ID qwen3-next-80b-a3b-instruct ## Lab Alibaba makes Qwen3 Next Instruct. Access the model through the Neon AI Gateway using chat/completions. ## Provider Databricks ## Inputs Text ## Context 131K ## Released Sep 2025 ## Input /M $0.15 ## Output /M $1.20 --- [Document source](https://neon.com/docs/ai-gateway/models/qwen35-122b-a10b.md) --- # Qwen3.5 122B A10B ## About Neon AI Gateway provides Qwen3.5 122B A10B by Alibaba. The model supports text inputs and a 262K context window. ## Command ### Text generation #### AI SDK Install: ```bash npm i ai @neon/ai-sdk-provider ``` ```typescript import { generateText } from "ai"; import { neon } from "@neon/ai-sdk-provider"; const { text } = await generateText({ model: neon("qwen35-122b-a10b"), prompt: "Explain Serverless Postgres.", }); console.log(text); ``` #### Mastra Install: ```bash npm i @mastra/core ``` ```typescript import { Agent } from "@mastra/core/agent"; const agent = new Agent({ id: "neon-demo", name: "neon-demo", instructions: "You are a helpful assistant.", model: "neon/qwen35-122b-a10b", }); const { text } = await agent.generate("Explain Serverless Postgres."); console.log(text); ``` #### TypeScript Install: ```bash npm i openai ``` ```typescript import OpenAI from "openai"; const client = new OpenAI({ apiKey: process.env.NEON_AI_GATEWAY_TOKEN, baseURL: `${process.env.NEON_AI_GATEWAY_BASE_URL}/v1`, }); const resp = await client.chat.completions.create({ model: "qwen35-122b-a10b", messages: [{ role: "user", content: "Explain Serverless Postgres." }], }); console.log(resp.choices[0].message.content); ``` #### Python Install: ```bash pip install openai ``` ```python import os from openai import OpenAI client = OpenAI( api_key=os.environ["NEON_AI_GATEWAY_TOKEN"], base_url=f"{os.environ['NEON_AI_GATEWAY_BASE_URL']}/v1", ) resp = client.chat.completions.create( model="qwen35-122b-a10b", messages=[{"role": "user", "content": "Explain Serverless Postgres."}], ) print(resp.choices[0].message.content) ``` #### cURL ```bash curl "${NEON_AI_GATEWAY_BASE_URL}/v1/chat/completions" \ -H "Authorization: Bearer ${NEON_AI_GATEWAY_TOKEN}" \ -H "Content-Type: application/json" \ -d '{ "model": "qwen35-122b-a10b", "messages": [{"role": "user", "content": "Explain Serverless Postgres."}] }' ``` **Environment variables** ```bash # Injected by `neon env pull` when AI Gateway is enabled on the branch (neon.ts preview.aiGateway). # Neon injects ONLY the NEON_AI_GATEWAY_* vars (not OPENAI_*). Build the OpenAI SDK / curl # apiKey + baseURL from them: apiKey = NEON_AI_GATEWAY_TOKEN (the bearer, nt_live_...). # # NEON_AI_GATEWAY_BASE_URL is the bare gateway host (no path). Append the route you need: # - `/v1` - unified Chat Completions and `/v1/embeddings` # - `/openai/v1` - OpenAI Responses API # - `/typesafe` - TypeSafe SDK base URL for System One decisions (`/typesafe/v1/systemone`) # @neon/ai-sdk-provider and Mastra route requests automatically. NEON_AI_GATEWAY_TOKEN=nt_live_... NEON_AI_GATEWAY_BASE_URL=https://-api.ai....neon.tech ``` ## Model ID qwen35-122b-a10b ## Lab Alibaba makes Qwen3.5 122B A10B. Access the model through the Neon AI Gateway using chat/completions. ## Provider Databricks ## Inputs Text ## Context 262K ## Released Feb 2026 ## Input /M $0.22 ## Output /M $2.20 --- [Document source](https://neon.com/docs/ai-gateway/models/typesafeai-jev-1-14-0.md) --- # Jev 1.14 ## About Neon AI Gateway provides Jev 1.14 by TypeSafe AI, a System One decision model. It answers questions about a given state with a choice, a probability, or a score; it does not generate text. ## Command ### Decisions #### AI SDK Install: ```bash npm i ai@7 @neon/ai-sdk-provider ``` ```typescript import { experimental_decide as decide } from "ai"; import { neon } from "@neon/ai-sdk-provider"; const { answers, usage } = await decide({ model: neon.decisionModel("typesafeai-jev-1-14-0"), state: "I was charged twice this month.", questions: { billing: { type: "boolean", instructions: "Is the user asking about billing?", criteria: { true: "Billing related", false: "Not billing" }, }, }, }); console.log(answers, usage); ``` #### TypeScript Install: ```bash npm i @typesafe-ai/sdk ``` ```typescript import { noul, TypeSafeClient } from "@typesafe-ai/sdk"; const client = new TypeSafeClient({ apiKey: process.env.NEON_AI_GATEWAY_TOKEN, baseURL: `${process.env.NEON_AI_GATEWAY_BASE_URL}/typesafe`, defaultModel: "typesafeai-jev-1-14-0", }); const { answers, usage } = await client.systemOne({ state: "I was charged twice this month.", questions: { billing: noul("Is the user asking about billing?", { true: "Billing related", false: "Not billing", }), }, }); console.log(answers, usage); ``` #### Python Install: ```bash pip install typesafe-sdk ``` ```python import os from typesafe_sdk import Noul, TypeSafeClient with TypeSafeClient( api_key=os.environ["NEON_AI_GATEWAY_TOKEN"], base_url=f"{os.environ['NEON_AI_GATEWAY_BASE_URL']}/typesafe", model="typesafeai-jev-1-14-0", ) as client: response = client.system_one( state="I was charged twice this month.", questions={ "billing": Noul( instructions="Is the user asking about billing?", criteria={"true": "Billing related", "false": "Not billing"}, ), }, ) print(response.answers, response.usage) ``` #### cURL ```bash curl "${NEON_AI_GATEWAY_BASE_URL}/typesafe/v1/systemone" \ -H "Authorization: Bearer ${NEON_AI_GATEWAY_TOKEN}" \ -H "Content-Type: application/json" \ -d '{ "model": "typesafeai-jev-1-14-0", "state": "I was charged twice this month.", "questions": { "billing": { "type": "noul", "instructions": "Is the user asking about billing?", "criteria": {"true": "Billing related", "false": "Not billing"} } } }' ``` **Environment variables** ```bash # Injected by `neon env pull` when AI Gateway is enabled on the branch (neon.ts preview.aiGateway). # Neon injects ONLY the NEON_AI_GATEWAY_* vars (not OPENAI_*). Build the OpenAI SDK / curl # apiKey + baseURL from them: apiKey = NEON_AI_GATEWAY_TOKEN (the bearer, nt_live_...). # # NEON_AI_GATEWAY_BASE_URL is the bare gateway host (no path). Append the route you need: # - `/v1` - unified Chat Completions and `/v1/embeddings` # - `/openai/v1` - OpenAI Responses API # - `/typesafe` - TypeSafe SDK base URL for System One decisions (`/typesafe/v1/systemone`) # @neon/ai-sdk-provider and Mastra route requests automatically. NEON_AI_GATEWAY_TOKEN=nt_live_... NEON_AI_GATEWAY_BASE_URL=https://-api.ai....neon.tech ``` ## Model ID typesafeai-jev-1-14-0 ## Lab TypeSafe AI makes Jev 1.14, a System One decision model. It answers questions about a given state with a choice, a probability, or a score; it does not generate text. ## Provider TypeSafe AI ## Context 66K ## Released Oct 2026 ## Input /M $0.042 --- [Document source](https://neon.com/docs/ai-gateway/openai-responses.md) --- > Summary: The OpenAI Responses endpoint exposes the OpenAI Responses API through Neon AI Gateway. Required for codex model variants, which do not work with the chat completions endpoint. # OpenAI Responses API Use the OpenAI Responses API with Neon AI Gateway Last updated: 2026-10-23 The OpenAI Responses endpoint exposes the [OpenAI Responses API](https://platform.openai.com/docs/api-reference/responses) through Neon AI Gateway. Use it with the OpenAI SDK's `responses.create()` method by changing only the `baseURL`. **Base URL:** `https:///openai/v1` This endpoint is also reachable at the longer `/ai-gateway/openai/v1/responses` path. Both behave identically and neither is deprecated. See [Shorter paths](https://neon.com/docs/ai-gateway/models#shorter-paths) for the full list of aliases. If you're using an OpenAI-compatible client that accepts a base URL, set it to either `https:///openai/v1` or `https:///ai-gateway/openai/v1`. The request and response shapes are the standard OpenAI Responses API shape. **Warning:** Codex model variants such as `gpt-5-3-codex` **require this endpoint**. They don't work with the [chat completions endpoint](https://neon.com/docs/ai-gateway/chat-completions). ## Setup Set these environment variables. See [Get started](https://neon.com/docs/ai-gateway/get-started) for how to obtain them. ```bash NEON_AI_GATEWAY_TOKEN=nt_live_... NEON_AI_GATEWAY_BASE_URL=https://br-winter-pond-aptw82ef-api.ai.c-2.us-east-2.aws.neon.tech ``` ## Supported models This endpoint accepts OpenAI models only: | Model ID | Notes | | --------------- | ---------------------- | | `gpt-6-astra` | | | `gpt-5-6-sol` | | | `gpt-5-6-terra` | | | `gpt-5-6-luna` | | | `gpt-5-5` | | | `gpt-5-5-pro` | Requires this endpoint | | `gpt-5-4` | | | `gpt-5-4-mini` | | | `gpt-5-4-nano` | | | `gpt-5-3-codex` | Requires this endpoint | | `gpt-5-2` | | | `gpt-5-1` | | | `gpt-5` | | | `gpt-5-mini` | | | `gpt-5-nano` | | Sending a non-OpenAI model ID returns `400 model "" is not available on the openai_responses endpoint`. ## Basic request **TypeScript (OpenAI SDK)** ```typescript import OpenAI from 'openai'; const client = new OpenAI({ apiKey: process.env.NEON_AI_GATEWAY_TOKEN, baseURL: `${process.env.NEON_AI_GATEWAY_BASE_URL}/openai/v1`, }); const response = await client.responses.create({ model: 'gpt-5-4', input: [{ role: 'user', content: 'What is Neon?' }], }); console.log(response.output_text); ``` **Python (OpenAI SDK)** ```python from openai import OpenAI import os client = OpenAI( api_key=os.environ['NEON_AI_GATEWAY_TOKEN'], base_url=f"{os.environ['NEON_AI_GATEWAY_BASE_URL']}/openai/v1", ) response = client.responses.create( model='gpt-5-4', input=[{'role': 'user', 'content': 'What is Neon?'}], ) print(response.output_text) ``` **cURL** ```bash curl -X POST "$NEON_AI_GATEWAY_BASE_URL/openai/v1/responses" \ -H "Authorization: Bearer $NEON_AI_GATEWAY_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "model": "gpt-5-4", "input": [{"role": "user", "content": "What is Neon?"}] }' ``` ## Streaming **TypeScript (OpenAI SDK)** ```typescript const stream = await client.responses.create({ model: 'gpt-5-4', input: [{ role: 'user', content: 'Explain database branching.' }], stream: true, }); for await (const event of stream) { if (event.type === 'response.output_text.delta') { process.stdout.write(event.delta); } } ``` **Python (OpenAI SDK)** ```python with client.responses.stream( model='gpt-5-4', input=[{'role': 'user', 'content': 'Explain database branching.'}], ) as stream: for event in stream: if event.type == 'response.output_text.delta': print(event.delta, end='', flush=True) ``` **cURL** ```bash curl -X POST "$NEON_AI_GATEWAY_BASE_URL/openai/v1/responses" \ -H "Authorization: Bearer $NEON_AI_GATEWAY_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "model": "gpt-5-4", "input": [{"role": "user", "content": "Explain database branching."}], "stream": true }' ``` ## Image generation with Vercel AI SDK The `@neon/ai-sdk-provider` package re-exports the OpenAI provider's Responses image-generation tool as `neon.tools.imageGeneration()`. Use it with OpenAI-routed models such as `gpt-5-mini`. Set `model` on the tool to `gpt-image-2`, `gpt-image-1.5`, or `gpt-image-1-mini`. `gpt-image-1` is deprecated and not available on AI Gateway. In `@neon/ai-sdk-provider` 1.3.0 and later, the tool sends `gpt-image-2` when you leave out `model`, and throws `UnsupportedFunctionalityError` for `gpt-image-1`. Use `streamText`, not `generateText`. A non-streaming response is limited to 655,360 bytes, and most base64 images are larger, so the request fails with `400` and `The response content length cannot be greater than 655360 bytes long`. With the OpenAI SDK, pass `stream: true` to `client.responses.create()`. ```typescript import { neon } from '@neon/ai-sdk-provider'; import { streamText } from 'ai'; const result = streamText({ model: neon('gpt-5-mini'), messages: [{ role: 'user', content: 'Create a simple Neon database mascot.' }], tools: { image: neon.tools.imageGeneration({ model: 'gpt-image-2', outputFormat: 'jpeg', size: '1024x1024', partialImages: 3, }), }, }); return result.toUIMessageStreamResponse(); ``` AI SDK `generateImage()` is not supported by AI Gateway; image generation is available only through this Responses tool. ## Error handling | Status | Message | Cause | | ----------------- | ---------------------------------------------------------------------- | -------------------------------------- | | `400 Bad Request` | `unknown model ""` | Model ID not in the catalog | | `400 Bad Request` | `model "" is not available on the openai_responses endpoint` | Non-OpenAI model sent to this endpoint | For authentication, quota, and upstream errors, see [Troubleshooting](https://neon.com/docs/ai-gateway/troubleshooting). ## Next steps - [Models](https://neon.com/docs/ai-gateway/models): full model catalog and which models require this endpoint - [Chat completions](https://neon.com/docs/ai-gateway/chat-completions): use any model via the unified OpenAI-compatible endpoint - [Authentication](https://neon.com/docs/ai-gateway/authentication): credential scopes and branch binding --- [Document source](https://neon.com/docs/ai-gateway/overview.md) --- > Summary: Neon AI Gateway is the LLM gateway built into your Neon project. One Neon credential gives you access to models across multiple providers. Standard AI SDKs work without code changes. Each branch gets its own gateway endpoint. # Neon AI Gateway One API for open-weight and foundation models from OpenAI, Google, and more. Built into your Neon project. Last updated: 2026-10-30 Add chat, agents, and embeddings to your app through one endpoint and one Neon credential, with models from many providers, scoped to your branch the same way your data is. Before you start: AI Gateway needs [prepaid credits](https://neon.com/docs/ai-gateway/prepaid-credits) ($5 minimum), which you can buy on any Neon plan, including Free, and a project in AWS US East (Ohio) (aws-us-east-2), AWS US East (N. Virginia) (aws-us-east-1), AWS Europe (Frankfurt) (aws-eu-central-1), or AWS Asia Pacific (Singapore) (aws-ap-southeast-1). Support is expanding toward [all regions](https://neon.com/docs/introduction/regions). [View prompt](https://neon.com/prompts/ai-gateway-landing.md) ## Available models Browse the full catalog below. Switch between the **Text**, **Image**, **Embeddings**, and **Decisions** tabs, filter by lab or open weights, sort any column, and click a model for a copy-paste quickstart. Chat and image models get AI SDK, Mastra, Python, TypeScript, and cURL; embedding models get Python, TypeScript, and cURL; System One decision models get AI SDK, TypeScript, Python, and cURL. The endpoint each snippet targets is baked into its base URL: `/v1` for chat completions and embeddings, `/openai/v1` for the Responses API (image generation), `/typesafe/v1/systemone` for decisions. ### Text models #### Anthropic | Model | Model ID | Inputs | Context | Released | Reasoning | Input /M | Output /M | Endpoints | License | | --------------------------------------------------------------------------------- | ------------------- | ---------------- | ------- | -------- | --------- | -------- | --------- | ------------------------------------- | ------- | | [Claude Haiku 5.5](https://neon.com/docs/ai-gateway/models/claude-haiku-5-5.md) | `claude-haiku-5-5` | text, image, pdf | 200K | Oct 2026 | Yes | $0.10 | $0.50 | chat/completions · anthropic/messages | — | | [Claude Sonnet 5.5](https://neon.com/docs/ai-gateway/models/claude-sonnet-5-5.md) | `claude-sonnet-5-5` | text, image, pdf | 1M | Sep 2026 | Yes | $2 | $10 | chat/completions · anthropic/messages | — | | [Claude Opus 5.5](https://neon.com/docs/ai-gateway/models/claude-opus-5-5.md) | `claude-opus-5-5` | text, image, pdf | 1M | Sep 2026 | Yes | $4 | $20 | chat/completions · anthropic/messages | — | | [Claude Fable 5.1](https://neon.com/docs/ai-gateway/models/claude-fable-5-1.md) | `claude-fable-5-1` | text, image, pdf | 1M | Sep 2026 | Yes | $10 | $50 | chat/completions · anthropic/messages | — | | [Claude Opus 5](https://neon.com/docs/ai-gateway/models/claude-opus-5.md) | `claude-opus-5` | text, image, pdf | 1M | Jul 2026 | Yes | $5 | $25 | chat/completions · anthropic/messages | — | | [Claude Sonnet 5](https://neon.com/docs/ai-gateway/models/claude-sonnet-5.md) | `claude-sonnet-5` | text, image, pdf | 1M | Jun 2026 | Yes | $2 | $10 | chat/completions · anthropic/messages | — | | [Claude Fable 5](https://neon.com/docs/ai-gateway/models/claude-fable-5.md) | `claude-fable-5` | text, image, pdf | 1M | Jun 2026 | Yes | $10 | $50 | chat/completions · anthropic/messages | — | | [Claude Opus 4.8](https://neon.com/docs/ai-gateway/models/claude-opus-4-8.md) | `claude-opus-4-8` | text, image, pdf | 1M | May 2026 | Yes | $5 | $25 | chat/completions · anthropic/messages | — | | [Claude Opus 4.7](https://neon.com/docs/ai-gateway/models/claude-opus-4-7.md) | `claude-opus-4-7` | text, image, pdf | 1M | Apr 2026 | Yes | $5 | $25 | chat/completions · anthropic/messages | — | | [Claude Sonnet 4.6](https://neon.com/docs/ai-gateway/models/claude-sonnet-4-6.md) | `claude-sonnet-4-6` | text, image, pdf | 1M | Feb 2026 | Yes | $3 | $15 | chat/completions · anthropic/messages | — | | [Claude Opus 4.6](https://neon.com/docs/ai-gateway/models/claude-opus-4-6.md) | `claude-opus-4-6` | text, image, pdf | 1M | Feb 2026 | Yes | $5 | $25 | chat/completions · anthropic/messages | — | | [Claude Opus 4.5](https://neon.com/docs/ai-gateway/models/claude-opus-4-5.md) | `claude-opus-4-5` | text, image, pdf | 200K | Nov 2025 | Yes | $5 | $25 | chat/completions · anthropic/messages | — | | [Claude Haiku 4.5](https://neon.com/docs/ai-gateway/models/claude-haiku-4-5.md) | `claude-haiku-4-5` | text, image, pdf | 200K | Oct 2025 | Yes | $1 | $5 | chat/completions · anthropic/messages | — | | [Claude Sonnet 4.5](https://neon.com/docs/ai-gateway/models/claude-sonnet-4-5.md) | `claude-sonnet-4-5` | text, image, pdf | 200K | Sep 2025 | Yes | $3 | $15 | chat/completions · anthropic/messages | — | | [Claude Opus 4.1](https://neon.com/docs/ai-gateway/models/claude-opus-4-1.md) | `claude-opus-4-1` | text, image, pdf | 200K | Aug 2025 | Yes | $15 | $75 | chat/completions · anthropic/messages | — | #### OpenAI | Model | Model ID | Inputs | Context | Released | Reasoning | Input /M | Output /M | Endpoints | License | | ------------------------------------------------------------------------- | --------------- | ---------------- | ------- | -------- | --------- | -------- | --------- | ----------------------------------- | ------------ | | [GPT-6.1 Sol](https://neon.com/docs/ai-gateway/models/gpt-6-1-sol.md) | `gpt-6-1-sol` | text, image, pdf | 1.1M | Sep 2026 | Yes | $2 | $10 | chat/completions · openai/responses | — | | [GPT-6 Sol](https://neon.com/docs/ai-gateway/models/gpt-6-sol.md) | `gpt-6-sol` | text, image, pdf | 1.1M | Sep 2026 | Yes | $2 | $10 | chat/completions · openai/responses | — | | [GPT-6 Luna](https://neon.com/docs/ai-gateway/models/gpt-6-luna.md) | `gpt-6-luna` | text, image, pdf | 1.1M | Sep 2026 | Yes | $0.10 | $0.50 | chat/completions · openai/responses | — | | [GPT-6 Astra](https://neon.com/docs/ai-gateway/models/gpt-6-astra.md) | `gpt-6-astra` | text, image, pdf | 1.1M | Sep 2026 | Yes | $10 | $50 | chat/completions · openai/responses | — | | [GPT-5.6 Luna](https://neon.com/docs/ai-gateway/models/gpt-5-6-luna.md) | `gpt-5-6-luna` | text, image, pdf | 1.1M | Jul 2026 | Yes | $0.20 | $1.20 | chat/completions · openai/responses | — | | [GPT-5.6 Sol](https://neon.com/docs/ai-gateway/models/gpt-5-6-sol.md) | `gpt-5-6-sol` | text, image, pdf | 1.1M | Jul 2026 | Yes | $5 | $30 | chat/completions · openai/responses | — | | [GPT-5.6 Terra](https://neon.com/docs/ai-gateway/models/gpt-5-6-terra.md) | `gpt-5-6-terra` | text, image, pdf | 1.1M | Jul 2026 | Yes | $2 | $12 | chat/completions · openai/responses | — | | [GPT-5.5](https://neon.com/docs/ai-gateway/models/gpt-5-5.md) | `gpt-5-5` | text, image, pdf | 1.1M | Apr 2026 | Yes | $5 | $30 | chat/completions · openai/responses | — | | [GPT-5.5 Pro](https://neon.com/docs/ai-gateway/models/gpt-5-5-pro.md) | `gpt-5-5-pro` | text, image, pdf | 1.1M | Apr 2026 | Yes | $30 | $180 | openai/responses | — | | [GPT-5.4 Mini](https://neon.com/docs/ai-gateway/models/gpt-5-4-mini.md) | `gpt-5-4-mini` | text, image | 400K | Mar 2026 | Yes | $0.75 | $4.50 | chat/completions · openai/responses | — | | [GPT-5.4 Nano](https://neon.com/docs/ai-gateway/models/gpt-5-4-nano.md) | `gpt-5-4-nano` | text, image | 400K | Mar 2026 | Yes | $0.20 | $1.25 | chat/completions · openai/responses | — | | [GPT-5.4](https://neon.com/docs/ai-gateway/models/gpt-5-4.md) | `gpt-5-4` | text, image, pdf | 1.1M | Mar 2026 | Yes | $2.50 | $15 | chat/completions · openai/responses | — | | [GPT-5.3 Codex](https://neon.com/docs/ai-gateway/models/gpt-5-3-codex.md) | `gpt-5-3-codex` | text, image, pdf | 400K | Feb 2026 | Yes | $1.75 | $14 | openai/responses | — | | [GPT-5.2](https://neon.com/docs/ai-gateway/models/gpt-5-2.md) | `gpt-5-2` | text, image | 400K | Dec 2025 | Yes | $1.75 | $14 | chat/completions · openai/responses | — | | [GPT-5.1](https://neon.com/docs/ai-gateway/models/gpt-5-1.md) | `gpt-5-1` | text, image | 400K | Nov 2025 | Yes | $1.25 | $10 | chat/completions · openai/responses | — | | [GPT-5](https://neon.com/docs/ai-gateway/models/gpt-5.md) | `gpt-5` | text, image | 400K | Aug 2025 | Yes | $1.25 | $10 | chat/completions · openai/responses | — | | [GPT-5 Mini](https://neon.com/docs/ai-gateway/models/gpt-5-mini.md) | `gpt-5-mini` | text, image | 400K | Aug 2025 | Yes | $0.25 | $2 | chat/completions · openai/responses | — | | [GPT-5 Nano](https://neon.com/docs/ai-gateway/models/gpt-5-nano.md) | `gpt-5-nano` | text, image | 400K | Aug 2025 | Yes | $0.05 | $0.40 | chat/completions · openai/responses | — | | [GPT OSS 120B](https://neon.com/docs/ai-gateway/models/gpt-oss-120b.md) | `gpt-oss-120b` | text | 131K | Aug 2025 | Yes | $0.15 | $0.60 | chat/completions | Open weights | | [GPT OSS 20B](https://neon.com/docs/ai-gateway/models/gpt-oss-20b.md) | `gpt-oss-20b` | text | 131K | Aug 2025 | Yes | $0.07 | $0.30 | chat/completions | Open weights | #### Google | Model | Model ID | Inputs | Context | Released | Reasoning | Input /M | Output /M | Endpoints | License | | ----------------------------------------------------------------------------------------- | ----------------------- | ------------------------------ | ------- | -------- | --------- | -------- | --------- | ------------------------- | ------------ | | [Gemini 4 Argon](https://neon.com/docs/ai-gateway/models/gemini-4-argon.md) | `gemini-4-argon` | text, image, video, audio, pdf | 1M | Oct 2026 | Yes | $4 | $20 | chat/completions · gemini | — | | [Gemini 3.8 Flash](https://neon.com/docs/ai-gateway/models/gemini-3-8-flash.md) | `gemini-3-8-flash` | text, image, video, audio, pdf | 1M | Sep 2026 | Yes | $1.50 | $7.50 | chat/completions · gemini | — | | [Gemini 3.7 Flash](https://neon.com/docs/ai-gateway/models/gemini-3-7-flash.md) | `gemini-3-7-flash` | text, image, video, audio, pdf | 1M | Aug 2026 | Yes | $1.50 | $7.50 | chat/completions · gemini | — | | [Gemini 3.5 Flash Lite](https://neon.com/docs/ai-gateway/models/gemini-3-5-flash-lite.md) | `gemini-3-5-flash-lite` | text, image, video, audio, pdf | 1M | Jul 2026 | Yes | $0.30 | $2.50 | chat/completions · gemini | — | | [Gemini 3.6 Flash](https://neon.com/docs/ai-gateway/models/gemini-3-6-flash.md) | `gemini-3-6-flash` | text, image, video, audio, pdf | 1M | Jul 2026 | Yes | $1.50 | $7.50 | chat/completions · gemini | — | | [Gemini 3.5 Flash](https://neon.com/docs/ai-gateway/models/gemini-3-5-flash.md) | `gemini-3-5-flash` | text, image, video, audio, pdf | 1M | May 2026 | Yes | $1.50 | $9 | chat/completions · gemini | — | | [Gemini 3.1 Flash Lite](https://neon.com/docs/ai-gateway/models/gemini-3-1-flash-lite.md) | `gemini-3-1-flash-lite` | text, image, video, audio, pdf | 1M | Mar 2026 | Yes | $0.25 | $1.50 | chat/completions · gemini | — | | [Gemini 3.1 Pro](https://neon.com/docs/ai-gateway/models/gemini-3-1-pro.md) | `gemini-3-1-pro` | text, image, video, audio, pdf | 1M | Feb 2026 | Yes | $2 | $12 | chat/completions · gemini | — | | [Gemini 3 Flash](https://neon.com/docs/ai-gateway/models/gemini-3-flash.md) | `gemini-3-flash` | text, image, video, audio, pdf | 1M | Dec 2025 | Yes | $0.50 | $3 | chat/completions · gemini | — | | [Gemma 3 12B](https://neon.com/docs/ai-gateway/models/gemma-3-12b.md) | `gemma-3-12b` | text, image | 131K | Mar 2025 | — | $0.15 | $0.50 | chat/completions | Open weights | #### Meta | Model | Model ID | Inputs | Context | Released | Reasoning | Input /M | Output /M | Endpoints | License | | ----------------------------------------------------------------------------------------------------- | ----------------------------- | ----------- | ------- | -------- | --------- | -------- | --------- | ---------------- | ------------ | | [Llama 4 Maverick](https://neon.com/docs/ai-gateway/models/llama-4-maverick.md) | `llama-4-maverick` | text, image | 1M | Apr 2025 | — | $0.50 | $1.50 | chat/completions | Open weights | | [Meta Llama 3.3 70B Instruct](https://neon.com/docs/ai-gateway/models/meta-llama-3-3-70b-instruct.md) | `meta-llama-3-3-70b-instruct` | text | 128K | Dec 2024 | — | $0.50 | $1.50 | chat/completions | Open weights | | [Meta Llama 3.1 8B Instruct](https://neon.com/docs/ai-gateway/models/meta-llama-3-1-8b-instruct.md) | `meta-llama-3-1-8b-instruct` | text | 131K | Jul 2024 | — | $0.15 | $0.45 | chat/completions | Open weights | #### Alibaba | Model | Model ID | Inputs | Context | Released | Reasoning | Input /M | Output /M | Endpoints | License | | --------------------------------------------------------------------------------------------- | ----------------------------- | ------ | ------- | -------- | --------- | -------- | --------- | ---------------- | ------------ | | [Qwen3.5 122B A10B](https://neon.com/docs/ai-gateway/models/qwen35-122b-a10b.md) | `qwen35-122b-a10b` | text | 262K | Feb 2026 | Yes | $0.22 | $2.20 | chat/completions | Open weights | | [Qwen3 Next Instruct](https://neon.com/docs/ai-gateway/models/qwen3-next-80b-a3b-instruct.md) | `qwen3-next-80b-a3b-instruct` | text | 131K | Sep 2025 | — | $0.15 | $1.20 | chat/completions | Open weights | #### Zhipu AI | Model | Model ID | Inputs | Context | Released | Reasoning | Input /M | Output /M | Endpoints | License | | ------------------------------------------------------------------------- | --------------- | ----------- | ------- | -------- | --------- | -------- | --------- | ---------------- | ------------ | | [GLM 5.3](https://neon.com/docs/ai-gateway/models/glm-5-3.md) | `glm-5-3` | text | 1M | Aug 2026 | Yes | $1.40 | $4.40 | chat/completions | Open weights | | [GLM 5.3 Flash](https://neon.com/docs/ai-gateway/models/glm-5-3-flash.md) | `glm-5-3-flash` | text, image | 1M | Aug 2026 | Yes | $0.15 | $0.50 | chat/completions | Open weights | | [GLM 5.2](https://neon.com/docs/ai-gateway/models/glm-5-2.md) | `glm-5-2` | text | 1M | Jun 2026 | Yes | $1.40 | $4.40 | chat/completions | Open weights | #### Moonshot AI | Model | Model ID | Inputs | Context | Released | Reasoning | Input /M | Output /M | Endpoints | License | | ------------------------------------------------------------------------- | --------------- | ------------------ | ------- | -------- | --------- | -------- | --------- | ---------------- | ------------ | | [Kimi K3.1 Pro](https://neon.com/docs/ai-gateway/models/kimi-k3-1-pro.md) | `kimi-k3-1-pro` | text, image | 1M | Nov 2026 | Yes | Free | Free | chat/completions | Open weights | | [Kimi K3](https://neon.com/docs/ai-gateway/models/kimi-k3.md) | `kimi-k3` | text, image, video | 1M | Jul 2026 | Yes | $3 | $15 | chat/completions | Open weights | #### xAI | Model | Model ID | Inputs | Context | Released | Reasoning | Input /M | Output /M | Endpoints | License | | --------------------------------------------------------------- | ---------- | ----------- | ------- | -------- | --------- | -------- | --------- | ----------------------------------- | ------- | | [Grok 4.7](https://neon.com/docs/ai-gateway/models/grok-4-7.md) | `grok-4-7` | text | 500K | Sep 2026 | Yes | $2.50 | $7.50 | chat/completions · openai/responses | — | | [Grok 4.6](https://neon.com/docs/ai-gateway/models/grok-4-6.md) | `grok-4-6` | text, image | 500K | Aug 2026 | Yes | $2 | $6 | chat/completions · openai/responses | — | #### DeepSeek | Model | Model ID | Inputs | Context | Released | Reasoning | Input /M | Output /M | Endpoints | License | | ------------------------------------------------------------------------------------- | --------------------- | ----------- | ------- | -------- | --------- | -------- | --------- | ---------------- | ------------ | | [DeepSeek V4.1 Flash](https://neon.com/docs/ai-gateway/models/deepseek-v4-1-flash.md) | `deepseek-v4-1-flash` | text, image | 128K | Sep 2026 | Yes | $0.30 | $1.20 | chat/completions | Open weights | Select a linked model for code examples matched to its measured AI Gateway capabilities. ### Image models These models support image generation through the Responses API (base URL `/openai/v1`): #### OpenAI | Model | Model ID | Inputs | Context | Released | Reasoning | Input /M | Output /M | Endpoints | License | | ------------------------------------------------------------------------- | --------------- | ---------------- | ------- | -------- | --------- | -------- | --------- | ----------------------------------- | ------- | | [GPT-6.1 Sol](https://neon.com/docs/ai-gateway/models/gpt-6-1-sol.md) | `gpt-6-1-sol` | text, image, pdf | 1.1M | Sep 2026 | Yes | $2 | $10 | chat/completions · openai/responses | — | | [GPT-6 Sol](https://neon.com/docs/ai-gateway/models/gpt-6-sol.md) | `gpt-6-sol` | text, image, pdf | 1.1M | Sep 2026 | Yes | $2 | $10 | chat/completions · openai/responses | — | | [GPT-6 Luna](https://neon.com/docs/ai-gateway/models/gpt-6-luna.md) | `gpt-6-luna` | text, image, pdf | 1.1M | Sep 2026 | Yes | $0.10 | $0.50 | chat/completions · openai/responses | — | | [GPT-6 Astra](https://neon.com/docs/ai-gateway/models/gpt-6-astra.md) | `gpt-6-astra` | text, image, pdf | 1.1M | Sep 2026 | Yes | $10 | $50 | chat/completions · openai/responses | — | | [GPT-5.6 Luna](https://neon.com/docs/ai-gateway/models/gpt-5-6-luna.md) | `gpt-5-6-luna` | text, image, pdf | 1.1M | Jul 2026 | Yes | $0.20 | $1.20 | chat/completions · openai/responses | — | | [GPT-5.6 Sol](https://neon.com/docs/ai-gateway/models/gpt-5-6-sol.md) | `gpt-5-6-sol` | text, image, pdf | 1.1M | Jul 2026 | Yes | $5 | $30 | chat/completions · openai/responses | — | | [GPT-5.6 Terra](https://neon.com/docs/ai-gateway/models/gpt-5-6-terra.md) | `gpt-5-6-terra` | text, image, pdf | 1.1M | Jul 2026 | Yes | $2 | $12 | chat/completions · openai/responses | — | | [GPT-5.5](https://neon.com/docs/ai-gateway/models/gpt-5-5.md) | `gpt-5-5` | text, image, pdf | 1.1M | Apr 2026 | Yes | $5 | $30 | chat/completions · openai/responses | — | | [GPT-5.5 Pro](https://neon.com/docs/ai-gateway/models/gpt-5-5-pro.md) | `gpt-5-5-pro` | text, image, pdf | 1.1M | Apr 2026 | Yes | $30 | $180 | openai/responses | — | | [GPT-5.4 Mini](https://neon.com/docs/ai-gateway/models/gpt-5-4-mini.md) | `gpt-5-4-mini` | text, image | 400K | Mar 2026 | Yes | $0.75 | $4.50 | chat/completions · openai/responses | — | | [GPT-5.4 Nano](https://neon.com/docs/ai-gateway/models/gpt-5-4-nano.md) | `gpt-5-4-nano` | text, image | 400K | Mar 2026 | Yes | $0.20 | $1.25 | chat/completions · openai/responses | — | | [GPT-5.4](https://neon.com/docs/ai-gateway/models/gpt-5-4.md) | `gpt-5-4` | text, image, pdf | 1.1M | Mar 2026 | Yes | $2.50 | $15 | chat/completions · openai/responses | — | | [GPT-5.3 Codex](https://neon.com/docs/ai-gateway/models/gpt-5-3-codex.md) | `gpt-5-3-codex` | text, image, pdf | 400K | Feb 2026 | Yes | $1.75 | $14 | openai/responses | — | | [GPT-5.2](https://neon.com/docs/ai-gateway/models/gpt-5-2.md) | `gpt-5-2` | text, image | 400K | Dec 2025 | Yes | $1.75 | $14 | chat/completions · openai/responses | — | | [GPT-5.1](https://neon.com/docs/ai-gateway/models/gpt-5-1.md) | `gpt-5-1` | text, image | 400K | Nov 2025 | Yes | $1.25 | $10 | chat/completions · openai/responses | — | | [GPT-5](https://neon.com/docs/ai-gateway/models/gpt-5.md) | `gpt-5` | text, image | 400K | Aug 2025 | Yes | $1.25 | $10 | chat/completions · openai/responses | — | | [GPT-5 Mini](https://neon.com/docs/ai-gateway/models/gpt-5-mini.md) | `gpt-5-mini` | text, image | 400K | Aug 2025 | Yes | $0.25 | $2 | chat/completions · openai/responses | — | | [GPT-5 Nano](https://neon.com/docs/ai-gateway/models/gpt-5-nano.md) | `gpt-5-nano` | text, image | 400K | Aug 2025 | Yes | $0.05 | $0.40 | chat/completions · openai/responses | — | Select a linked model for image-generation examples matched to that model. ### Embedding models These models return a fixed-length vector on `POST /v1/embeddings` rather than generating text — a different endpoint from every model above: | Model | Model ID | Lab | Dimensions | Released | Input /M | Endpoints | License | | --------------------------------------------------------------------------------------- | ---------------------- | ------- | ---------- | -------- | -------- | ---------- | ------------ | | [Qwen3 Embedding 0.6B](https://neon.com/docs/ai-gateway/models/qwen3-embedding-0-6b.md) | `qwen3-embedding-0-6b` | Alibaba | 1024 | Jun 2025 | $0.02 | embeddings | Open weights | | [GTE Large (En)](https://neon.com/docs/ai-gateway/models/gte-large-en.md) | `gte-large-en` | Alibaba | 1024 | Jul 2023 | $0.13 | embeddings | Open weights | | [BGE Large (En)](https://neon.com/docs/ai-gateway/models/bge-large-en.md) | `bge-large-en` | BAAI | 1024 | Sep 2023 | $0.10 | embeddings | Open weights | Select a linked model for embeddings-specific code examples. ### Decision models These System One models answer questions about a given state with a choice, a probability, or a score rather than generating text: | Model | Model ID | Lab | Context | Released | Input /M | License | | ------------------------------------------------------------------------------------- | ----------------------- | ----------- | ------- | -------- | -------- | ------------ | | [OpenJev (Qwen 3.5 4B)](https://neon.com/docs/ai-gateway/models/openjev-qwen35-4b.md) | `openjev-qwen35-4b` | Alibaba | 131K | Oct 2026 | $0.042 | Open weights | | [Jev 1.14](https://neon.com/docs/ai-gateway/models/typesafeai-jev-1-14-0.md) | `typesafeai-jev-1-14-0` | TypeSafe AI | 66K | Oct 2026 | $0.042 | — | Prices are provider list prices per million tokens. Inference is free during the private preview. Click a model for a copy-paste quickstart. For full request paths and when to prefer each endpoint, see [Which endpoint to use](https://neon.com/docs/ai-gateway/models#which-endpoint-to-use). For embedding models (dimensions, normalization, and choosing a distance operator), see [Embeddings](https://neon.com/docs/ai-gateway/embeddings). For decision models (question types and answer shapes), see [Decisions](https://neon.com/docs/ai-gateway/decisions). ## Get started - [Quickstart](https://neon.com/docs/ai-gateway/get-started): Get a credential and make your first inference request in minutes. - [Model reference](https://neon.com/docs/ai-gateway/models): Endpoints, model IDs, rate limits, pricing, and provider terms. - [Chat completions](https://neon.com/docs/ai-gateway/chat-completions): Use the OpenAI-compatible endpoint with any model in the catalog. - [Embeddings](https://neon.com/docs/ai-gateway/embeddings): Turn text into vectors for search with the OpenAI-compatible embeddings endpoint. - [Decisions](https://neon.com/docs/ai-gateway/decisions): Ask yes/no, choice, and score questions about text and get back probabilities. - [Authentication](https://neon.com/docs/ai-gateway/authentication): Understand how Neon credentials work with AI Gateway. ## Starter templates Browse working examples at [build-on-neon.vercel.app](https://build-on-neon.vercel.app/). Two templates use AI Gateway: **`ai-sdk`**: An image-generation agent that routes model calls through AI Gateway, stores results in Neon Object Storage, and writes metadata to Postgres on a Neon Function. ```bash neon bootstrap --template ai-sdk ``` **`mastra`**: A personal assistant that uses AI Gateway for LLM calls with Postgres-backed memory on a Neon Function. ```bash neon bootstrap --template mastra ``` --- [Document source](https://neon.com/docs/ai-gateway/prepaid-credits.md) --- > Summary: Learn how AI Gateway prepaid credits work, who can buy them, how to purchase credits, how to set up automatic top-up, how to check your balance, and how usage limits and metering affect access. # AI Gateway prepaid credits Buy credits, understand pricing and limits, and manage your balance for the Neon AI Gateway Last updated: 2026-11-04 The Neon AI Gateway is billed with **prepaid credits**. You buy credits up front, and AI Gateway usage draws down your balance. This page explains who can buy credits, how pricing and usage limits work, how to purchase or top up, and how to check your balance. **Note:** The AI Gateway is available on **every Neon plan**, including Free. On the Free plan, you add a payment card and buy credits without upgrading. Your organization stays on the Free plan. See [Neon plans](https://neon.com/docs/introduction/plans) and [About billing](https://neon.com/docs/introduction/about-billing). ## How credits and pricing work - **1 credit = $1 USD.** Credits are prepaid, purchased before use. - **Minimum purchase: $5.** - **Minimum balance: $2.** Once your balance drops below $2, new requests return HTTP 429 until you add credits. - **Credits expire 12 months after purchase.** - Your balance can go **below $2, or negative**. Usage is metered after a request is served, so a long or large request, or several running at once, can take the balance below $2 or below zero before new requests are blocked. Your balance **draws down as usage is metered**. Each request consumes credits based on its token usage, so your balance decreases as you send requests. For example, a small request might reduce a $25.00 balance to $24.99. ## Who can buy credits - Only **organization admins** can purchase credits. - The organization must be billed directly by payment card. On the Free plan, add a payment card first. Adding a card doesn't change your plan. - Members, editors, and viewers cannot purchase credits. - Sales-invoiced, marketplace, trial, sponsored, and shared-token accounts cannot purchase credits through this self-service flow. Contact your account team for assistance. ## Buy or top up credits Buying credits is a Neon Console flow: 1. In the Neon Console, select **Billing**. 2. Find the **AI gateway credits** card and select **Add credits**. On the Free plan with no payment card on file, the card shows **Add a card** instead. Select it, add your card, and then select **Add credits**. 3. Select a preset amount: **$5**, **$10**, **$25**, **$50**, or **$100**. You can also select **Other** to enter a custom amount. The default selection is $25, and the minimum purchase is $5. 4. Confirm the purchase. Neon applies a **one-time charge** to the payment card already on file for your organization. ![AI Gateway credits purchase modal with preset and custom amounts](https://neon.com/docs/ai-gateway/ai-gateway-add-credits-modal.png) Credits post to your balance promptly after the charge succeeds. The purchase appears in your credit history as **Manual purchase**, with the date and amount. **Important:** Only **one purchase can be open at a time** per account. You can't start a second purchase until the first completes. If an automatic top-up is in progress, a manual purchase fails with "Another credit purchase is in progress. Try again in a moment." **If a purchase fails.** If the payment card on file is declined, the purchase fails and no credits are added to your balance. Neon doesn't leave a payable invoice behind, and failed attempts don't appear in your credit history. Update your card in **Billing** and try again. ## View your balance and usage history In the Console, select **Billing** and find the **AI gateway credits** card. The card shows: - **Credits remaining**: your organization's current credit balance. - **Credits added in last 30 days**: a history panel that lists each entry's date, source, and amount, plus the total credits added during the period. Automatic top-ups are listed with the source **Auto-reload**. ![AI Gateway credits balance and credits added in the last 30 days](https://neon.com/docs/ai-gateway/ai-gateway-credits-balance.png) The balance is shown in **whole cents**, so small or occasional requests might not visibly change it even though their metered usage still draws down the balance. ## Usage limits AI Gateway usage is subject to **soft limits** that guard against runaway cost and abuse: - **Per-minute token limit.** A soft limit of **200,000 tokens per minute (TPM)** applies to input and output tokens separately, but this may vary by account. - **Daily spend cap.** A **$20 per day** limit applies to total usage, but this may vary by account. Short-window rate limits, the daily spend cap, and balance depletion are distinct: - **Short-window rate limits** return HTTP 429 with a `Retry-After` header that points to the start of the next minute. `x-ratelimit-*` headers, when present, come from the upstream provider, not from Neon's limits. - The **daily spend cap** limits how much you can spend in a single day. - **Balance depletion** happens when your prepaid credits run out. If you're blocked and need a limit raised, [contact Support](https://neon.com/docs/introduction/support). See [Rate limits](https://neon.com/docs/ai-gateway/models#rate-limits) for details. When you exceed a limit, the API returns **HTTP 429**: ```json { "error_code": "REQUEST_LIMIT_EXCEEDED", "message": "You've reached your AI Gateway daily spend limit. You can retry after it resets, or ask Neon support to raise it (we review all increases to prevent abuse): https://console.neon.tech/app/projects?modal=support" } ``` ## Model access Any account with prepaid credits can use every AI Gateway model. See [Model access](https://neon.com/docs/ai-gateway/models#model-access) for details. After you buy credits, locked models unlock once Neon confirms access. If a model still shows a padlock on the **AI Gateway** page, reload the page. See [Locked models in the Console](https://neon.com/docs/ai-gateway/troubleshooting#some-models-are-restricted-in-the-console). The model list is subject to change. See [Supported models](https://neon.com/docs/ai-gateway/models) for the current catalog. ## Automatic top-up Turn on **auto-reload** to keep your balance from running out. When your balance drops below a threshold you set, Neon buys a fixed amount of credits with the payment card on file, with no action needed from you. Auto-reload is available on paid plans only. It isn't available on the Free plan yet. Only organization admins can set it up, and the organization must be billed directly by payment card. To set up auto-reload: 1. In the Neon Console, select **Billing**. 2. On the **AI gateway credits** card, select **Auto-reload**. 3. Turn on **Enable auto-reload** and set: - **When balance drops below (USD)**: the threshold that triggers a top-up. It must be higher than the $2 minimum balance. The default is $10. - **Automatically purchase (USD)**: how many credits to buy each time. The amount must be at least the threshold and within the same range as a manual purchase. The default is $25. 4. Click **Save**. ![Auto-reload credits dialog with a $10 threshold and a $25 purchase amount](https://neon.com/docs/ai-gateway/ai-gateway-auto-reload-modal.png) You can also turn on auto-reload in the **Add credits** dialog when you buy credits. Neon saves those settings only if the purchase succeeds. The **Auto-reload** button shows **On** or **Off** so you can check its status at a glance. If your balance is already below the threshold when you turn on auto-reload, Neon tops it up right away. Neon turns auto-reload off when it can't complete a top-up, for example when your card is declined or a top-up keeps failing. It also turns off if your organization no longer qualifies, such as after a downgrade to Free or removing your payment card. When this happens, an alert on the **AI gateway credits** card and in the **Auto-reload** dialog explains why. To resume, fix the issue and turn auto-reload back on. ## Availability The AI Gateway is available in AWS US East (Ohio), US East (N. Virginia), Europe (Frankfurt), and Asia Pacific (Singapore) (more [regions](https://neon.com/docs/introduction/regions) to follow). **Note:** **IP Allow** and **Private Networking** do not cover AI Gateway traffic. ## If you downgrade to Free If your organization moves to the Free plan, your AI Gateway credits **remain on your account** and you can keep using them. Auto-reload turns off when you downgrade. ## Related - [AI Gateway overview](https://neon.com/docs/ai-gateway/overview) - [Supported models](https://neon.com/docs/ai-gateway/models) - [AI Gateway troubleshooting](https://neon.com/docs/ai-gateway/troubleshooting) - [About billing](https://neon.com/docs/introduction/about-billing) - [Manage billing](https://neon.com/docs/introduction/manage-billing) ## Frequently asked questions ### Who can use AI Gateway? Any Neon organization with prepaid credits, on any plan, including Free. On the Free plan, add a payment card to buy credits. You don't need to upgrade. Credits give you every model in the catalog. ### How much do AI Gateway credits cost? 1 credit equals $1 USD, with a $5 minimum purchase. You buy credits from the **Billing** page in the [Neon Console](https://console.neon.tech/app/billing). ### Can my credit balance go negative? Yes, by a small amount. Usage can exceed your remaining balance before it's detected, so a minimum balance of $2 applies to account for this. ### Can I top up credits automatically? Yes, on paid plans. Auto-reload isn't available on the Free plan yet. Organization admins can turn it on from the **AI gateway credits** card on the **Billing** page. When your balance drops below the threshold you set, Neon buys the amount you chose with the payment card on file. See [Automatic top-up](https://neon.com/docs/ai-gateway/prepaid-credits#automatic-top-up). ### Do credits expire? Credits are valid for 12 months from the date of purchase. ### What happens to my credits if I downgrade to Free? Your credits stay on your account, and you can keep using AI Gateway on the Free plan. Auto-reload turns off when you downgrade. ### What are the default usage limits? By default, each account has a soft limit of 200,000 tokens per minute (TPM), applied to input and output tokens separately, and a $20 per day spend cap, though both may vary by account. Both guard against runaway costs. If you're blocked and need a limit raised, [contact Support](https://neon.com/docs/introduction/support). See [Usage limits](https://neon.com/docs/ai-gateway/prepaid-credits#usage-limits) for details. ### What happens if I hit a usage limit? Requests are blocked once you reach your per-minute token limit or daily spend cap, and the gateway returns an `HTTP 429` response with error code `REQUEST_LIMIT_EXCEEDED`. See [Usage limits](https://neon.com/docs/ai-gateway/prepaid-credits#usage-limits) for details, or [Troubleshooting](https://neon.com/docs/ai-gateway/troubleshooting#429-account-quota-exceeded) if you hit it. --- [Document source](https://neon.com/docs/ai-gateway/troubleshooting.md) --- > Summary: Solutions for common errors when using Neon AI Gateway, including authentication failures, model errors, quota limits, and upstream issues. # AI Gateway troubleshooting Common errors and how to fix them Last updated: 2026-11-04 ## Authentication errors ### `401 invalid or missing credential` The bearer token is missing, malformed, or has been revoked. **Fix:** Check that `NEON_AI_GATEWAY_TOKEN` is set and contains the full `nt_live_...` token returned when you created the credential. If the credential was revoked, create a new one. See [Authentication](https://neon.com/docs/ai-gateway/authentication#creating-a-credential). ### `403 credential not authorized for ai gateway` The credential exists but lacks the `ai_gateway:invoke` scope. **Fix:** Create a new credential that includes `ai_gateway:invoke` in the `scopes` array. You can't add scopes to an existing credential. See [Authentication](https://neon.com/docs/ai-gateway/authentication#creating-a-credential). ### `403 credential not authorized for this branch` The credential was issued on a branch that is not an ancestor of the branch in the request hostname. **Fix:** Use a credential issued on the current branch or an ancestor branch. See [Authentication](https://neon.com/docs/ai-gateway/authentication#how-branch-binding-works) for how branch lineage works. ### `503 authorization temporarily unavailable` The credential store or branch resolver is temporarily unavailable. **Fix:** Retry the request. This is a transient infrastructure error, not a client error. --- ## Model errors ### `400 unknown model ""` The `model` field in the request body does not match any entry in the AI Gateway catalog. The error message includes the model ID you sent. **Fix:** Check the model ID against the [full model catalog](https://neon.com/docs/ai-gateway/models). Use the short form (e.g., `gpt-5-mini`) or the `databricks-` prefixed form (`databricks-gpt-5-mini`) — both are accepted. ### `400 model "" is not available on the endpoint` The model exists in the catalog but doesn't work with the endpoint you're calling. The error message names both the model and the endpoint dialect it was sent to (for example, `openai_responses`, `gemini_generate_content`, or `chat_completions`). **Fix:** Check which endpoint the model requires: - OpenAI codex models on `/v1/chat/completions` → use `/openai/v1/responses` - Google models on `/openai/v1/responses` → use `/gemini/v1beta/...` or `/v1/chat/completions` See [Which endpoint to use](https://neon.com/docs/ai-gateway/models#which-endpoint-to-use). ### `400 missing or invalid model` The request body does not contain a valid `model` field. **Fix:** Include `"model": ""` in the request body. ### Locked models in the Console On your project's **AI Gateway** page, a locked model shows a padlock. Hover over the padlock to see why the model is locked, along with a link to fix it: | Tooltip | What to do | | -------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | **Add a card to buy AI gateway credits for this model.** | Your organization is on the Free plan with no payment card on file. Select **Add a card**, add your card, then buy credits. You don't need to upgrade your plan. See [AI Gateway prepaid credits](https://neon.com/docs/ai-gateway/prepaid-credits#buy-or-top-up-credits). | | **AI Gateway credits are required to use this model.** | Select **Buy credits**. See [AI Gateway prepaid credits](https://neon.com/docs/ai-gateway/prepaid-credits). | | **A paid plan is required to use this model.** | Your organization can't buy credits on its current plan, for example because it's billed through the Vercel Marketplace. Select **Upgrade plan**. | | **Account verification is required to use this model.** | Neon checks your account after your first credit purchase. Wait a few minutes and reload the page. If the tooltip links to **Complete verification** or **Contact support for verification**, follow that link. | | **Your account has reached its daily AI Gateway spend limit.** | [Contact Support](https://neon.com/docs/introduction/support) to raise the limit. See [Usage limits](https://neon.com/docs/ai-gateway/prepaid-credits#usage-limits). | | **Your account is restricted from using this model.** | [Contact Support](https://neon.com/docs/introduction/support). | | **This model is not available to your account.** | [Contact Support](https://neon.com/docs/introduction/support). | Only organization admins can add a card or buy credits. After you buy credits, models unlock once Neon confirms access, usually within a few seconds. Reload the page if a model still shows as locked. --- ## Gemini-specific errors ### `404 unsupported gemini action` The action in the Gemini endpoint URL is unsupported. The AI Gateway supports Gemini `generateContent` and streaming `streamGenerateContent` calls. **Fix:** Use either `::generateContent` or `::streamGenerateContent`. Other actions (`countTokens`, etc.) are not available. ### `404 invalid gemini model path` The `{modelAction}` segment in the Gemini URL path is malformed. It must follow the format `:` where both parts are non-empty. **Fix:** Ensure the URL path contains exactly one colon separating the model ID and action, e.g. `gemini-3-flash:generateContent`. --- ## Workspace resolution errors ### `403` or `400`: `could not resolve workspace from host` The request host does not match the expected format or region. **Common causes:** - The host does not end with a trusted suffix (`.neon.tech` in production). Returns 403. - The host has no parseable AWS region label. Returns 400. - The region in the host has no configured workspace. Returns 404. **Fix:** Verify that you are using the correct AI Gateway host from the Neon Console or API. The host format for production is `-api.ai...aws.neon.tech`. Do not construct the host manually. --- ## Rate limiting and quota ### `429`: upstream provider rate limit The request hit the upstream Databricks/provider rate limit. **Fix:** Implement exponential backoff. The response includes a `Retry-After` header and provider-specific rate limit headers (`X-Ratelimit-*`). See [Rate limiting](https://neon.com/docs/ai-gateway/chat-completions#rate-limiting). ### `429`: account quota exceeded Your account's AI Gateway quota is blocked. This happens when you exceed a token-per-minute (TPM) rate limit or your account's daily spend limit, or when your prepaid credit balance drops below the $2 minimum. All three return `REQUEST_LIMIT_EXCEEDED`, and the message names the limit that was hit and how to recover. An account-wide TPM limit: ```json { "error_code": "REQUEST_LIMIT_EXCEEDED", "message": "You've exceeded your AI Gateway account input token limit ( input tokens per minute across all models). You can retry once the current minute resets, or ask Neon support to raise it (we review all increases to prevent abuse): https://console.neon.tech/app/projects?modal=support" } ``` A per-model TPM limit names the model instead. Only the `message` value changes: ```text You've exceeded your AI Gateway input token limit for model "" ( input tokens per minute). You can retry once the current minute resets, or ask Neon support to raise it (we review all increases to prevent abuse): https://console.neon.tech/app/projects?modal=support ``` Input and output tokens are limited separately. When the output limit is hit, the same messages say `output` instead of `input`. A daily spend limit: ```json { "error_code": "REQUEST_LIMIT_EXCEEDED", "message": "You've reached your AI Gateway daily spend limit. You can retry after it resets, or ask Neon support to raise it (we review all increases to prevent abuse): https://console.neon.tech/app/projects?modal=support" } ``` A credit balance below the minimum. The response includes a link to add credits: ```json { "error_code": "REQUEST_LIMIT_EXCEEDED", "message": "AI Gateway credit balance is below the required minimum. Add credits to continue. ", "unavailable_reason": "credits_required", "recovery_url": "" } ``` This block has no `Retry-After` header and doesn't clear on its own. [Buy credits](https://neon.com/docs/ai-gateway/prepaid-credits#buy-or-top-up-credits), or turn on [automatic top-up](https://neon.com/docs/ai-gateway/prepaid-credits#automatic-top-up) so it doesn't happen again. **Fix:** Check the `Retry-After` header. If present, the block is temporary and lifts at that time; retry with exponential backoff. If absent, the block lasts until it's resolved: for a low credit balance, add credits; for a limit, ask Support to raise it. See [Support](https://neon.com/docs/introduction/support) for your plan's support options and [Rate limits](https://neon.com/docs/ai-gateway/models#rate-limits) for current values. --- ## Upstream errors When the upstream model provider or Databricks returns an error, the AI Gateway replaces the upstream response body with its own `{"error_code","message"}` envelope and preserves the upstream status code. Upstream internal details, such as endpoints, workspace IDs, Unity Catalog objects, principals, and internal headers, are never exposed to the caller. The message identifies the condition: | Condition | Message | | ----------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | Endpoint disabled | `This model is temporarily disabled. Contact Neon support for help: https://console.neon.tech/app/projects?modal=support` | | Timeout | `The model took too long to respond. Reduce max_tokens or your input size, or use streaming.` | | Request too large | `ai gateway upstream rejected the request: body too large` | | Model unavailable | `ai gateway upstream model is not available. Contact Neon support` | | Access denied | `ai gateway upstream denied the request. Contact Neon support` | | Over capacity | `ai gateway upstream model is temporarily over capacity. Retry later` | | Upstream internal error | `ai gateway upstream model error. Retry later, or contact Neon support if it persists` | | Invalid request | `ai gateway upstream model rejected the request: ` (redacted to `...rejected the request as invalid` when the provider detail can't be shown safely) | | Unknown | `ai gateway upstream request failed. Contact Neon support if it persists` | **Fix:** Follow the guidance in the message. Retry transient conditions (over capacity, upstream internal error) with exponential backoff, respecting any `Retry-After` header. Don't retry a timeout as is: the gateway sends `X-Should-Retry: false` so the OpenAI and Anthropic SDKs skip their automatic retry, because each retry runs the whole slow generation again. Reduce `max_tokens` or the input size, or use streaming. If an error persists, check the [Neon status page](https://neonstatus.com). For paid plan support options, see [Support](https://neon.com/docs/introduction/support). --- ## Error response formats Errors the gateway generates itself (authentication, model validation, workspace resolution) use the standard OpenAI error envelope: ```json { "error": { "message": "unknown model \"\"" } } ``` Quota blocks and all upstream (non-2xx) errors use a flat envelope, with the upstream status code preserved: ```json { "error_code": "REQUEST_LIMIT_EXCEEDED", "message": "You've reached your AI Gateway daily spend limit. You can retry after it resets, or ask Neon support to raise it (we review all increases to prevent abuse): https://console.neon.tech/app/projects?modal=support" } ``` --- [Document source](https://neon.com/docs/ai/agent-setup.md) --- > Summary: Set up Neon in an AI coding agent (Claude Code, Cursor, Codex, VS Code with GitHub Copilot, and more) or a chat app (ChatGPT, Claude.ai, Grok Bot). Copy the Set up agent prompt so your agent installs the Neon CLI and the Neon plugin (agent skills plus the Neon MCP Server), or run `npx neon@latest init` in your project. Per-agent pages cover chat apps, manual installs, and MCP-only setup. # Set up your AI agent for Neon Connect Neon to your coding agent or chat app [View prompt](https://neon.com/prompts/agent-setup-landing.md) That's all most coding agents need: your agent installs the Neon CLI, signs you in, and installs the Neon plugin. Restart it afterward. Prefer a terminal? Run [`npx neon@latest init`](https://neon.com/docs/cli/init) instead. ## Set up a specific agent Use these pages to connect a chat app like ChatGPT or Claude.ai, to run the install yourself, or for MCP-only and API key setup. - [Claude Code](https://neon.com/docs/ai/agent-setup/claude-code) - [Cursor](https://neon.com/docs/ai/agent-setup/cursor) - [Codex](https://neon.com/docs/ai/agent-setup/codex) - [VS Code and GitHub Copilot](https://neon.com/docs/ai/agent-setup/vscode) - [ChatGPT](https://neon.com/docs/ai/agent-setup/chatgpt) - [Claude.ai and Claude Desktop](https://neon.com/docs/ai/agent-setup/claude-ai) - [Grok Bot](https://neon.com/docs/ai/agent-setup/grok-bot) - [Zed, Devin, Kiro, and more](https://neon.com/docs/ai/connect-mcp-clients-to-neon) ## What gets installed The Neon plugin bundles seven Neon [agent skills](https://neon.com/docs/ai/agent-skills): `neon`, `neon-postgres`, `neon-auth`, `neon-functions`, `neon-object-storage`, `neon-ai-gateway`, and `neon-realtime`. It also includes the [Neon MCP Server](https://neon.com/docs/ai/neon-mcp-server), which your agent signs in to with OAuth the first time it uses it. ## Building agents on Neon? - [Agent plan](https://neon.com/docs/introduction/agent-plan): A pricing tier for platforms that provision databases for their users - [AI agent integration](https://neon.com/docs/guides/ai-agent-integration): Provision per-tenant databases and versions with the Neon API - [Database versioning](https://neon.com/docs/ai/ai-database-versioning): Snapshot APIs for codegen and agent platforms - [Claimable Neon](https://neon.com/docs/reference/claimable-neon): Provision a project now; your user claims it later --- [Document source](https://neon.com/docs/ai/agent-setup/chatgpt.md) --- > Summary: Add the Neon plugin to ChatGPT from Settings > Plugins > Browse directory. The plugin includes Neon's agent skills and the Neon app, which connects ChatGPT to your Neon account through the Neon MCP Server with OAuth. # Set up Neon in ChatGPT Add the Neon plugin from the ChatGPT plugins directory The Neon plugin for ChatGPT includes Neon's agent skills and the **Neon** app. The app connects ChatGPT to your Neon account through the [Neon MCP Server](https://neon.com/docs/ai/neon-mcp-server). With the plugin, ChatGPT can manage your projects, branches, and SQL in natural language. **Important: Security** The Neon MCP Server is intended for **development and testing only**. Always review LLM-requested actions before execution. See [MCP security guidance](https://neon.com/docs/ai/neon-mcp-server#mcp-security-guidance). ## Add the Neon plugin 1. In ChatGPT, go to **Settings** → **Plugins** → **Browse directory**. 2. Search for **Neon** and click **+ Install plugin**. 3. Sign in to Neon when prompted. During authorization, choose read-only or full access. Then ask in natural language, for example: ```text List my Neon projects ``` See [Available tools](https://neon.com/docs/ai/neon-mcp-server#available-tools) for everything the Neon app can do. ## Use Neon with dots Dots, ChatGPT's always-on agents, use the same plugin settings as your ChatGPT account. After you install the Neon plugin, connect it to a dot from **Customize** → **Plugins** in the dot's profile. See [Getting started with your dot](https://help.openai.com/en/articles/20001530-getting-started-with-your-dot). To build an app on Neon with OpenAI's coding agent, see [Set up Neon in Codex](https://neon.com/docs/ai/agent-setup/codex). --- [Document source](https://neon.com/docs/ai/agent-setup/claude-ai.md) --- > Summary: Connect Claude.ai or Claude Desktop to Neon by adding the official Neon connector (Settings > Connectors > Browse connectors) and signing in with OAuth. Claude Desktop can also load the Neon MCP Server from claude_desktop_config.json through the mcp-remote bridge. # Set up Neon in Claude.ai and Claude Desktop Add Neon as a Claude connector, or configure the Neon MCP Server in Claude Desktop Claude.ai and Claude Desktop connect to Neon through the hosted [Neon MCP Server](https://neon.com/docs/ai/neon-mcp-server), which is an official Claude connector. Add the connector once and sign in, and Claude can manage your projects, branches, and SQL in natural language. Using Claude Code? See [Set up Neon in Claude Code](https://neon.com/docs/ai/agent-setup/claude-code) instead. **Important: Security** The Neon MCP Server is intended for **development and testing only**. Always review LLM-requested actions before execution. See [MCP security guidance](https://neon.com/docs/ai/neon-mcp-server#mcp-security-guidance). ## Add the Neon connector You don't need a custom connector URL. In [Claude.ai](https://claude.ai) or Claude Desktop: 1. Open **Settings** from your profile menu. 2. Select **Connectors** (sometimes shown under **Customize > Connectors**). 3. Click **Browse connectors** (top-right of that page), find **Neon**, and add it. 4. Authorize access to your Neon account. Then ask in natural language, for example: ```text List my Neon projects ``` See [Available tools](https://neon.com/docs/ai/neon-mcp-server#available-tools) for everything the server can do. ## Use a config file instead Claude Desktop's `claude_desktop_config.json` only supports local (stdio) servers. If you manage Claude Desktop with that file, add the [`mcp-remote` bridge config](https://neon.com/docs/ai/neon-mcp-server#deprecated-stdio). Open the file from **Settings** → **Developer** → **Edit Config**, then restart Claude Desktop. For a walkthrough, see [Get started with Claude Desktop and Neon MCP Server](https://neon.com/guides/neon-mcp-server). --- [Document source](https://neon.com/docs/ai/agent-setup/claude-code.md) --- > Summary: Install the Neon plugin in Claude Code with `npx neon@latest plugins --agent claude-code --global`, or from Neon's plugin marketplace with `/plugin install neon-postgres@neon`. The plugin bundles seven Neon agent skills and the Neon MCP Server. Also covers the official Claude marketplace listing, MCP-only setup with OAuth or an API key, and skills-only setup. # Set up Neon in Claude Code Install the Neon plugin for agent skills and the Neon MCP Server The Neon plugin gives [Claude Code](https://docs.anthropic.com/en/docs/claude-code) Neon's agent skills, so it knows how to build on Neon, and the Neon MCP Server, so it can act on your Neon account. ## Install the plugin Run: ```bash npx neon@latest plugins --agent claude-code ``` This installs the plugin at user level, for all your projects. See [`neon plugins`](https://neon.com/docs/cli/plugins) for all options. Then run `/reload-plugins` in Claude Code, or start a new session. Claude Code asks you to sign in to Neon with OAuth the first time it uses an MCP tool. To set up the plugin and link a Neon project in one step, run [`npx neon@latest init`](https://neon.com/docs/cli/init) instead. ## Check that it works Ask Claude Code: ```text Which Neon skills do you have access to? ``` You should see the Neon skills listed. Then try: ```text Get started with Neon ``` ## Other ways to install ### From a plugin marketplace In a Claude Code session, install the plugin from Neon's marketplace. This is the same plugin `neon plugins` installs: ```text /plugin marketplace add neondatabase/agent-skills /plugin install neon-postgres@neon ``` It's also in Anthropic's official marketplace as `neon@claude-plugins-official`. That listing is pinned to a specific commit and updated separately, so it can lag behind. Install from one marketplace only. ### MCP Server only To add only the Neon MCP Server, without skills, use OAuth: ```bash claude mcp add --transport http neon https://mcp.neon.tech/mcp ``` Start a new `claude` session, or run `/mcp`, to sign in. For a [Neon API key](https://neon.com/docs/manage/api-keys) instead, run [`npx neon@latest mcp --agent claude-code`](https://neon.com/docs/cli/mcp), which mints one. The [config generator](https://neon.com/docs/ai/neon-mcp-server#config-generator) also builds an API key config, with read-only mode and other access controls. ### Skills only ```bash npx neon@latest skills --agent claude-code ``` For an end-to-end example, see [Get started with Claude Code and Neon MCP Server](https://neon.com/guides/claude-code-mcp-neon). If something isn't working, see [MCP troubleshooting](https://neon.com/docs/ai/neon-mcp-server#troubleshooting). --- [Document source](https://neon.com/docs/ai/agent-setup/codex.md) --- > Summary: Install the Neon plugin in OpenAI Codex from the plugin directory (`/plugins` in the Codex CLI, or Plugins in the Codex app), or run `npx neon@latest plugins --agent codex`. The plugin bundles the Neon MCP Server, shown in Codex as the Neon app, and Neon's agent skills. Also covers MCP-only setup in .codex/config.toml and skills-only setup. # Set up Neon in Codex Install the Neon plugin in the Codex CLI or the Codex app The Neon plugin gives [OpenAI Codex](https://developers.openai.com/codex/) Neon's [agent skills](https://developers.openai.com/codex/skills/), so it knows how to build on Neon. It also adds the Neon MCP Server, so Codex can act on your Neon account. In Codex, the MCP Server appears as the **Neon** app. ## Install the plugin **Codex CLI** In the Codex CLI, run `/plugins`, open **Neon**, and choose **Add to Codex**. To install the Codex CLI first, see [Codex CLI](https://developers.openai.com/codex/cli). **Codex app** In the Codex app, open **Plugins**, search for **Neon**, and choose **Add to Codex**. **Neon CLI** Install the plugin: ```bash npx neon@latest plugins --agent codex ``` If Codex asks you to connect Neon, follow the prompts. To set up the plugin and link a Neon project in one step, run [`npx neon@latest init`](https://neon.com/docs/cli/init) instead. ## Check that it works Start a new thread, or type `@` to pick the **Neon** plugin, and ask: ```text Use Neon to create a new Postgres database for my project and help me connect to it. ``` ## Other ways to install ### MCP Server only ```bash npx add-mcp https://mcp.neon.tech/mcp -a codex ``` This adds a `neon` entry to `.codex/config.toml` (add `-g` to write `~/.codex/config.toml` instead). Restart Codex. If Codex doesn't prompt you to sign in, run `codex mcp login neon` and click **Authorize** in the OAuth window. Or run [`npx neon@latest mcp --agent codex`](https://neon.com/docs/cli/mcp). For read-only mode and other access controls, see the [Neon MCP Server](https://neon.com/docs/ai/neon-mcp-server) reference. ### Skills only ```bash npx neon@latest skills --agent codex ``` For a schema refactoring walkthrough, see [Safe AI-powered schema refactoring with OpenAI Codex and Neon](https://neon.com/guides/openai-codex-neon-mcp). If something isn't working, see [MCP troubleshooting](https://neon.com/docs/ai/neon-mcp-server#troubleshooting). --- [Document source](https://neon.com/docs/ai/agent-setup/cursor.md) --- > Summary: Install the Neon plugin in Cursor with `/add-plugin neon-postgres` in Cursor chat, from the Cursor marketplace, or with `npx neon@latest plugins --agent cursor --global`. The plugin bundles seven Neon agent skills and the Neon MCP Server. Also covers MCP-only setup (one-click install, OAuth, or an API key) and skills-only setup. # Set up Neon in Cursor Install the Neon plugin for agent skills and the Neon MCP Server The Neon plugin gives Cursor Neon's agent skills, so it knows how to build on Neon, and the Neon MCP Server, so it can act on your Neon account. ## Install the plugin In Cursor chat, run: ```text /add-plugin neon-postgres ``` Or install it from [cursor.com/marketplace/neon](https://cursor.com/marketplace/neon), or from a terminal: ```bash npx neon@latest plugins --agent cursor ``` When Cursor first uses a Neon MCP tool, follow the prompts to sign in to Neon. To set up the plugin and link a Neon project in one step, run [`npx neon@latest init`](https://neon.com/docs/cli/init) instead. ## Check that it works Ask Cursor: ```text Get started with Neon ``` ## Other ways to install ### MCP Server only [https://cursor.com/en-US/install-mcp?name=Neon&config=eyJ1cmwiOiJodHRwczovL21jcC5uZW9uLnRlY2gvbWNwIn0%3D](https://cursor.com/en-US/install-mcp?name=Neon\&config=eyJ1cmwiOiJodHRwczovL21jcC5uZW9uLnRlY2gvbWNwIn0%3D) Click the button to add the Neon MCP Server with OAuth. For a [Neon API key](https://neon.com/docs/manage/api-keys) instead, run [`npx neon@latest mcp --agent cursor`](https://neon.com/docs/cli/mcp), which mints one. The [config generator](https://neon.com/docs/ai/neon-mcp-server#config-generator) also builds an API key config, with read-only mode and other access controls. ### Skills only ```bash npx neon@latest skills --agent cursor ``` For an end-to-end example, see [Get started with Cursor and the Neon MCP Server](https://neon.com/guides/cursor-mcp-neon). If something isn't working, see [MCP troubleshooting](https://neon.com/docs/ai/neon-mcp-server#troubleshooting). --- [Document source](https://neon.com/docs/ai/agent-setup/grok-bot.md) --- > Summary: Connect Neon to Grok Bot so you can create projects, work with branches, and run SQL from chat. # Set up Neon in Grok Bot Add the Neon plugin to Grok Bot to work with projects, branches, and SQL from chat Last updated: 2026-11-05 The Neon plugin for Grok Bot connects your Neon account. After you authorize it, you can create projects, work with branches, and run SQL without leaving Grok Bot. ## Install the plugin [Add the Neon plugin](https://neon.com/docs/ai/agent-setup/grokbot://app/v1/plugin/add?id=669) in Grok Bot. The link opens the Neon Postgres plugin page. If the link doesn't open Grok Bot, install from the plugins directory: 1. Launch Grok Bot. 2. Select **Plugins** in the sidebar. 3. Enter `neon` in the search field. 4. Select **Add** next to **Neon Postgres**. ![Plugins directory in Grok Bot, searching for Neon](https://neon.com/docs/ai/grok_bot_plugins_search.png) ## Ask for the Neon connector You can skip the plugins directory. In a Grok Bot chat, ask it to connect Neon: ```text Can you connect Neon? ``` The bot finds the Neon Postgres plugin and asks you to confirm. Then it shows a connect card in the chat. Authorize Neon in the browser when that card appears. ## Connect your Neon account After you add the plugin, Grok Bot asks you to authorize Neon in the browser. The plugin page then shows the default account as **Connected**. To connect another Neon account, add it from the plugin page and authorize it the same way. ![Neon Postgres plugin in Grok Bot, with the default account Connected](https://neon.com/docs/ai/grok_bot_plugin.png) ## Use Neon in Grok Bot Once it's connected, you can ask a bot to: - Create a project and get a connection string for your app - Create an isolated branch to test a migration - List projects and see which databases are unused - Create a routine that summarizes database usage - Coordinate a branch handoff between bots ![Grok Bot using the Neon plugin to list organizations](https://neon.com/docs/ai/grok_bot_chat.png) For example: ```text Create a Neon project for this application and help me connect to it. ``` To use Neon from a coding agent instead, see [Set up your AI agent](https://neon.com/docs/ai/agent-setup). --- [Document source](https://neon.com/docs/ai/agent-setup/vscode.md) --- > Summary: Set up Neon for GitHub Copilot in VS Code and the GitHub Copilot CLI. Install the Neon plugin at user level with `npx neon@latest plugins --agent vscode --global`, or add only the Neon MCP Server to .vscode/mcp.json with OAuth or an API key. Also covers the Neon VS Code extension, which configures the MCP Server on sign-in, and the Neon Migration Specialist and Neon Performance Analyzer custom agents for Copilot. # Set up Neon in VS Code and GitHub Copilot Install the Neon plugin, the Neon MCP Server, or Neon's custom agents for GitHub Copilot GitHub Copilot in VS Code gets Neon through the Neon plugin, which bundles Neon's agent skills and the Neon MCP Server. To use MCP servers in VS Code, you need the [GitHub Copilot](https://marketplace.visualstudio.com/items?itemName=GitHub.copilot) and [GitHub Copilot Chat](https://marketplace.visualstudio.com/items?itemName=GitHub.copilot-chat) extensions. ## Install the plugin Run: ```bash npx neon@latest plugins --agent vscode ``` The GitHub Copilot CLI uses the same plugin target (`github-copilot`), so `--agent github-copilot-cli` installs to the same place. [`npx neon@latest init`](https://neon.com/docs/cli/init) sets up VS Code with the skills and MCP Server installed separately (not the plugin) and links a Neon project. ## Check that it works Open GitHub Copilot Chat, [switch to Agent mode](https://code.visualstudio.com/docs/copilot/chat/chat-agent-mode), and ask: ```text Get started with Neon ``` ## Other ways to install ### MCP Server only ```bash npx add-mcp https://mcp.neon.tech/mcp -a vscode ``` This writes `.vscode/mcp.json` in your project (`-g` writes your user-level `mcp.json`). Restart VS Code or enable the server in settings, and click **Authorize** when the OAuth window opens. Or run [`npx neon@latest mcp --agent vscode`](https://neon.com/docs/cli/mcp). To configure it by hand with a [Neon API key](https://neon.com/docs/manage/api-keys), add this to `.vscode/mcp.json`: ```json { "servers": { "neon": { "type": "http", "url": "https://mcp.neon.tech/mcp", "headers": { "Authorization": "Bearer " } } } } ``` For read-only mode and other access controls, see the [Neon MCP Server](https://neon.com/docs/ai/neon-mcp-server) reference. ### Skills only ```bash npx neon@latest skills --agent vscode ``` ### Neon VS Code extension The [Neon VS Code extension](https://neon.com/docs/local/vscode-extension) lets you browse projects, branches, and tables in the editor. When you sign in, it also configures the Neon MCP Server. ## Neon custom agents for GitHub Copilot Neon publishes two custom agents for GitHub Copilot in the [awesome-copilot](https://github.com/github/awesome-copilot) repository. Both work on temporary branches (default TTL of 4 hours), away from your main branch: - The [Neon Migration Specialist](https://github.com/github/awesome-copilot/blob/main/agents/neon-migration-specialist.agent.md) tests a migration on a temporary branch, then opens a PR with the migration files for you or your CI/CD to apply. It works with your ORM's migration system (Prisma, Drizzle, SQLAlchemy, Django, Rails, and more) and never runs migrations on your main branch. - The [Neon Performance Analyzer](https://github.com/github/awesome-copilot/blob/main/agents/neon-optimization-analyzer.agent.md) finds slow queries with `pg_stat_statements` and `EXPLAIN`, tests indexes and query rewrites on a temporary branch, and opens a PR with before and after metrics. Both agents call the Neon API directly, so they need a [Neon API key](https://console.neon.tech/app/settings#api-keys) and a project ID or connection string. They ask for these if you haven't provided them. To install an agent, use its **Install in VS Code** button in the [awesome-copilot custom agents list](https://github.com/github/awesome-copilot/blob/main/docs/README.agents.md), or add its `.agent.md` file to your repository's `.github/agents/` directory. Then mention it in GitHub Copilot Chat: ```text @neon-migration-specialist Add a new email column to my users table ``` --- [Document source](https://neon.com/docs/ai/agent-skills.md) --- > Summary: Agent Skills are structured context files (SKILL.md) that give AI coding assistants accurate knowledge of Neon's cloud backend primitives, APIs, SDKs, and best practices. Install them when using Cursor, Claude Code, OpenAI Codex, or any Agent Skills-compatible tool. Skills cover Postgres, Managed Better Auth, Neon Functions, Object Storage, AI Gateway, branching workflows, and more. Install them with `neon skills`, `npx skills add neondatabase/agent-skills -y`, `neon init`, or the Neon plugin, at project or user level. # Agent Skills Teach your AI coding assistant how to work with Neon Last updated: 2026-11-05 Agent Skills provide your AI coding assistant with structured context about Neon's platform, APIs, and best practices. With skills installed, your assistant produces more accurate code and avoids common mistakes when working with Neon, from Postgres and Auth to [Neon Functions](https://neon.com/docs/compute/functions/overview), [Object Storage](https://neon.com/docs/storage/overview), and the [AI Gateway](https://neon.com/docs/ai-gateway/overview). [Watch on YouTube](https://youtube.com/watch?v=NN251KTjAo8) ## Install There are several ways to install Neon skills depending on your editor and workflow. ### neon skills The [Neon CLI](https://neon.com/docs/cli) installs skills interactively: ```bash neon skills ``` It pre-selects your detected agents, lets you pick which skills to add, and confirms before writing. Pass `-s ` and `--agent ` to skip the prompts, `--global` to install user-level, and run `neon skills update` to refresh installed skills. To see which installed skills have updates, run `neon skills status`. Other `neon` commands also warn you once a day when a skill is out of date. Both cover skills installed with `neon skills` or `npx skills add`, not plugins. See the [`neon skills` reference](https://neon.com/docs/cli/skills) for all options. ### npx skills For any AI tool that supports the [Agent Skills](https://agentskills.io) format, install skills from the [Agent Skills repository](https://github.com/neondatabase/agent-skills): ```bash npx skills add neondatabase/agent-skills -y ``` This installs **all** skills in the repository. To install a specific skill instead, pass the `-s` flag: ```bash npx skills add neondatabase/agent-skills -s neon -y ``` Useful flags: - `-y` skips the interactive prompt and installs immediately - `-s` selects one or more skills (repeat the flag for multiple skills) - `-g` installs globally instead of at the project level (see [Project vs. user level](https://neon.com/docs/ai/agent-skills#project-level-vs-global-install)) ### Plugins The Neon plugin bundles seven Neon [agent skills](https://neon.com/docs/ai/agent-skills): `neon`, `neon-postgres`, `neon-auth`, `neon-functions`, `neon-object-storage`, `neon-ai-gateway`, and `neon-realtime`. It also includes the [Neon MCP Server](https://neon.com/docs/ai/neon-mcp-server), which your agent signs in to with OAuth the first time it uses it. For most coding agents, the plugin is the easier option. To install it, see [Set up your AI agent](https://neon.com/docs/ai/agent-setup). ### neon init [`npx neon@latest init`](https://neon.com/docs/cli/init) installs the plugin, or skills and the MCP Server, for your coding agents and links a Neon project. ## Available skills Skills are grouped by area. Each skill is a `SKILL.md` entry point that your agent reads and invokes when relevant. Browse and install individual skills on [skills.sh](https://skills.sh/neondatabase/agent-skills). Install any of them by name with [`neon skills`](https://neon.com/docs/cli/skills) (`-s` is repeatable): ```bash neon skills -s neon -s neon-postgres ``` Without the Neon CLI, run `npx skills add neondatabase/agent-skills -s neon -s neon-postgres` instead. ### Core Start here for platform overview and Postgres development. | Skill | Description | | ---------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------- | | [`neon`](https://skills.sh/neondatabase/agent-skills/neon) | Platform overview for apps and agents: Postgres, Auth, Data API, Functions, Storage, and AI Gateway, including Claimable Neon when there is no account yet | | [`neon-postgres`](https://skills.sh/neondatabase/agent-skills/neon-postgres) | Full index of Neon Serverless Postgres documentation and best practices, including branching workflows and egress optimization | ### Neon Platform Use Neon services beyond core Postgres. **Functions**, **Object Storage**, **AI Gateway**, and **Realtime** are available in AWS US East (Ohio), US East (N. Virginia), Europe (Frankfurt), and Asia Pacific (Singapore), with more regions coming. See the [backend overview](https://neon.com/docs/get-started/backend-overview) for details. | Skill | Description | Docs | | ---------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------ | | [`neon-functions`](https://skills.sh/neondatabase/agent-skills/neon-functions) | Long-running serverless Node.js HTTP functions on your branch, with `DATABASE_URL` injected automatically | [Neon Functions](https://neon.com/docs/compute/functions/overview) | | [`neon-object-storage`](https://skills.sh/neondatabase/agent-skills/neon-object-storage) | S3-compatible object storage that branches with your project | [Object Storage](https://neon.com/docs/storage/overview) | | [`neon-ai-gateway`](https://skills.sh/neondatabase/agent-skills/neon-ai-gateway) | One API and credential for frontier and open-source LLMs; compatible with OpenAI, Anthropic, and Vercel AI SDKs | [AI Gateway](https://neon.com/docs/ai-gateway/overview) | | [`neon-auth`](https://skills.sh/neondatabase/agent-skills/neon-auth) | Add authentication with Managed Better Auth: sign-up, sign-in, OAuth, magic links, OTP, passkeys, and organizations | [Managed Better Auth](https://neon.com/docs/auth/overview) | | [`neon-realtime`](https://skills.sh/neondatabase/agent-skills/neon-realtime) | Live SQL queries and reactivity primitives, so app UI and agent state update as rows change | [Realtime](https://neon.com/docs/realtime/overview) | ### Agent platforms For codegen tools and multi-tenant products that provision Neon for their users, see the companion skill in [neondatabase/neon-for-agent-platforms](https://github.com/neondatabase/neon-for-agent-platforms) (`neon-postgres-agent-platforms` on [skills.sh](https://skills.sh/neondatabase/neon-for-agent-platforms/neon-postgres-agent-platforms)). ## Project vs. user level Project-level installs live in your project directory and can be committed with it. User-level (global) installs apply across all your projects. Each install method has its own default: | How you install | Where it goes | | ----------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | [Set up agent prompt](https://neon.com/docs/ai/agent-setup) | User level | | `neon init` (recommended setup) | User level, for each detected agent. With no agent detected, skills go in the current directory. [Custom setup](https://neon.com/docs/cli/init#recommended-and-custom-setup) can write to the project | | [`neon plugins`](https://neon.com/docs/cli/plugins) | User level | | [`neon skills`](https://neon.com/docs/cli/skills) | Project by default; `--global` for user level | | `npx skills add` | Project by default; `-g` for user level | | [`neon mcp`](https://neon.com/docs/cli/mcp) | Asks; `--project` for the project, `-y` for user level | ## What's covered With the full skill set installed, your assistant can guide you across Neon: **Postgres and platform basics (`neon`, `neon-postgres`)** - **Getting started** with Neon, including project setup and key features (branching, autoscaling, scale-to-zero, instant restore, read replicas) - **Connections**, including the serverless driver, connection pooling, and connection strings - **Authentication** with Managed Better Auth - **Data API** via `@neon/neon-js` - **Platform APIs and SDKs**, including the REST API, TypeScript SDK, and Python SDK - **Developer tools**, including the CLI, VS Code extension, and MCP server **Database workflows** - **Disposable projects** via [Claimable Neon](https://neon.com/claimable-neon), for agents and tests - **Branch types and workflows** for migrations, schema-only branches, and reset-from-parent - **Egress optimization** for high transfer costs and query anti-patterns **Platform services** - **Neon Functions**: declare, deploy, and connect long-running compute next to your database - **Object Storage**: S3-compatible storage that branches with your data - **AI Gateway**: model routing, logging, and cost controls with a single Neon credential For example, ask your assistant to "set up Managed Better Auth in my Next.js app" and it will provide the correct imports, configuration, and middleware setup. Or ask it to "add an AI Gateway route in my `neon.ts` file" and it will follow the correct constraints and SDK patterns. ## Example prompts ``` Get started with Neon ``` ``` Recommend a connection method for this project ``` ``` Set up Drizzle ORM with Neon ``` ``` Set up Managed Better Auth for my Next.js app ``` ``` Create a Neon branch for this feature ``` ``` Give me a quick temporary Postgres database ``` ``` Why is my Neon bill so high? ``` ``` Add a serverless function to my Neon branch ``` ``` Set up S3-compatible storage in neon.ts ``` ``` Route LLM calls through the Neon AI Gateway ``` ## How it works Your AI assistant reads the `SKILL.md` file to understand what Neon guidance is available. When you ask about a specific topic, the skill fetches the relevant documentation from online, so your assistant always has up-to-date context without bundling everything locally. For the complete source, see the [Agent Skills repository](https://github.com/neondatabase/agent-skills). --- [Document source](https://neon.com/docs/ai/ai-azure-notebooks.md) --- > Summary: Azure Data Studio Notebooks support Jupyter-style Python notebooks that connect to a Lakebase Postgres database and run pgvector similarity search queries using the psycopg driver. Use this guide when you want to combine SQL, Python, and markdown in a single interactive document to prototype vector search without leaving Azure Data Studio. The walkthrough covers installing psycopg, enabling the pgvector extension with CREATE EXTENSION, inserting 3-dimensional vector embeddings, and querying nearest neighbors with the <-> distance operator. # Azure Data Studio Notebooks Use Azure Data Studio Notebooks with Neon for vector similarity search Last updated: 2026-09-16 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](https://neon.com/docs/manage/databases#create-a-database). ## Retrieve your Neon database connection string Click **Connect** in the Console nav to open the **Connect to your branch** modal, and select a branch, a user, and the database you want to connect to. A connection string is constructed for you. ![Connection modal](https://neon.com/docs/connect/connect_to_branch_modal.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 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 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 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](https://neon.com/docs/extensions/pgvector). --- [Document source](https://neon.com/docs/ai/ai-concepts.md) --- > Summary: Embeddings are floating-point vectors that encode semantic meaning from unstructured data, enabling similarity search by computing vector distance in Postgres. Read this page to understand how embeddings work before building AI features such as semantic search, recommendations, or anomaly detection on Neon. Topics include distance metrics (Euclidean, Manhattan, cosine), generating embeddings with the Neon AI Gateway or OpenAI, storing vectors with the pgvector extension, and searching them at scale with Lakebase Search. # AI Concepts Learn how embeddings are used to build AI applications Last updated: 2026-10-23 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? Embeddings transform unstructured data into a structured format that's easier to analyze and retrieve. They're 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]. Embeddings let you measure similarity between pieces of text. By calculating the distance between two embeddings, you can assess how related they are — the smaller the distance, the greater the similarity. 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. Applying this process, sentences 1 and 2 should come out as most similar (both involve jumping cattle). ## Vector similarity search Transforming data into embeddings and computing similarities between items is called 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 embeddings API, such as the [Neon AI Gateway](https://neon.com/docs/ai-gateway/embeddings) or [OpenAI's Embeddings API](https://platform.openai.com/docs/api-reference/embeddings). These APIs let you 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, but most embedding models generate vectors with many more. The examples below send the same text to each API and get a vector back. Size your `vector` column to match the model you choose. **Neon AI Gateway** The [Neon AI Gateway](https://neon.com/docs/ai-gateway/embeddings) serves embedding models on an OpenAI-compatible endpoint, using the same Neon credential as the rest of your project instead of a separate provider key. Its `qwen3-embedding-0-6b`, `bge-large-en`, and `gte-large-en` models return 1024-dimensional vectors. ```bash curl "$NEON_AI_GATEWAY_BASE_URL/v1/embeddings" \ -H "Content-Type: application/json" \ -H "Authorization: Bearer $NEON_AI_GATEWAY_TOKEN" \ -d '{ "input": "Your text string goes here", "model": "qwen3-embedding-0-6b", "encoding_format": "float" }' ``` The `model` field in the response reports the resolved, versioned model name that served the request: ```json { "object": "list", "data": [ { "object": "embedding", "index": 0, "embedding": [ -0.00520731508731842, -0.01622946560382843, -0.011803247034549713, -0.06526501476764679, ... (1024 values total, omitted for spacing) ] } ], "model": "qwen3-embedding-0-6b-112025", "usage": { "prompt_tokens": 6, "total_tokens": 6 } } ``` **OpenAI** OpenAI's `text-embedding-3-small` and `text-embedding-3-large` models generate 1536- and 3072-dimensional vectors by default. Generating an embedding requires an API key from [OpenAI](https://platform.openai.com/). ```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", "encoding_format": "float" }' ``` If it works, you'll get a response like this: ```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 } } ``` See [Embeddings](https://neon.com/docs/ai-gateway/embeddings) for the full gateway model list and options. 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 [LangChain](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 Lakebase Postgres database. ## Storing vector embeddings in Postgres Neon supports the [pgvector](https://neon.com/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 requires running the following `CREATE EXTENSION` statement from the [Neon SQL Editor](https://neon.com/docs/get-started/query-with-neon-sql-editor) or any SQL client connected to your Lakebase Postgres database. ```sql CREATE EXTENSION vector; ``` After installing `pgvector`, you can create a table to store your embeddings. For example: ```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](https://neon.com/docs/extensions/pgvector). ## Searching vector embeddings at scale `pgvector` gives you the `vector` type and similarity operators. To index and search embeddings at scale, Neon offers [Lakebase Search](https://neon.com/docs/ai/lakebase-search). Its [`lakebase_vector`](https://neon.com/docs/extensions/lakebase-vector) extension adds the `lakebase_ann` index for approximate nearest-neighbor search on your existing `pgvector` columns, with no schema or query changes, and scales to over a billion vectors on a single index. Pair it with `lakebase_text` for BM25 keyword search and hybrid results. For an end-to-end walkthrough that generates embeddings with the AI Gateway, stores them in Postgres, and runs vector, keyword, and hybrid searches, see [Get started with Lakebase Search](https://neon.com/docs/ai/lakebase-search-get-started). --- [Document source](https://neon.com/docs/ai/ai-database-versioning.md) --- > Summary: Database versioning with Neon snapshots is a pattern for AI agents and codegen platforms that captures point-in-time database states and restores them without changing the connection string, by transferring compute endpoints to a new branch via the `finalize_restore: true` flag. Use this pattern when you need instant rollbacks to a previous version while keeping the active branch connection string stable, or when you need temporary preview branches from any saved version. Snapshot limits and storage pricing vary by plan. # Database versioning with snapshots How AI agents and codegen platforms implement database version control using snapshots and preview branches Last updated: 2026-09-17 **Note:** Please give us [Feedback](https://console.neon.tech/app/projects?modal=feedback) from the Neon Console or by connecting with us on [Discord](https://neon.com/discord). **Limits and pricing:** The Free plan includes 1 manual snapshot, and paid plans (including the [Agent plan](https://neon.com/use-cases/ai-agents)) include 100 manual snapshots. On paid plans, snapshots created by backup schedules do not count toward this limit. Snapshot storage is billed at $0.09/GB-month. If you need higher limits, please reach out to [Neon support](https://neon.com/docs/introduction/support). ## 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. **Tip: 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. ## 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](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](https://neon.com/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](https://neon.com/docs/ai/ai-database-versioning#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](https://neon.com/docs/guides/active_branch_pattern.jpg) ## Implementation ### Creating snapshots Create a snapshot to capture the current database version using the [snapshot endpoint](https://neon.com/docs/reference/api/snapshots/create-snapshot): ```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' ``` **Response:** The JSON body includes a `snapshot` object. It may include optional **`full_size`** and **`diff_size`** (bytes) for storage size; the same fields appear when you [list](https://neon.com/docs/reference/api/snapshots/list-snapshots) or [update](https://neon.com/docs/reference/api/snapshots/update-snapshot) snapshots. See [Snapshot size fields in API responses](https://neon.com/docs/guides/backup-restore#snapshot-size-fields-in-api-responses). **When to create snapshots:** - Start of each agent session - Before database schema changes - After successful operations - User-initiated save points **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). ### Rolling back to (restoring) a snapshot Restore any snapshot to recover a previous version using the [restore endpoint](https://neon.com/docs/reference/api/snapshots/restore-snapshot): ```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** **Note: 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. #### 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 (for example, `main (old)`) to the branch name. **Info: 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 (for example, to create the next snapshot), you must retrieve and store the new branch ID after the restore operation completes. #### 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 (for example, `main (old)`) to avoid incurring storage costs. > See the [poll operation status](https://neon.com/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](https://neon.com/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 (for example, `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://neon.com/docs/reference/api/snapshots/list-snapshots): ```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://neon.com/docs/reference/api/snapshots/delete-snapshot): ```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 a snapshot Rename a snapshot or change its expiration using the [update endpoint](https://neon.com/docs/reference/api/snapshots/update-snapshot): ```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 fields (all optional):** - `name` (string): A new name for the snapshot - `expires_at` (string or `null`): The auto-deletion time in [RFC 3339](https://tools.ietf.org/html/rfc3339#section-5.6) format. Set a future timestamp to change the retention deadline, or send `null` to clear the expiration so the snapshot never expires. Omit the field to leave the current expiration unchanged. A past timestamp is rejected. Rename a snapshot: ```json { "snapshot": { "name": "important-milestone" } } ``` Extend a snapshot's expiration: ```json { "snapshot": { "expires_at": "2026-12-31T00:00:00Z" } } ``` Remove the expiration so the snapshot never expires: ```json { "snapshot": { "expires_at": null } } ``` #### 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](https://neon.com/docs/reference/glossary#project): Neon project that owns branches, computes, and snapshots, and more - [Branch](https://neon.com/docs/reference/glossary#branch): An isolated database environment with its own data and schema that you can connect to and modify - [Snapshot](https://neon.com/docs/reference/glossary#snapshot): An immutable, point-in-time backup of a branch's schema and data. Read-only until restored - [Root branch](https://neon.com/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](https://neon.com/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://neon.com/docs/reference/api/snapshots/create-snapshot) | `POST /api/v2/projects/{project_id}/branches/{branch_id}/snapshot` | Save current database state as a new version | | [Restore snapshot](https://neon.com/docs/reference/api/snapshots/restore-snapshot) | `POST /api/v2/projects/{project_id}/snapshots/{snapshot_id}/restore` | Restore database to a previous version | | [List snapshots](https://neon.com/docs/reference/api/snapshots/list-snapshots) | `GET /api/v2/projects/{project_id}/snapshots` | Get all available versions | | [Delete snapshot](https://neon.com/docs/reference/api/snapshots/delete-snapshot) | `DELETE /api/v2/projects/{project_id}/snapshots/{snapshot_id}` | Remove a saved version | | [Update snapshot](https://neon.com/docs/reference/api/snapshots/update-snapshot) | `PATCH /api/v2/projects/{project_id}/snapshots/{snapshot_id}` | Rename a version or change its expiration | | [Poll operation](https://neon.com/docs/reference/api/operations/get-project-operation) | `GET /api/v2/projects/{project_id}/operations/{operation_id}` | Check restore status | | [List branches](https://neon.com/docs/reference/api/branches/list-project-branches) (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 (for example, `prod (old)`) for sanity checks before deletion, or assign a [time to live](https://neon.com/docs/guides/branch-expiration) for automatic cleanup. - **Cleanup strategy**: Set `expires_at` on temporary snapshots and preview branches. Delete orphaned branches (for example, `production (old)`) created during restores. - **Version metadata**: Keep version metadata separate to preserve audit trail across restores. ## Frequently asked questions ### 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. ## 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. --- [Document source](https://neon.com/docs/ai/ai-google-colab.md) --- > Summary: Google Colab integration with Neon lets you run Python notebooks in a browser-based Jupyter environment that connects to Lakebase Postgres and uses the pgvector extension to store and query vector embeddings. Use this guide when you want to prototype vector similarity search without local setup, using psycopg2 to connect, CREATE EXTENSION vector to enable pgvector, and the <-> distance operator to run nearest-neighbor queries. A pre-built Colab notebook is available for one-click setup. # Google Colab Use Google Colab with Neon for vector similarity search Last updated: 2026-09-16 [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 enable 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](https://neon.com/docs/manage/databases#create-a-database) for instructions. ## Retrieve your database connection string Click **Connect** in the Console nav to open the **Connect to your branch** modal, and select a branch, a user, and the database you want to connect to. A connection string is constructed for you. ![Connection modal](https://neon.com/docs/connect/connect_to_branch_modal.png) ## Create a notebook In your browser, navigate to [Google Colab](https://colab.research.google.com/), and click **New notebook**. ![Google Colab](https://neon.com/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. [https://colab.research.google.com/github/neondatabase/neon-google-colab-notebooks/blob/main/neon_pgvector_quickstart.ipynb](https://colab.research.google.com/github/neondatabase/neon-google-colab-notebooks/blob/main/neon_pgvector_quickstart.ipynb) ## 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 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 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 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](https://neon.com/docs/extensions/pgvector). --- [Document source](https://neon.com/docs/ai/ai-intro.md) --- > Summary: Neon AI Starter Kit is the central hub for building AI and vector search applications on Lakebase Postgres on Neon, collecting concepts, framework integrations, and deployable starter apps in one place. Use this page when starting an AI project on Neon and need to orient across pgvector setup, RAG pipelines, semantic search, or scaling strategies before diving into a specific guide. Supported frameworks include LangChain, LlamaIndex, Semantic Kernel, and Inngest; app types covered include RAG chatbots, hybrid search, reverse image search, and text-to-SQL. # AI Starter Kit Resources for building AI applications with Lakebase Postgres on Neon Last updated: 2026-08-04 Build AI applications and agents on Neon. This guide collects resources for AI workloads: core concepts, starter applications, framework integrations, and deployment guides. Use them to build applications like RAG chatbots, semantic search engines, or custom AI tools. > **Start building AI apps with Neon** > > Sign up for Lakebase Postgres on Neon and jumpstart your AI application with our starter apps and resources. > > [Sign Up](https://console.neon.tech/signup) ## Getting started Learn the fundamentals of building AI applications with Neon: - [AI concepts](https://neon.com/docs/ai/ai-concepts): Learn the fundamentals of embeddings and vector search for AI applications - [pgvector extension](https://neon.com/docs/extensions/pgvector): Get started with pgvector for storing and querying vector embeddings ## AI frameworks and integrations Build AI applications faster with these popular frameworks, tools, and services: - [LangChain](https://neon.com/docs/ai/langchain): Create AI applications using LangChain with OpenAI and Neon - [LlamaIndex](https://neon.com/docs/ai/llamaindex): Build RAG applications using LlamaIndex with OpenAI and Neon - [Semantic Kernel](https://neon.com/docs/ai/semantic-kernel): Develop AI applications using Semantic Kernel with Azure OpenAI - [Inngest](https://neon.com/docs/ai/inngest): Build reliable AI workflows with Inngest and Neon - [app.build](https://neon.com/docs/ai/ai-app-build): Generate and deploy web applications using the open-source app.build agent ## Starter applications Hackable, fully-featured, pre-built starter apps to get you up and running: - [AI chatbot (OpenAI + LllamIndex)](https://github.com/neondatabase/examples/tree/main/ai/llamaindex/chatbot-nextjs): A Next.js AI chatbot starter app built with OpenAI and LlamaIndex - [AI chatbot (OpenAI + LangChain)](https://github.com/neondatabase/examples/tree/main/ai/langchain/chatbot-nextjs): A Next.js AI chatbot starter app built with OpenAI and LangChain - [RAG chatbot (OpenAI + LlamaIndex)](https://github.com/neondatabase/examples/tree/main/ai/llamaindex/rag-nextjs): A Next.js RAG chatbot starter app built with OpenAI and LlamaIndex - [RAG chatbot (OpenAI + LangChain)](https://github.com/neondatabase/examples/tree/main/ai/langchain/rag-nextjs): A Next.js RAG chatbot starter app built with OpenAI and LangChain - [Semantic search (OpenAI + LlamaIndex)](https://github.com/neondatabase/examples/tree/main/ai/llamaindex/semantic-search-nextjs): A Next.js Semantic Search chatbot starter app built with OpenAI and LlamaIndex - [Semantic search (OpenAI + LangChain)](https://github.com/neondatabase/examples/tree/main/ai/langchain/semantic-search-nextjs): A Next.js Semantic Search chatbot starter app built with OpenAI and LangChain - [Hybrid search (OpenAI)](https://github.com/neondatabase/examples/tree/main/ai/hybrid-search-nextjs): A Next.js Hybrid Search starter app built with OpenAI - [Reverse image search (OpenAI + LlamaIndex)](https://github.com/neondatabase/examples/tree/main/ai/llamaindex/reverse-image-search-nextjs): A Next.js Reverse Image Search Engine starter app built with OpenAI and LlamaIndex - [Chat with PDF (OpenAI + LlamaIndex)](https://github.com/neondatabase/examples/tree/main/ai/llamaindex/chat-with-pdf-nextjs): A Next.js Chat with PDF chatbot starter app built with OpenAI and LlamaIndex - [Chat with PDF (OpenAI + LangChain)](https://github.com/neondatabase/examples/tree/main/ai/langchain/chat-with-pdf-nextjs): A Next.js Chat with PDF chatbot starter app built with OpenAI and LangChain ## Scale your AI application - [Scale with Neon](https://neon.com/docs/ai/ai-scale-with-neon): Learn how to scale your AI application with Autoscaling and Read Replicas - [Optimize vector search](https://neon.com/docs/ai/ai-vector-search-optimization): Best practices for optimizing vector search performance ## Featured examples Real-world AI applications built with Neon that you can reference as code examples or inspiration. **Tip: Built something cool?** Share your AI app on our [#showcase](https://discord.gg/neon) channel on Discord. - [AI vector database per tenant](https://github.com/neondatabase/ai-vector-db-per-tenant): Deploy an AI vector database per-tenant architecture with Neon - [Guide: Build a RAG chatbot](https://neon.com/guides/chatbot-astro-postgres-llamaindex): Build a RAG chatbot in an Astro application with LlamaIndex and Postgres - [Guide: Build a Reverse Image Search Engine](https://neon.com/guides/llamaindex-postgres-search-images): Using LlamaIndex with Postgres to Build your own Reverse Image Search Engine - [Ask Neon Chatbot](https://github.com/neondatabase/ask-neon): An Ask Neon AI-powered chatbot built with pgvector - [Vercel Postgres pgvector Starter](https://vercel.com/templates/next.js/postgres-pgvector): Enable vector similarity search with Vercel Postgres powered by Neon - [YCombinator Semantic Search App](https://github.com/neondatabase/yc-idea-matcher): YCombinator semantic search application - [Web-based AI SQL Playground](https://github.com/neondatabase/postgres-ai-playground): An AI-enabled SQL playground application for natural language queries - [Jupyter Notebook for vector search with Neon](https://github.com/neondatabase/neon-vector-search-openai-notebooks): Jupyter Notebook for vector search with Neon, pgvector, and OpenAI - [Image search with Neon and Vertex AI](https://github.com/ItzCrazyKns/Neon-Image-Search): Community: An image search app built with Neon and Vertex AI - [Text-to-SQL conversion with Mistral + LangChain](https://github.com/mistralai/cookbook/blob/main/third_party/Neon/neon_text_to_sql.ipynb): A Text-to-SQL conversion app built with Mistral AI, Neon, and LangChain - [Postgres GPT Expert](https://neon.com/blog/openais-gpt-store-is-live-create-and-publish-a-custom-postgres-gpt-expert): Blog + repo: Create and publish a custom Postgres GPT Expert using OpenAI's GPT ## Vector search tools and notebooks Optimize your vector search implementation and experiment with different approaches: - [Vector search optimization](https://neon.com/docs/ai/ai-vector-search-optimization): Best practices for optimizing vector search performance - [Vector search notebooks](https://github.com/neondatabase/neon-vector-search-openai-notebooks): Interactive notebooks for vector search with OpenAI - [Google Colab guide](https://neon.com/docs/ai/ai-google-colab): Use Neon with Google Colab for ML experiments - [Azure Data Studio Notebooks](https://neon.com/docs/ai/ai-azure-notebooks): A cloud-based Jupyter notebook service integrated with Azure Data Studio --- [Document source](https://neon.com/docs/ai/ai-scale-with-neon.md) --- > Summary: Scaling options for AI applications that use pgvector on Lakebase Postgres, covering vertical scaling from 0.25 CU (1 GB RAM) to 56 CU (224 GB RAM) with autoscaling up to 16 CU, and horizontal scaling via read replicas for offloading vector similarity search workloads at no extra storage cost. # Scale your AI application with Neon Scale your AI application with Neon's Autoscaling and Read Replica features Last updated: 2026-10-01 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](https://neon.com/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](https://neon.com/docs/introduction/autoscaling). ## Storage On the Free plan, you get 1 GB of Postgres storage per project. Storage on paid plans is usage based. See [Neon plans](https://neon.com/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 use read replicas to offload reads from your primary compute to a dedicated compute. After you create a read replica, swap your Neon connection string for the read replica connection string. 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](https://neon.com/docs/introduction/read-replicas) and refer to our [Working with Neon read replicas](https://neon.com/docs/guides/read-replica-guide) guide. --- [Document source](https://neon.com/docs/ai/ai-vector-search-optimization.md) --- > Summary: pgvector similarity search optimization in Postgres covers profiling with EXPLAIN ANALYZE, choosing between sequential scans and approximate nearest neighbor indexes (HNSW or IVFFlat), and tuning build and query-time parameters to balance speed and recall. Use this page when query latency is too high and you need to select an index type, set build parameters, or tune query-time settings like ef_search or probes. HNSW delivers better query speed than IVFFlat at the cost of higher build time and memory; IVFFlat requires existing data before the index can be created. # Optimize pgvector search Fine-tune parameters for efficient and accurate similarity searches in Postgres Last updated: 2026-06-05 This guide covers how to use `pgvector` for vector similarity searches. 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. **Note: 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. The query below uses `EXPLAIN ANALYZE` to generate an execution plan and display the performance of the similarity search query. ```sql 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. **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. ![HNSW graph](https://neon.com/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 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 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 SET ivfflat.probes = 100; SET enable_seqscan=off; SELECT * FROM items ORDER BY embedding <-> '[0.011699999682605267,..., 0.008700000122189522]' LIMIT 100; ``` **Note:** In the example above, `enable_seqscan=off` forces Postgres to use index scans. 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. Try different values for `probes` and `lists` to find the right balance for your dataset. Good places to start: - 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. --- [Document source](https://neon.com/docs/ai/connect-mcp-clients-to-neon.md) --- > Summary: Set up Neon in AI agents and MCP clients that don't have their own setup page, including Antigravity, Cline, Devin Desktop, fx, Gamut, Gemini CLI, Grok Build, Jules, Kimi Code, Kiro, Pi, and Zed. Install agent skills and the hosted Neon MCP Server (https://mcp.neon.tech/mcp) with the Neon CLI or add-mcp, or configure the server by hand with OAuth or an API key. # Set up other agents and MCP clients Install Neon's agent skills and the Neon MCP Server in Devin Desktop, Cline, Zed, Gemini CLI, Kiro, Kimi Code, and other agents Last updated: 2026-11-05 This page covers agents and MCP clients that don't have their own setup page. If you use Claude Code, Cursor, Codex, VS Code, Claude.ai, ChatGPT, or Grok Bot, start from [Set up your AI agent](https://neon.com/docs/ai/agent-setup) instead. **Important: Security** The Neon MCP Server is intended for **development and testing only**. Always review LLM-requested actions before execution. See [MCP security guidance](https://neon.com/docs/ai/neon-mcp-server#mcp-security-guidance). ## Install for any supported agent Most agents get Neon's [agent skills](https://neon.com/docs/ai/agent-skills) and the [Neon MCP Server](https://neon.com/docs/ai/neon-mcp-server) as two installs. From your project directory, run: ```bash npx neon@latest skills --agent npx neon@latest mcp --agent ``` Replace `` with your agent's ID; `neon skills --help` and `neon mcp --help` list the IDs each command accepts. [`neon mcp`](https://neon.com/docs/cli/mcp) mints a Neon API key by default; pass `--oauth` to sign in on first use instead. To write only the MCP config, use [add-mcp](https://github.com/neondatabase/add-mcp), the tool the Neon CLI uses to patch each agent's MCP config: ```bash npx add-mcp https://mcp.neon.tech/mcp -a ``` Add `-g` for user-level config instead of project-level, then restart your agent. On first use, an OAuth window opens to authorize; for API key auth, add `--header "Authorization: Bearer $NEON_API_KEY"`. ## Supported agents (add-mcp) Run `npx add-mcp list-agents` for the live list from your installed version. As of [add-mcp](https://github.com/neondatabase/add-mcp) 2.6.0, `--agent` values include: | Assistant | `--agent` | Setup | | :------------------------ | :------------------- | :---------------------------------------------------------------------------------------------------------- | | Antigravity | `antigravity` | [Antigravity](https://neon.com/docs/ai/connect-mcp-clients-to-neon#antigravity) | | Claude Code | `claude-code` | [Claude Code page](https://neon.com/docs/ai/agent-setup/claude-code) | | Claude Desktop | `claude-desktop` | [Claude.ai and Claude Desktop page](https://neon.com/docs/ai/agent-setup/claude-ai) | | Cline (VS Code extension) | `cline` | [Cline](https://neon.com/docs/ai/connect-mcp-clients-to-neon#cline-vs-code-extension) | | Cline CLI | `cline-cli` | [Cline](https://neon.com/docs/ai/connect-mcp-clients-to-neon#cline-vs-code-extension) | | Codex | `codex` | [Codex page](https://neon.com/docs/ai/agent-setup/codex) | | Cursor | `cursor` | [Cursor page](https://neon.com/docs/ai/agent-setup/cursor) | | Factory Droid | `factory-droid` | [Any supported agent](https://neon.com/docs/ai/connect-mcp-clients-to-neon#install-for-any-supported-agent) | | fx | `fx` | [fx](https://neon.com/docs/ai/connect-mcp-clients-to-neon#fx) | | Gemini CLI | `gemini-cli` | [Any supported agent](https://neon.com/docs/ai/connect-mcp-clients-to-neon#install-for-any-supported-agent) | | GitHub Copilot CLI | `github-copilot-cli` | [VS Code page](https://neon.com/docs/ai/agent-setup/vscode) | | Goose | `goose` | [Any supported agent](https://neon.com/docs/ai/connect-mcp-clients-to-neon#install-for-any-supported-agent) | | Grok Build | `grok-build` | [Grok Build](https://neon.com/docs/ai/connect-mcp-clients-to-neon#grok-build) | | Hermes Agent | `hermes` | [Any supported agent](https://neon.com/docs/ai/connect-mcp-clients-to-neon#install-for-any-supported-agent) | | Junie | `junie` | [Any supported agent](https://neon.com/docs/ai/connect-mcp-clients-to-neon#install-for-any-supported-agent) | | Kilo Code | `kilo-code` | [Any supported agent](https://neon.com/docs/ai/connect-mcp-clients-to-neon#install-for-any-supported-agent) | | Kimi Code | `kimi-code` | [Kimi Code](https://neon.com/docs/ai/connect-mcp-clients-to-neon#kimi-code) | | Kiro CLI | `kiro-cli` | [Kiro](https://neon.com/docs/ai/connect-mcp-clients-to-neon#kiro) | | Mastra Code | `mastracode` | [Any supported agent](https://neon.com/docs/ai/connect-mcp-clients-to-neon#install-for-any-supported-agent) | | MCPorter | `mcporter` | [Any supported agent](https://neon.com/docs/ai/connect-mcp-clients-to-neon#install-for-any-supported-agent) | | OpenCode | `opencode` | [Any supported agent](https://neon.com/docs/ai/connect-mcp-clients-to-neon#install-for-any-supported-agent) | | Pi | `pi` | [Pi](https://neon.com/docs/ai/connect-mcp-clients-to-neon#pi) | | VS Code | `vscode` | [VS Code page](https://neon.com/docs/ai/agent-setup/vscode) | | Windsurf | `windsurf` | [Devin Desktop](https://neon.com/docs/ai/connect-mcp-clients-to-neon#devin-desktop) | | Zed | `zed` | [Zed](https://neon.com/docs/ai/connect-mcp-clients-to-neon#zed) | **Aliases:** `cline-vscode` → `cline`, `droid`/`factory` → `factory-droid`, `gemini` → `gemini-cli`, `github-copilot` → `vscode`, `grok` → `grok-build`, `hermes-agent` → `hermes`, `kilo`/`kilocode` → `kilo-code`, `kimi` → `kimi-code`, `kiro` → `kiro-cli`, `mastra` → `mastracode`, `pi-agent` → `pi`, `codeium`/`cascade` → `windsurf`. Config paths differ by agent and by project vs global (`-g`); see the [add-mcp README](https://github.com/neondatabase/add-mcp#supported-agents). ## Agents with their own page ### ChatGPT See [Set up Neon in ChatGPT](https://neon.com/docs/ai/agent-setup/chatgpt). ### Claude Code See [Set up Neon in Claude Code](https://neon.com/docs/ai/agent-setup/claude-code). ### Claude Desktop See [Set up Neon in Claude.ai and Claude Desktop](https://neon.com/docs/ai/agent-setup/claude-ai). ### Codex See [Set up Neon in Codex](https://neon.com/docs/ai/agent-setup/codex). ### Cursor See [Set up Neon in Cursor](https://neon.com/docs/ai/agent-setup/cursor). ### VS Code (with GitHub Copilot) See [Set up Neon in VS Code and GitHub Copilot](https://neon.com/docs/ai/agent-setup/vscode). ## Antigravity Antigravity can install Neon's [agent-skills repository](https://github.com/neondatabase/agent-skills) as a plugin, which includes the skills and the Neon MCP Server: ```bash agy plugin install https://github.com/neondatabase/agent-skills ``` Confirm that Antigravity found the plugin, its skills, and the MCP Server with `agy plugin list`. To authenticate, run `/mcp` in Antigravity, select the Neon MCP Server, and complete the OAuth flow. To install with the Neon CLI instead, use `--agent antigravity` with the commands in [Install for any supported agent](https://neon.com/docs/ai/connect-mcp-clients-to-neon#install-for-any-supported-agent). ## Cline (VS Code extension) For skills plus the MCP Server, use the commands in [Install for any supported agent](https://neon.com/docs/ai/connect-mcp-clients-to-neon#install-for-any-supported-agent). To add only the MCP Server: ```bash npx add-mcp https://mcp.neon.tech/mcp -a cline ``` For the Cline CLI, use `-a cline-cli`. To configure the extension by hand: 1. Open Cline in VS Code (sidebar → Cline icon). 2. Click the **MCP Servers** icon → **Installed** → **Configure MCP Servers** to open the configuration file. 3. Add the Neon server entry within the `mcpServers` object. For OAuth, leave out `headers`. For an API key, replace `` with your [Neon API key](https://neon.com/docs/manage/api-keys): ```json { "mcpServers": { "neon": { "type": "streamableHttp", "url": "https://mcp.neon.tech/mcp", "headers": { "Authorization": "Bearer " } } } } ``` 4. Save the file. Cline should reload the configuration automatically. With OAuth, review the requested permissions and click **Authorize** when the browser window opens. For more, see [Get started with Cline and Neon MCP Server](https://neon.com/guides/cline-mcp-neon). ## Devin Desktop (formerly Windsurf) Install Neon from the Devin marketplace: 1. In Devin Desktop, open **Customize**, then **Marketplace**. 2. Find **Neon** and install it. 3. Click **Connect MCP** and sign in to Neon in the browser. The plugin's status changes to **Enabled**. 4. Start a new session so Devin loads the plugin. The marketplace plugin includes the Neon MCP Server and Neon agent skills. ## fx [fx](https://fx.sh) reads MCP servers only from `~/.fx/mcp.json`. A project file can't add a server. add-mcp always writes that global file; `-g` isn't required. **Note:** fx rejects a literal `Authorization` header. Don't pass `--header "Authorization: Bearer $NEON_API_KEY"` when installing to fx. Use `bearer_token_env` (API key tab) or `/mcp auth` (OAuth tab). **OAuth** ```bash npx add-mcp https://mcp.neon.tech/mcp -a fx ``` This writes `~/.fx/mcp.json`: ```json { "mcp": { "neon": { "type": "http", "url": "https://mcp.neon.tech/mcp", "enabled": true } } } ``` A running session applies the change with `/mcp reload`. Then authorize from the fx shell: ```text /mcp auth neon --open ``` Confirm with `/mcp list`. **API key** 1. Create a [Neon API key](https://neon.com/docs/manage/api-keys#creating-api-keys) and export it in the environment fx will inherit: ```bash export NEON_API_KEY= ``` 2. Write `~/.fx/mcp.json`: ```json { "mcp": { "neon": { "type": "http", "url": "https://mcp.neon.tech/mcp", "enabled": true, "bearer_token_env": "NEON_API_KEY" } } } ``` 3. Start a new `fx` or `fx ask` session from this shell. Confirm with `/mcp list`. `/mcp reload` applies a later file change only in a session that already has `NEON_API_KEY`. See [fx MCP](https://fx.sh/docs/capabilities/mcp) for `/mcp reload`, `/mcp auth`, `/mcp list`, and `bearer_token_env`. ## Gamut 1. In your [Gamut](https://www.gamut.so/mcp/developer-tools/neon) agent, go to **Connections** and click **Add Connection**. 2. Search for **Neon** and click **+** to add it. 3. When the OAuth window opens, sign in to Neon and authorize the connection. 4. Ask your agent to query or manage your database on Neon to verify the connection. ## Grok Build Grok Build supports the Neon plugin at user level: ```bash npx neon@latest plugins --agent grok-build ``` The plugin includes the Neon skills and the Neon MCP Server. To add only the MCP Server, run `npx add-mcp https://mcp.neon.tech/mcp -a grok-build`. For the Grok Bot chat app, see [Set up Neon in Grok Bot](https://neon.com/docs/ai/agent-setup/grok-bot). ## Jules 1. Create a [Neon API key](https://neon.com/docs/manage/api-keys#creating-api-keys) from your Neon Console **Settings**. 2. Go to [jules.google.com](https://jules.google.com) > **Settings** > **MCP** (or use [this direct link](https://jules.google.com/settings/mcp)). 3. Click **Connect** on the Neon server and paste your API key when prompted. 4. Run a task invoking the Neon MCP Server to verify the connection. ## Kimi Code Install Neon's [agent-skills repository](https://github.com/neondatabase/agent-skills) as a plugin. Kimi reads its own manifest (`kimi.plugin.json`), which declares the Neon MCP Server, so one command wires up the skills and the MCP connection. In the Kimi CLI chat, run: ```text /plugins install https://github.com/neondatabase/agent-skills ``` Plugin changes apply to new sessions, so run `/new` afterward. You can also run `npx neon@latest plugins --agent kimi-code`. To add only the MCP Server, run `npx add-mcp https://mcp.neon.tech/mcp -a kimi-code`, start a new session, and click **Authorize** when the OAuth window opens. ## Kiro For skills plus the MCP Server, use the commands in [Install for any supported agent](https://neon.com/docs/ai/connect-mcp-clients-to-neon#install-for-any-supported-agent). To add only the MCP Server: ```bash npx add-mcp https://mcp.neon.tech/mcp -a kiro-cli ``` Restart Kiro (or enable the MCP Server in settings). When the OAuth window opens, click **Authorize** to complete the connection. For manual configuration, Kiro reads `~/.kiro/settings/mcp.json` (global) or `.kiro/settings/mcp.json` (project). See [Kiro MCP documentation](https://kiro.dev/docs/mcp/). **Tip: One-click install for Kiro** [https://kiro.dev/launch/mcp/add?name=Neon&config=%7B%22url%22%3A%20%22https%3A//mcp.neon.tech/mcp%22%7D](https://kiro.dev/launch/mcp/add?name=Neon\&config=%7B%22url%22%3A%20%22https%3A//mcp.neon.tech/mcp%22%7D) ## Pi Install Neon's skills in [Pi](https://pi.dev) from npm: ```bash pi install npm:@neon/skills ``` Or straight from the repository: ```bash pi install git:github.com/neondatabase/agent-skills ``` Pi reads the `skills/` directory directly, so there's no separate sync step. This installs the skills only. To add the Neon MCP Server, run `npx neon@latest mcp --agent pi`. ## Zed Zed calls MCP servers **context servers**. For skills plus the MCP Server, use the commands in [Install for any supported agent](https://neon.com/docs/ai/connect-mcp-clients-to-neon#install-for-any-supported-agent). To add only the MCP Server: **OAuth** ```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. **API key** Add this to `~/.config/zed/settings.json`. Replace `` with your [Neon API key](https://neon.com/docs/manage/api-keys): ```json "context_servers": { "Neon": { "source": "custom", "type": "http", "url": "https://mcp.neon.tech/mcp", "headers": { "Authorization": "Bearer " } } } ``` For more details, including workflow examples and troubleshooting, see [Get started with Zed and the Neon MCP Server](https://neon.com/guides/zed-mcp-neon). ## Other MCP clients For Gemini CLI, Goose, OpenCode, and the other agents in the [table above](https://neon.com/docs/ai/connect-mcp-clients-to-neon#supported-agents-add-mcp), use [Install for any supported agent](https://neon.com/docs/ai/connect-mcp-clients-to-neon#install-for-any-supported-agent). For a client that add-mcp doesn't support, build its config with the [config generator](https://neon.com/docs/ai/neon-mcp-server#config-generator) or write it by hand. Most clients accept `"type": "http"` with the URL `https://mcp.neon.tech/mcp`. If your client only supports local (stdio) servers, use the [`mcp-remote` bridge](https://neon.com/docs/ai/neon-mcp-server#deprecated-stdio). ## Troubleshooting See [MCP troubleshooting](https://neon.com/docs/ai/neon-mcp-server#troubleshooting) for retired SSE endpoints, stdio-only clients, and OAuth `invalid redirect uri` errors. --- [Document source](https://neon.com/docs/ai/inngest.md) --- > Summary: Inngest is a TypeScript workflow framework for building AI RAG and agentic pipelines on Lakebase Postgres, providing per-step caching, automatic retries, concurrency controls, and LLM request offloading via step.ai.infer() that pauses compute while waiting for slow model responses. Use this page when you need database-change-triggered or event-driven AI workflows, or want to avoid unnecessary serverless compute costs during LLM calls. Starter apps for Next.js RAG, multi-tenant RAG, and auto-embeddings with OpenAI are included. # Inngest Quickly build AI RAG and Agentic workflows that scale with Inngest and Neon Last updated: 2026-07-31 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 the database 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.](https://neon.com/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](https://neon.com/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.](https://neon.com/docs/guides/inngest-with-step-ai-infer.png) ![An AI workflow built with Inngest. The AI request is offloaded to the LLM provider.](https://neon.com/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 Lakebase Postgres to trigger AI workflows based on database changes: ![Inngest integrates with Lakebase Postgres to trigger AI workflows based on database changes](https://neon.com/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 Inngest's Neon integration to trigger AI workflows from your Neon database changes [by following this guide](https://neon.com/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. - [RAG starter (OpenAI + Inngest)](https://github.com/neondatabase/examples/tree/main/ai/inngest/rag-starter-nextjs): A Next.js RAG starter app built with OpenAI and Inngest - [multi-tenant RAG (OpenAI + Inngest)](https://github.com/inngest/multi-tenant-rag-example): A Next.js contacts importer multi-tenant RAG built with OpenAI and Inngest - [Auto-embedding (OpenAI + Inngest)](https://github.com/neondatabase/examples/tree/main/ai/inngest/auto-embeddings-nextjs): A Next.js app example of auto-embedding with Inngest --- [Document source](https://neon.com/docs/ai/lakebase-search-get-started.md) --- > Summary: Step-by-step guide to enabling lakebase_vector and lakebase_text on a Neon Postgres database, creating a documents table with vector embeddings and a BM25 full-text index, and running vector and keyword searches from a TypeScript application using @neondatabase/serverless and the Vercel AI SDK. # Get started with Lakebase Search Set up vector and full-text search on Neon in minutes Last updated: 2026-10-23 This guide sets up Lakebase Search on a Neon project: enabling both extensions, creating a schema that supports vector and full-text search, inserting documents with embeddings, and querying from TypeScript. ## Prerequisites - A Neon project. You enable Lakebase Search on it in the first step below. - Postgres 16 or later (Lakebase Search requires PG16+) - Node.js 22 or later - Choose an embedding provider to turn text into vectors: - **Neon AI Gateway** (this guide's default): set `NEON_AI_GATEWAY_TOKEN` and `NEON_AI_GATEWAY_BASE_URL` (see [Get started](https://neon.com/docs/ai-gateway/get-started)) and use the [`qwen3-embedding-0-6b`](https://neon.com/docs/ai-gateway/embeddings) model (1024 dimensions). Requires [prepaid AI Gateway credits](https://neon.com/docs/ai-gateway/prepaid-credits), available on any plan, and a project in a [Neon AI Gateway region](https://neon.com/docs/ai-gateway/overview). - **OpenAI directly**: install `@ai-sdk/openai`, set `OPENAI_API_KEY`, and use `openai.embeddingModel('text-embedding-3-small')` from that provider (1536 dimensions). - **Any other provider**: generate the vector with its SDK and match the `VECTOR` column to its dimensions. ## Enable the extensions Install the extensions in the [Neon SQL Editor](https://neon.com/docs/get-started/query-with-neon-sql-editor) or any connected Postgres client: ```sql CREATE EXTENSION IF NOT EXISTS lakebase_vector CASCADE; CREATE EXTENSION IF NOT EXISTS lakebase_text CASCADE; ``` `CASCADE` automatically installs `pgvector` if it is not already present, since `lakebase_vector` depends on it. ## Create a table ```sql CREATE TABLE documents ( id SERIAL PRIMARY KEY, title TEXT NOT NULL, body TEXT NOT NULL, embedding VECTOR(1024), body_tsv TSVECTOR GENERATED ALWAYS AS (to_tsvector('english', body)) STORED ); CREATE INDEX documents_embedding_idx ON documents USING lakebase_ann (embedding vector_cosine_ops); ``` The `lakebase_bm25` index is created in a later step, after data is inserted. BM25 computes corpus-wide statistics (document count, term frequencies) at index build time, so the index must be built on populated data to return meaningful scores. ## Set up your project The remaining steps run from a local TypeScript project. Install dependencies: ```bash npm install @neondatabase/serverless @neon/ai-sdk-provider@1.1.0 ai@7.0.133 dotenv ``` This guide uses Neon's provider with the Vercel AI SDK for embeddings and Jev. The provider reads your AI Gateway credentials automatically. Keep the SDK versions pinned while `experimental_decide` is experimental. Create a `.env` file with your Neon connection string and AI Gateway credentials. See [Get started with AI Gateway](https://neon.com/docs/ai-gateway/get-started) for how to obtain the gateway values: ```ini filename=".env" DATABASE_URL=postgresql://[user]:[password]@[neon_hostname]/[dbname]?sslmode=require NEON_AI_GATEWAY_TOKEN=nt_live_... NEON_AI_GATEWAY_BASE_URL=https://[branch-host] ``` ## Run the demo Create `search.ts` and paste the following. It inserts documents with embeddings, creates the `lakebase_bm25` index, runs a vector search, then runs a BM25 text search: ```typescript filename="search.ts" import 'dotenv/config'; import { neon } from '@neondatabase/serverless'; import { neon as neonAi } from '@neon/ai-sdk-provider'; import { embed } from 'ai'; const sql = neon(process.env.DATABASE_URL!); const documents = [ { title: 'Vector search on Postgres', body: 'lakebase_vector adds a lakebase_ann index to Postgres for fast approximate nearest-neighbor search at billion-vector scale.', }, { title: 'BM25 full-text search', body: 'lakebase_text adds a lakebase_bm25 index that provides BM25 ranking and top-K pushdown while preserving standard tsvector types.', }, { title: 'AI agent memory', body: 'Store conversation history, session state, and vector embeddings in a single Postgres database to power AI agent backends.', }, { title: 'Branching for retrieval experiments', body: 'Neon branching lets you test new chunking strategies or embedding models on a branch without rebuilding your search indexes.', }, { title: 'Scale-to-zero search', body: 'Lakebase Search indexes survive cold starts. Your vector and BM25 indexes are available immediately after a Neon compute wakes up.', }, ]; async function embedText(text: string): Promise { const { embedding } = await embed({ model: neonAi.embeddingModel('qwen3-embedding-0-6b'), value: text, }); return JSON.stringify(embedding); } async function embedAndInsert() { for (const doc of documents) { const vector = await embedText(doc.body); await sql` INSERT INTO documents (title, body, embedding) VALUES (${doc.title}, ${doc.body}, ${vector}::vector) `; } } async function vectorSearch(query: string, limit = 5) { const queryVector = await embedText(query); return sql` SELECT id, title, embedding <=> ${queryVector}::vector AS distance FROM documents ORDER BY distance LIMIT ${limit} `; } // BM25 scores are negative — lower (more negative) means more relevant async function textSearch(query: string, limit = 5) { return sql` SELECT id, title, score FROM ( SELECT id, title, body_tsv <@> to_bm25query( to_tsvector('english', ${query}), 'documents_bm25' ) AS score FROM documents ) AS scored WHERE score < 0 ORDER BY score, id LIMIT ${limit} `; } async function main() { console.log('Inserting documents...'); await embedAndInsert(); console.log('Building BM25 index...'); await sql` CREATE INDEX IF NOT EXISTS documents_bm25 ON documents USING lakebase_bm25 (body_tsv) WITH (default_limit = 10) `; console.log('\nVector search — "how do agents store memory?":'); console.log(await vectorSearch('how do agents store memory?')); console.log('\nBM25 search — "vector search":'); console.log(await textSearch('vector search')); } main(); ``` Run it: ```bash npx tsx search.ts ``` ## Combine results with hybrid search Vector search finds matches by meaning, while keyword search finds matches by wording. You can combine their results in two ways: - **Jev through Neon AI Gateway** reads each result alongside your query and scores how likely it is to answer your question. - **Reciprocal Rank Fusion (RRF)** uses each result's position in the two search lists to build a combined ranking, without an extra model call. ### Use Jev through Neon AI Gateway Jev reads each result alongside your query and estimates how likely it is to answer your question. The example below combines both searches, removes duplicates, and puts the most likely answers first. It follows the [TypeSafe reranking cookbook](https://docs.typesafe.ai/cookbooks/rerank_typesafe). Jev runs through AI Gateway, so it has the same credits requirement as AI Gateway embeddings. If you don't have AI Gateway, use [RRF](https://neon.com/docs/ai/lakebase-search-get-started#fuse-ranks-with-rrf) instead. Add the following code to `search.ts`. It reuses the provider and credentials from the embedding example. See [Decision models](https://neon.com/docs/ai-gateway/decisions#use-with-the-vercel-ai-sdk) for more about the SDK. ```typescript filename="search.ts" import { experimental_decide as decide } from 'ai'; type Candidate = { id: number; title: string; body: string }; async function hybridSearchWithJev(query: string, limit = 5): Promise { if (!Number.isInteger(limit) || limit < 1) { throw new Error('limit must be a positive integer'); } const queryVector = await embedText(query); const candidates = (await sql` WITH vector_candidates AS ( SELECT id FROM documents WHERE embedding IS NOT NULL ORDER BY embedding <=> ${queryVector}::vector LIMIT 40 ), keyword_candidates AS ( SELECT id FROM ( SELECT id, body_tsv <@> to_bm25query( to_tsvector('english', ${query}), 'documents_bm25' ) AS score FROM documents ) AS scored WHERE score < 0 ORDER BY score, id LIMIT 40 ), candidate_ids AS ( SELECT id FROM vector_candidates UNION SELECT id FROM keyword_candidates ) SELECT d.id, d.title, d.body FROM candidate_ids AS c JOIN documents AS d ON d.id = c.id ORDER BY d.id `) as Candidate[]; if (candidates.length === 0) return []; const { answers } = await decide({ model: neonAi.decisionModel('typesafeai-jev-1-14-0'), state: { query }, questions: Object.fromEntries( candidates.map((doc, index) => [ `d${index}`, { type: 'boolean' as const, instructions: { question: 'Given the search query in state.query, does this candidate passage supply the specific information the user is looking for?', candidate: { title: doc.title, body: doc.body }, }, criteria: { true: 'The candidate states the specific facts or steps the query asks for.', false: 'The candidate only shares keywords or a topic with the query, answers a different question, or lacks the requested information.', }, }, ]) ), maxRetries: 0, abortSignal: AbortSignal.timeout(10_000), }); return candidates .map((doc, index) => { const answer = answers[`d${index}`]; if (answer?.type !== 'boolean') { throw new Error(`Missing relevance probability for d${index}`); } return { doc, index, probability: answer.probability }; }) .sort((a, b) => b.probability - a.probability || a.index - b.index) .slice(0, limit) .map(({ doc }) => doc); } ``` Call `hybridSearchWithJev(query)` after inserting the documents and building the indexes. It sends the query and all the search results to Jev in one request, which must fit within the model's 65,536-token context window. For long documents, search shorter passages or send fewer results. If your app restricts documents by tenant or user, apply those filters to both searches before limiting the results. One result will always rank first, even if none answers the query. If your app needs to say "no answer," test it with unanswered queries to choose a minimum score for accepting a result. If the Jev call fails, you can catch the error and fall back to `hybridSearch`. ### Fuse ranks with RRF RRF gives each result a score of `1 / (60 + rank)` for its position in each search list, then adds the two scores. Results near the top of either list get higher scores. Add a `hybridSearch` function to `search.ts`, alongside `vectorSearch` and `textSearch`. It reuses the `documents` table and indexes from above: ```typescript filename="search.ts" async function hybridSearch(query: string, limit = 5) { const queryVector = await embedText(query); return sql` WITH vector_ranked AS ( SELECT id, RANK() OVER (ORDER BY dist) AS rank FROM ( SELECT id, embedding <=> ${queryVector}::vector AS dist FROM documents WHERE embedding IS NOT NULL ORDER BY dist FETCH FIRST 40 ROWS WITH TIES ) v ), keyword_ranked AS ( SELECT id, RANK() OVER (ORDER BY score) AS rank FROM ( SELECT id, score FROM ( SELECT id, body_tsv <@> to_bm25query( to_tsvector('english', ${query}), 'documents_bm25' ) AS score FROM documents ) AS scored WHERE score < 0 ORDER BY score, id LIMIT 40 ) k ) SELECT d.id, d.title, COALESCE(1.0 / (60 + v.rank), 0) + COALESCE(1.0 / (60 + k.rank), 0) AS rrf_score FROM documents d LEFT JOIN vector_ranked v ON d.id = v.id LEFT JOIN keyword_ranked k ON d.id = k.id WHERE v.id IS NOT NULL OR k.id IS NOT NULL ORDER BY rrf_score DESC, d.id LIMIT ${limit} `; } ``` `WITH TIES` keeps vector results that share the 40th result's distance, so the search can return more than 40 rows. The keyword search leaves out non-matches and stops at 40 because many BM25 matches can have the same score. `RANK()` gives tied results the same rank, and `d.id` keeps the final order stable when scores are equal. Try different candidate counts and RRF constants to find what works best for your data. ## Next steps - [lakebase_vector reference](https://neon.com/docs/extensions/lakebase-vector): index options, operator classes, tuning guide - [lakebase_text reference](https://neon.com/docs/extensions/lakebase-text): BM25 operators, functions, fallback parameters, prefilter - [lakebase_tokenizer reference](https://neon.com/docs/extensions/lakebase-tokenizer): optional configurable tokenization, stop words, synonyms, and stemming --- [Document source](https://neon.com/docs/ai/lakebase-search.md) --- > Summary: Lakebase Search adds vector, keyword, and hybrid search to Neon through the lakebase_vector and lakebase_text Postgres extensions, with optional configurable tokenization from lakebase_tokenizer. Use this page to understand the search types, how the extensions work, the scale-to-zero architecture advantages, and where to get started. # Lakebase Search Scalable vector and full-text search for Postgres Last updated: 2026-10-23 **About Lakebase:** Lakebase Search is developed by Databricks. These extensions are part of the shared technology foundation between Neon and the Databricks Lakebase platform. Lakebase Search adds vector, keyword, and hybrid search to your Neon project. Install `lakebase_vector` for vector search, `lakebase_text` for BM25 keyword search, and `lakebase_tokenizer` for configurable tokenization. [View prompt](https://neon.com/prompts/lakebase-search-landing.md) ## Vector, keyword, and hybrid search Lakebase Search gives you two complementary ways to search. Use either on its own, or combine them: - **Vector (semantic) search** finds rows whose meaning is closest to your query, even when they share no words. You search with an embedding (a numeric vector from a model), and the `lakebase_ann` index returns the nearest vectors by distance. Use it for natural-language questions, recommendations, and retrieval-augmented generation (RAG). - **Keyword (full-text) search** ranks rows by how well they match the exact terms in your query, using BM25 relevance scoring from the `lakebase_bm25` index. Use it for names, codes, and exact-term lookups where wording matters. - **Hybrid search** combines vector and keyword results with fusion or reranking, so you get semantic and exact-term matches together. Use it when queries mix intent with specific terms, which covers most real-world search. The [Get started guide](https://neon.com/docs/ai/lakebase-search-get-started#combine-results-with-hybrid-search) shows how to combine results with Jev through Neon AI Gateway or RRF. ![Keyword search matches only documents that contain the typed words and misses synonyms like "quick automobile" for "fast sports car." Vector search places the query and documents in the same embedding space and returns the nearest neighbors by meaning, including those synonyms.](https://neon.com/docs/ai/lakebase-search-keyword-vs-vector.png) ## How it works Lakebase Search is built on three Postgres extensions: - **[`lakebase_vector`](https://neon.com/docs/extensions/lakebase-vector)**: adds the `lakebase_ann` index type for vector similarity search. No migration from `pgvector` required. The same `vector` types, distance operators, and query syntax work unchanged. Scales to over 1 billion vectors on a single index. - **[`lakebase_text`](https://neon.com/docs/extensions/lakebase-text)**: adds the `lakebase_bm25` index type for BM25 keyword search. No migration from Postgres full-text search required. Standard `tsvector` types and query operators work unchanged. Adds BM25 ranking and top-K pushdown that native GIN lacks. - **[`lakebase_tokenizer`](https://neon.com/docs/extensions/lakebase-tokenizer)**: adds configurable whole-word tokenization and Chinese, Japanese, and Korean (CJK) morphological analysis through Postgres's text-search dictionary interface. It produces standard `tsvector` values that work with GIN and `lakebase_bm25` indexes. ## How `lakebase_ann` scales `lakebase_ann` is designed for the separated compute/storage architecture that powers Neon. Because the index lives in storage rather than in compute memory, it works naturally with Neon's scale-to-zero model: your vector index is available immediately after a cold start, with no warmup required. You only pay for compute when your database is actively serving requests. This holds for production workloads and for development or staging environments where the database sits idle most of the time. It uses IVF (Inverted File) partitioning to divide the vector space into lists and searches only the relevant ones at query time, using sequential I/O that suits storage-backed systems. RaBitQ quantization compresses vectors 4–8x, keeping index size and build time down. The result: - **Scale to 1 billion+ vectors**: a single `lakebase_ann` index grows with your data without resharding or rebuilding - **Faster index builds**: compression reduces index size significantly, making builds 50–100x faster than HNSW - **Branching without index rebuilds**: Neon branches copy-on-write; your search indexes are available instantly on every branch without re-indexing - **Scale-to-zero compatible**: indexes survive cold starts without warmup; you don't pay for idle compute ## Get started - [Quickstart](https://neon.com/docs/ai/lakebase-search-get-started): Install lakebase_vector and lakebase_text, create a schema, insert documents with embeddings, and run your first searches - [lakebase_vector reference](https://neon.com/docs/extensions/lakebase-vector): Index options, operator classes, and tuning reference for lakebase_vector - [lakebase_text reference](https://neon.com/docs/extensions/lakebase-text): BM25 operators, functions, fallback parameters, and prefilter reference for lakebase_text - [lakebase_tokenizer reference](https://neon.com/docs/extensions/lakebase-tokenizer): Whole-word and CJK tokenization, built-in language configurations, custom stop words, synonyms, and stemming --- [Document source](https://neon.com/docs/ai/langchain.md) --- > Summary: LangChain integration with Neon uses the `NeonPostgres` vector store class (backed by `pgvector`) to store embeddings and run similarity search directly in Postgres. Use this page when building RAG pipelines, AI chatbots, or semantic search in JavaScript/TypeScript and you need LangChain's retrieval chain wired to a Neon database. Includes full TypeScript code for initializing the vector store with OpenAI embeddings, streaming chat completions via `createRetrievalChain`, and links to Next.js starter apps for chatbot, RAG, semantic search, and PDF chat. # LangChain Build AI applications faster with LangChain and Postgres Last updated: 2026-09-30 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 handles document insertion and embedding generation through its vector store methods. Here's how you can initialize Postgres Vector with LangChain. `OpenAIEmbeddings` works against either OpenAI directly or the [Neon AI Gateway](https://neon.com/docs/ai-gateway/embeddings), which serves embedding models on an OpenAI-compatible endpoint using the same Neon credential as the rest of your project: **Neon AI Gateway** ```tsx // File: vectorStore.ts import { NeonPostgres } from '@langchain/community/vectorstores/neon'; import { OpenAIEmbeddings } from '@langchain/openai'; const embeddings = new OpenAIEmbeddings({ model: 'qwen3-embedding-0-6b', // 1024-dimensional; supports the `dimensions` parameter dimensions: 512, apiKey: process.env.NEON_AI_GATEWAY_TOKEN, configuration: { baseURL: `${process.env.NEON_AI_GATEWAY_BASE_URL}/v1`, }, }); 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(); ``` **OpenAI** ```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(); ``` **Note:** Set `NEON_AI_GATEWAY_TOKEN` and `NEON_AI_GATEWAY_BASE_URL` from your branch (`neon env pull`, or the Neon Console's **Connect** panel). On the `openai` JavaScript SDK v6, embedding calls need `encoding_format: 'float'`, or upgrade to v7 or later. See [Embeddings](https://neon.com/docs/ai-gateway/embeddings) for model IDs, dimensions, and this SDK caveat. ## 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('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. - [AI chatbot (OpenAI + LangChain)](https://github.com/neondatabase/examples/tree/main/ai/langchain/chatbot-nextjs): A Next.js AI chatbot starter app built with OpenAI and LangChain - [RAG chatbot (OpenAI + LangChain)](https://github.com/neondatabase/examples/tree/main/ai/langchain/rag-nextjs): A Next.js RAG chatbot starter app built with OpenAI and LangChain - [Semantic search chatbot (OpenAI + LangChain)](https://github.com/neondatabase/examples/tree/main/ai/langchain/semantic-search-nextjs): A Next.js Semantic Search chatbot starter app built with OpenAI and LangChain - [Chat with PDF (OpenAI + LangChain)](https://github.com/neondatabase/examples/tree/main/ai/langchain/chat-with-pdf-nextjs): A Next.js Chat with PDF chatbot starter app built with OpenAI and LangChain --- [Document source](https://neon.com/docs/ai/llamaindex.md) --- > Summary: LlamaIndex integrates with Lakebase Postgres as a vector store via the pgvector extension, enabling RAG pipelines, semantic search, and AI chatbots backed by serverless Postgres. Use this page to wire up PGVectorStore, generate OpenAI embeddings, and stream chat completions through ContextChatEngine in a Next.js API route. Includes TypeScript code for initialization and streaming, plus links to starter apps for chatbot, RAG, semantic search, reverse image search, and PDF chat. # LlamaIndex Build AI applications faster with LlamaIndex and Postgres Last updated: 2026-09-30 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. `OpenAIEmbedding` works against either OpenAI directly or the [Neon AI Gateway](https://neon.com/docs/ai-gateway/embeddings), which serves embedding models on an OpenAI-compatible endpoint using the same Neon credential as the rest of your project: **Neon AI Gateway** ```tsx // File: vectorStore.ts import { OpenAIEmbedding, Settings } from 'llamaindex'; import { PGVectorStore } from 'llamaindex/storage/vectorStore/PGVectorStore'; Settings.embedModel = new OpenAIEmbedding({ model: 'qwen3-embedding-0-6b', // 1024-dimensional; supports the `dimensions` parameter dimensions: 512, apiKey: process.env.NEON_AI_GATEWAY_TOKEN, additionalSessionOptions: { baseURL: `${process.env.NEON_AI_GATEWAY_BASE_URL}/v1`, }, }); 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); ``` **OpenAI** ```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); ``` **Note:** Set `NEON_AI_GATEWAY_TOKEN` and `NEON_AI_GATEWAY_BASE_URL` from your branch (`neon env pull`, or the Neon Console's **Connect** panel). Keep the `PGVectorStore` `dimensions` in sync with the embedding model's output size. See [Embeddings](https://neon.com/docs/ai-gateway/embeddings) for model IDs and dimensions. ## 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. - [AI chatbot (OpenAI + LllamIndex)](https://github.com/neondatabase/examples/tree/main/ai/llamaindex/chatbot-nextjs): A Next.js AI chatbot starter app built with OpenAI and LlamaIndex - [RAG chatbot (OpenAI + LlamaIndex)](https://github.com/neondatabase/examples/tree/main/ai/llamaindex/rag-nextjs): A Next.js RAG chatbot starter app built with OpenAI and LlamaIndex - [Semantic search chatbot (OpenAI + LlamaIndex)](https://github.com/neondatabase/examples/tree/main/ai/llamaindex/semantic-search-nextjs): A Next.js Semantic Search chatbot starter app built with OpenAI and LlamaIndex - [Reverse image search (OpenAI + LlamaIndex)](https://github.com/neondatabase/examples/tree/main/ai/llamaindex/reverse-image-search-nextjs): A Next.js Reverse Image Search Engine starter app built with OpenAI and LlamaIndex - [Chat with PDF (OpenAI + LlamaIndex)](https://github.com/neondatabase/examples/tree/main/ai/llamaindex/chat-with-pdf-nextjs): A Next.js Chat with PDF chatbot starter app built with OpenAI and LlamaIndex --- [Document source](https://neon.com/docs/ai/neon-mcp-server.md) --- > Summary: The Neon MCP Server implements the Model Context Protocol (MCP), letting AI assistants interact with your Neon projects on your behalf. Set up with `npx neon@latest mcp` or use the config generator. Supports OAuth and API key auth. # Neon MCP Server overview Connect your AI assistant to Neon to manage projects, run queries, and make schema changes Last updated: 2026-11-06 The Neon MCP Server implements the Model Context Protocol (MCP), letting AI assistants interact with your Neon projects on your behalf. Your AI agent can interact with Neon via MCP tools or by running [Neon CLI](https://neon.com/docs/cli) commands directly. **Important: Security** The Neon MCP Server grants broad database management capabilities. **Always review and authorize actions requested by the LLM before execution.** Restrict access to trusted users only. See [MCP security guidance](https://neon.com/docs/ai/neon-mcp-server#mcp-security-guidance). ## Quick setup To set up the Neon MCP Server in your agent, follow [Set up your AI agent](https://neon.com/docs/ai/agent-setup). For most coding agents, the Neon plugin installs the MCP Server together with Neon's agent skills. To install only the MCP Server, run [`neon mcp`](https://neon.com/docs/cli/mcp): ```bash npx neon@latest mcp ``` It prompts for where to write the config, which agents to install into, and how to authenticate, then writes it for you. For CI or headless agents, run `neon mcp -y --agent --api-key `. The CLI signs in with that key and mints a new one for the MCP Server. Or use the API key option in the [config generator](https://neon.com/docs/ai/neon-mcp-server#config-generator). ## Config generator Use the generator to build an MCP config for your editor and auth method, including the `Authorization` header for API key or remote agent setups. If you'd rather write the config by hand, most clients accept this format. With OAuth, your client opens a browser to authorize on first use: **OAuth** ```json { "mcpServers": { "Neon": { "type": "http", "url": "https://mcp.neon.tech/mcp" } } } ``` **API key** ```json { "mcpServers": { "Neon": { "type": "http", "url": "https://mcp.neon.tech/mcp", "headers": { "Authorization": "Bearer " } } } } ``` Add [access control](https://neon.com/docs/ai/neon-mcp-server#access-control) parameters to the `url` as needed. ## Claude connector The Neon MCP Server is an official Claude connector for Claude.ai and Claude Desktop. See [Set up Neon in Claude.ai and Claude Desktop](https://neon.com/docs/ai/agent-setup/claude-ai). This page covers the hosted Neon MCP Server, which manages your Neon resources. To give your own application an MCP server that customers connect to, see [Build an MCP server with Managed Better Auth](https://neon.com/docs/compute/functions/mcp-server). ## Access control The Neon MCP Server supports URL parameters to restrict scope and permissions. Append them to the MCP URL (`https://mcp.neon.tech/mcp`). ### Read-only mode Append `?readonly=true` to restrict the server to read operations: ``` https://mcp.neon.tech/mcp?readonly=true ``` `SELECT` queries and schema inspection remain available. Write operations (creating branches, running migrations, modifying auth config) are disabled. `run_sql_transaction` and `get_connection_string` aren't available in read-only mode; use `run_sql` for read queries. With OAuth, you can also choose read-only scope during the authorization flow instead of using the URL parameter. ### Project-scoped mode Scope all operations to a single project: ``` https://mcp.neon.tech/mcp?projectId= ``` Cross-project search and navigation are disabled in this mode, and project management tools such as `list_projects` and `create_project` are hidden. ### Category filtering Restrict active tools to specific categories using `?category=` (repeatable): ``` https://mcp.neon.tech/mcp?category=querying&category=schema ``` See [Available tools](https://neon.com/docs/ai/neon-mcp-server#available-tools) for the full category list. To verify which tools are active for a given config without authenticating: ```bash curl "https://mcp.neon.tech/api/list-tools?readonly=true&category=querying" ``` ### Postgres role By default, SQL tools connect as the database owner. Set `?roleName=` to make every SQL tool log in as that Postgres role instead, so the role's grants decide what the agent can read and change: ``` https://mcp.neon.tech/mcp?readonly=true&roleName=app_reader ``` The role must exist on each branch you query and be able to log in. For example, a role that can only read one table: ```sql CREATE ROLE app_reader LOGIN PASSWORD ''; GRANT SELECT ON public.orders TO app_reader; ``` Create the role with SQL, as shown above, or create a read-only or read-write role with [`neon roles create --access`](https://neon.com/docs/cli/roles#create). Roles created in the Neon Console or API, and roles created with the CLI or MCP Server without an access level, are members of [`neon_superuser`](https://neon.com/docs/manage/roles#the-neonsuperuser-role), which can read all data, so pinning one of those roles doesn't limit what the agent can read. See [Manage database access](https://neon.com/docs/manage/database-access) for least-privilege role examples. - `role_name` arguments that name a different role are rejected, and a role that cannot log in fails the call without falling back to the owner. - `get_connection_string` is not available on a pinned connection. - The role applies to SQL only. Combine it with `readonly=true` and `category` to limit Management API tools too. - With OAuth, `roleName` on the URL is fixed when you authorize. With the plain `https://mcp.neon.tech/mcp` URL, enter the role in the optional **Postgres role** field on the authorization page instead. ## MCP security guidance 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 To limit what an agent can do, combine [read-only mode](https://neon.com/docs/ai/neon-mcp-server#read-only-mode), a [Postgres role](https://neon.com/docs/ai/neon-mcp-server#postgres-role) with limited grants, and [category filtering](https://neon.com/docs/ai/neon-mcp-server#category-filtering). ### Check the authorization page When you connect with OAuth, the authorization page shows where the sign-in returns before you click **Approve**, for example "Returns to claude.ai". Approve only when that matches the client you're connecting: - **Returns to an app on this computer:** The sign-in returns to a `localhost` or `127.0.0.1` address. Continue only if you started the sign-in from an app on your computer. - **App identity published at a host:** Clients such as Claude, ChatGPT, Codex, VS Code, Zed, GitHub Copilot CLI, and Antigravity identify themselves with a [Client ID Metadata Document](https://modelcontextprotocol.io/specification/2026-07-28/basic/authorization/client-registration), an `https` URL that describes the client. The page names the host that published that document, such as `claude.ai`. This confirms who controls the client ID, not which app is behind it. Clients that don't support metadata documents register through dynamic client registration and don't show an app identity line. Select **App details** to see the client's website and every registered redirect URI. ### Allowlist IP addresses The hosted Neon MCP Server (`mcp.neon.tech`) connects to your Neon databases from the following static IP addresses: - `34.192.103.46` - `23.22.233.166` If [IP Allow](https://neon.com/docs/introduction/ip-allow) is enabled on your project, add these addresses to your allowlist so the MCP server can connect. ## Database diagnostics When you ask why a branch is slow, large, or behind, the MCP server can run `inspect_database` instead of inventing catalog SQL. It exposes the same 15 read-only checks as [`neon inspect db`](https://neon.com/docs/cli/inspect): table and index sizes, unused indexes, sequential scans, long-running and stalled queries and locks, heavy and frequent statements, cache hit rate and working set, autovacuum and bloat, and replication state. The `stalled-queries` check reports active queries running longer than 30 seconds, with their waits, blockers, parallel workers, query IDs, and query text. Pick a check with the `check` parameter (for example `table-sizes` or `unused-indexes`). The tool runs inside a read-only transaction, so it works with [`?readonly=true`](https://neon.com/docs/ai/neon-mcp-server#read-only-mode). It belongs to the `querying` category, not `observability`. Some checks need [`pg_stat_statements`](https://neon.com/docs/extensions/pg_stat_statements) or the [`neon`](https://neon.com/docs/extensions/neon) extension; the tool reports that and asks before suggesting installation. ## Available tools Tools are grouped into categories. Use the `?category=` URL parameter to restrict which categories are active. You can pass it more than once to enable multiple categories. | Category | What it enables | | --------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | Project management (`projects`) | List, create, describe, and delete projects; count projects; get project and branch consumption; list organizations | | Branch management (`branches`) | Create, reset, and delete branches; manage Postgres roles and databases | | Compute endpoints (`endpoints`) | List, create, start, suspend, and restart branch computes | | Snapshots (`snapshots`) | Create, restore, and schedule snapshots | | Schema (`schema`) | Inspect tables and columns; compare schemas | | SQL (`querying`) | Execute queries and transactions; apply schema changes on a temporary branch; run the same diagnostics as `neon inspect db` | | Managed Better Auth (`neon_auth`) | Provision Auth; configure branch settings (localhost access, email and password, email provider, plugins, webhooks); manage OAuth providers, the OAuth provider plugin and its clients, trusted domains, and users | | Neon Data API (`data_api`) | Enable, update, and disable the Data API for a branch | | Observability (`observability`) | Query function and storage logs; check AI Gateway availability | | Documentation (`docs`) | Search and read Neon docs, the API reference, guides, the PostgreSQL tutorial, the blog, and the changelog from within your assistant (no OAuth required) | | Functions (`functions`) | List, deploy, update, and delete Neon Functions | | Object storage (`storage`) | Manage buckets and objects; create presigned URLs | | Realtime (`realtime`) | Enable and disable Realtime for a branch; get and rotate its secret | Search and navigation tools (search across projects, fetch resource details by ID) are available by default but disabled in [project-scoped mode](https://neon.com/docs/ai/neon-mcp-server#project-scoped-mode). Schema tools accept schema-qualified table names, such as `crm.contacts`. An unqualified name resolves against the database `search_path`, which defaults to the `public` schema. **Note:** The `observability` tools query [Neon Functions logs](https://neon.com/docs/compute/functions/logs) and [object storage logs](https://neon.com/docs/storage/logs), which are part of the Neon backend, currently available in AWS US East (Ohio) (`aws-us-east-2`), AWS US East (N. Virginia) (`aws-us-east-1`), AWS Europe (Frankfurt) (`aws-eu-central-1`), and AWS Asia Pacific (Singapore) (`aws-ap-southeast-1`). Support is expanding toward [all regions](https://neon.com/docs/introduction/regions). Log querying returns results only for projects in a supported region. Database diagnostics via `inspect_database` are under `querying`, not `observability`. ## Legacy transports ### Deprecated local stdio **Important:** The local stdio package (`@neondatabase/mcp-server-neon`) is deprecated. Use the hosted server at `https://mcp.neon.tech/mcp`. If your client only supports local stdio servers, put one of these in the client config so [`mcp-remote`](https://www.npmjs.com/package/mcp-remote) bridges to Streamable HTTP. **OAuth:** ```json { "mcpServers": { "Neon": { "command": "npx", "args": ["-y", "mcp-remote@latest", "https://mcp.neon.tech/mcp"] } } } ``` **API key:** ```json { "mcpServers": { "Neon": { "command": "npx", "args": [ "-y", "mcp-remote@latest", "https://mcp.neon.tech/mcp", "--header", "Authorization:${NEON_AUTH_HEADER}" ], "env": { "NEON_AUTH_HEADER": "Bearer " } } } } ``` ### Retired HTTP+SSE transport **Important:** The hosted Neon MCP Server uses Streamable HTTP at `https://mcp.neon.tech/mcp`. The older HTTP+SSE endpoints (`https://mcp.neon.tech/sse` and `/message`) are retired and return `410 Gone`. If your client still points at `/sse`, change the URL to `https://mcp.neon.tech/mcp`. If your client only supports local stdio servers, bridge to Streamable HTTP with [`mcp-remote`](https://www.npmjs.com/package/mcp-remote): ```json { "mcpServers": { "Neon": { "command": "npx", "args": ["-y", "mcp-remote@latest", "https://mcp.neon.tech/mcp"] } } } ``` ## Troubleshooting ### Client still points at the SSE endpoint The HTTP+SSE endpoints (`https://mcp.neon.tech/sse` and `/message`) are retired and return `410 Gone`. Point your client at `https://mcp.neon.tech/mcp` instead. See [Retired HTTP+SSE transport](https://neon.com/docs/ai/neon-mcp-server#retired-sse). ### Client doesn't support remote servers If your client only supports local (stdio) servers, bridge to the hosted server with `mcp-remote`. See [Deprecated local stdio](https://neon.com/docs/ai/neon-mcp-server#deprecated-stdio). ### OAuth error: invalid redirect uri When you use OAuth with the hosted server, you might see this error: ```json {"code":"invalid_request","error":"invalid redirect uri"} ``` This typically means the cached OAuth credentials are stale. To fix it: 1. Remove the MCP authentication cache directory: ```bash rm -rf ~/.mcp-auth ``` 2. Restart your MCP client. 3. Sign in again when the OAuth flow starts. ## Resources - [MCP Protocol](https://modelcontextprotocol.org) - [Neon API Reference](https://neon.com/docs/reference/api) - [Neon API Keys](https://neon.com/docs/manage/api-keys#creating-api-keys) - [Neon MCP server GitHub](https://github.com/neondatabase/mcp-server-neon) - [Get started with Claude Code and Neon MCP Server](https://neon.com/guides/claude-code-mcp-neon) - [Get started with Cursor and the Neon MCP Server](https://neon.com/guides/cursor-mcp-neon) - [Get started with Claude Desktop and Neon MCP Server](https://neon.com/guides/neon-mcp-server) --- [Document source](https://neon.com/docs/ai/semantic-kernel.md) --- > Summary: Semantic Kernel is Microsoft's open-source SDK for building RAG and agentic AI workflows in .NET (C#), and this page shows how to connect it to Neon Postgres using the `Microsoft.SemanticKernel.Connectors.Postgres` NuGet package and the `pgvector` extension as a vector store. Use this page when you need to initialize a `PostgresVectorStore`, generate embeddings with Azure OpenAI, or run chat-completion queries against a Neon-backed vector index from a C# application. The guide covers the full pipeline: NpgsqlDataSourceBuilder setup, embedding generation, and kernel-based prompt invocation, with a companion .NET RAG console app on GitHub. # Semantic Kernel Quickly build AI RAG and Agentic workflows with Semantic Kernel and Neon Last updated: 2026-06-05 [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 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;Password=mypass;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;Password=mypass;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", apiKey: "your-api-key" ); 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;Password=mypass;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", apiKey: "your-api-key" ); 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", apiKey: "your-api-key" ).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. - [RAG .NET console app (Azure OpenAI + Semantic Kernel)](https://github.com/neondatabase-labs/neon-semantic-kernel-examples): A .NET RAG example app built with Azure OpenAI and Semantic Kernel --- [Document source](https://neon.com/docs/auth/about.md) --- > Summary: Managed Better Auth is a managed authentication service built on Better Auth. It stores users, sessions, and OAuth configuration in your database under the neon_auth schema, compatible with Row Level Security. This page covers how it compares to self-hosting Better Auth, basic SDK usage, use cases, example applications, availability, pricing, and migration from Stack Auth. # About Managed Better Auth How Neon's managed Better Auth works, when to use it, and what it costs Last updated: 2026-10-30 Managed Better Auth is the managed authentication service in the Neon backend for apps and agents. It stores users, sessions, and auth configuration directly in your Neon database. When you branch your database, your entire auth state branches with it, so you can test real authentication workflows in preview environments. - **Identity lives in your database.** All authentication data is stored in the `neon_auth` schema, queryable with SQL and compatible with Row Level Security (RLS) policies. - **Zero server management.** It runs as a managed REST API service. Configure it in the Console and use the [client SDK](https://neon.com/docs/reference/javascript-sdk) or [server SDK](https://neon.com/docs/auth/reference/nextjs-server) in your app. - **Auth that branches with your data.** Test sign-up, login, password reset, and OAuth flows in isolated branches without touching production data. ## Set up with your AI editor The fastest way to connect your editor to Managed Better Auth is to run `npx neon@latest init` from your project root: ```bash npx neon@latest init ``` This command configures the [Neon MCP server](https://neon.com/docs/ai/neon-mcp-server) and installs **[Agent Skills](https://neon.com/docs/ai/agent-skills)** (`neon-postgres`) in your project. Together they help you set up Managed Better Auth in two ways: 1. **Configure Managed Better Auth on your branch (MCP).** After `init`, ask your assistant to enable and configure auth in natural language. The MCP server exposes: - `provision_neon_auth`: Enable Managed Better Auth on a branch - `add_auth_oauth_provider`, `add_auth_trusted_domain`, `update_auth_config`: Change Auth settings - `get_neon_auth_config`: Read the current configuration (secrets redacted) See [Available tools](https://neon.com/docs/ai/neon-mcp-server#available-tools) (`neon_auth`) for the full set. 2. **Add Managed Better Auth to your application (Agent Skills).** Skills teach your assistant how to install the SDK, environment variables, and routes for your framework. Use the quick start guides on this page, or ask your assistant directly. **Example prompt:** ```text Set up Managed Better Auth for my project. Enable Google OAuth and email/password sign-in, and set the application name to "My App". ``` You can also enable Managed Better Auth in the [Neon Console](https://console.neon.tech) (Project → Branch → Auth) and configure settings manually. ## Built on Better Auth Managed Better Auth is powered by [Better Auth](https://www.better-auth.com/), which means you get familiar APIs. You can use Better Auth UI components or call auth methods directly to build your own UI. Managed Better Auth runs Better Auth version **1.7.12**. Use `@neon/auth` **0.8.1 or later**, which uses a Better Auth 1.7.12 client. Apps on older `@neondatabase/auth` versions keep working, so you don't need to upgrade. If you use your own Better Auth client, use Better Auth 1.7 or later. ### When to use Managed Better Auth vs. self-hosting Better Auth Managed Better Auth is a managed authentication service built into Lakebase Postgres on Neon: - **Branch-aware authentication**: Every Neon branch gets its own isolated auth environment, so you can test authentication features without affecting your production branch. - **Built-in Data API integration**: JWT token validation for the Data API has native support for Managed Better Auth. - **No infrastructure to manage**: Managed Better Auth is deployed in the same region as your database, reducing latency without requiring you to run auth infrastructure. - **Shared OAuth credentials for testing**: Get started quickly with out-of-the-box Google OAuth credentials, eliminating the setup complexity for testing and prototyping. Self-hosting Better Auth makes sense if you need: - Flexibility in auth configuration: custom plugins, hooks, and options not yet supported by Managed Better Auth. - Full control over your auth code and the ability to run it inside your own infrastructure. For more details on the SDK differences between `@neon/auth` and `better-auth/client`, see [Why use @neon/auth over better-auth/client](https://github.com/neondatabase/neon-js/blob/main/packages/auth/neon-auth_vs_better-auth.md). As Managed Better Auth evolves, more Better Auth integrations and features will be added. Check the [roadmap](https://neon.com/docs/auth/roadmap) to see what's currently supported and what's coming next. ## Basic usage Enable Auth in the Neon Console, from the terminal with [`neon neon-auth enable`](https://neon.com/docs/cli/neon-auth#enable) or declaratively with [`neon config add auth`](https://neon.com/docs/cli/config#add), or [with your AI editor](https://neon.com/docs/auth/about#set-up-with-your-ai-editor), then add authentication to your app. **For Next.js (server-side):** See the [Next.js Server SDK reference](https://neon.com/docs/auth/reference/nextjs-server) for complete API documentation. ```typescript filename="lib/auth/server.ts" import { createNeonAuth } from '@neon/auth/next/server'; export const auth = createNeonAuth({ baseUrl: process.env.NEON_AUTH_BASE_URL!, cookies: { secret: process.env.NEON_AUTH_COOKIE_SECRET! }, }); ``` ```typescript filename="app/api/auth/[...path]/route.ts" import { auth } from '@/lib/auth/server'; export const { GET, POST, PUT, PATCH, DELETE } = auth.handler(); ``` **For React/Vite (client-side):** See the [Client SDK reference](https://neon.com/docs/reference/javascript-sdk) for complete API documentation. If you want one client for both Managed Better Auth and the Data API, initialize `createClient()` from a single Neon URL as shown in [`createClient()` initialization](https://neon.com/docs/reference/javascript-sdk#initializing). ```typescript filename="src/auth.ts" import { createAuthClient } from '@neon/auth'; import { BetterAuthReactAdapter } from '@neon/auth/react/adapters'; // credentials: 'include' sends the session cookie on cross-origin requests. export const authClient = createAuthClient(import.meta.env.VITE_NEON_AUTH_URL, { adapter: BetterAuthReactAdapter({ fetchOptions: { credentials: 'include' } }), }); ``` For pre-built sign-in and sign-up forms, add [Better Auth UI](https://neon.com/docs/auth/reference/ui-components) with `npx shadcn@latest add @better-auth-ui/auth` and pass the client to its `AuthProvider`: ```tsx filename="src/App.tsx" import { getSafeRedirectTo } from '@better-auth-ui/core'; import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; import { AuthProvider } from '@/components/auth/auth-provider'; import { Auth } from '@/components/auth/auth'; import { Toaster } from '@/components/ui/sonner'; import { authClient } from './auth'; const queryClient = new QueryClient(); export default function App() { return ( { const path = getSafeRedirectTo(to, window.location.origin); window.location.assign(path.startsWith('//') ? '/' : path); }} Link={({ to: _to, ...props }) => } > ); } ``` `navigate` checks the target because the components pass it the URL's `?redirectTo=` value after sign-in; see [Validate redirect targets](https://neon.com/docs/auth/reference/ui-components#validate-redirect-targets). ## Use cases - **Production authentication** Use Managed Better Auth as the identity system for your app. Store users, sessions, and OAuth configuration directly in Postgres, and pair with RLS for secure, database-centric access control. - **Preview environments** Test full authentication flows in Vercel previews with real users and sessions - **Multi-tenant SaaS** Test complex org and role hierarchies safely in isolated branches - **CI/CD workflows** Run end-to-end auth tests without touching production. The [Neon Create Branch GitHub Action](https://github.com/marketplace/actions/neon-create-branch-github-action) supports retrieving branch-specific auth URLs for testing authentication flows in GitHub Actions workflows. - **Development workflows** Spin up complete environments instantly with database and auth together See [Branching authentication](https://neon.com/docs/auth/branching-authentication) for details on how auth branches with your database. ## Example applications Beyond the quick starts on this site, the [neondatabase/neon-js](https://github.com/neondatabase/neon-js) monorepo ships **more runnable Managed Better Auth and `neon-js` samples** under [`examples/`](https://github.com/neondatabase/neon-js/tree/main/examples), including plugin demos (see [Plugins](https://neon.com/docs/auth/guides/plugins#example-applications)), Next.js and React apps, cross-subdomain setups, alternative UI stacks, and Data API patterns. Each folder includes its own README (many workflows use **bun** from the repository root). Browse there when you want a full project to clone next to the guides here. ## Availability Managed Better Auth is currently available for AWS regions only. Azure support is not yet available. Managed Better Auth does not currently support projects with [IP Allow](https://neon.com/docs/manage/projects#configure-ip-allow) or [Private Networking](https://neon.com/docs/guides/neon-private-networking) enabled. ## Pricing Managed Better Auth is included in all Neon plans based on Monthly Active Users (MAU): - **Free**: Up to 60,000 MAU per project - **Launch**: Up to 1M MAU per project - **Scale**: Up to 1M MAU per project An MAU (Monthly Active User) is a unique user who authenticates at least once during a monthly billing period. If you need more than 1M MAU, request an increase in the [console feedback form](https://console.neon.tech/app/settings?modal=feedback\&modalparams=%22Neon%20auth%20limit%20increase%22). See [Neon plans](https://neon.com/docs/introduction/plans#auth) for more details. ## Migration from Stack Auth If you're using legacy Neon Auth (Stack Auth), your version will continue to work. When you're ready to migrate to Managed Better Auth, see our [migration guide](https://neon.com/docs/auth/migrate/from-legacy-auth). --- [Document source](https://neon.com/docs/auth/authentication-flow.md) --- > Summary: Managed Better Auth authentication flow traces every step from SDK call to HTTP-only session cookie, JWT issuance, and writes to the neon_auth schema, covering email sign-in, sign-up, and OAuth providers such as Google and GitHub. Use this page to understand what happens under the hood during login, debug session or token problems, or wire auth.uid() into Row-Level Security policies via the Data API. All auth state lands directly in your Neon database with no sync delay, and each branch holds isolated auth data. # Authentication flow Understanding the complete sign-in and sign-up process Last updated: 2026-11-05 This guide explains the authentication flow: how sign-in works from SDK call to session creation. **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](https://neon.com/docs/auth/guides/email-verification) via verification link or verification code. ## Architecture overview Managed Better 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 Managed Better 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: ## User signs in Your application calls the SDK's sign-in method: ```typescript const { data, error } = await client.auth.signIn.email({ email: 'user@example.com', password: 'password', }); ``` The SDK posts to `{NEON_AUTH_BASE_URL}/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: "user@example.com", emailVerified: true, // ... other user fields } } } ``` ## Session cookie is set The Auth service sets an HTTP-only cookie (`__Secure-neon-auth.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-neon-auth.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 the `/token` endpoint separately; the SDK handles this behind the scenes. **What's in the JWT:** ```json { "sub": "dc42fa70-09a7-4038-a3bb-f61dda854910", // User ID "email": "user@example.com", "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 ` 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 ## Sign-up flow The sign-up flow creates a new user: ```typescript const { data, error } = await client.auth.signUp.email({ email: 'newuser@example.com', password: 'securepassword', name: 'New User', }); ``` The SDK posts to `{NEON_AUTH_BASE_URL}/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. **Note:** By default, anyone can sign up for your application. To add an additional verification layer, enable email verification (see [Email Verification](https://neon.com/docs/auth/guides/email-verification)). Built-in signup restrictions are coming soon. ## OAuth flow OAuth authentication (Google, GitHub, Vercel, Microsoft, Apple, 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 Managed Better 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](https://neon.com/docs/data-api/get-started), JWT tokens from Managed Better Auth are validated automatically. Two helper functions make the user ID available to RLS policies. Use the one that matches your column type: - `auth.user_id()`: returns `sub` as `text` - `auth.uid()`: returns `sub` as `uuid` (returns `NULL` if `sub` isn't a valid UUID) The Data API also works with [other authentication providers](https://neon.com/docs/data-api/custom-authentication-providers) that issue JWTs, such as Auth0, Clerk, and Firebase. **Example RLS policy:** ```sql CREATE POLICY "Users can view own posts" ON posts FOR SELECT TO authenticated USING (user_id = auth.user_id()); ``` **Learn more about securing your data:** - [Row-Level Security with Neon](https://neon.com/docs/guides/row-level-security) - [Simplify RLS with Drizzle](https://neon.com/docs/guides/rls-drizzle) ## What's next - [Branching Authentication](https://neon.com/docs/auth/branching-authentication): How auth works with database branches - [Row Level Security](https://neon.com/docs/guides/row-level-security): Secure your data with RLS policies --- [Document source](https://neon.com/docs/auth/branching-authentication.md) --- > Summary: Managed Better Auth stores users, sessions, and configuration in the database's neon_auth schema, so authentication data is automatically cloned when you create a branch, giving each branch its own fully isolated auth environment. Use this page when you need to safely test OAuth providers, RBAC policy changes, password reset flows, or full application refactors without touching production users. Each branch gets a unique Auth API URL, and sessions and tokens do not cross between branches. # Branching authentication How authentication works with Neon database branches Last updated: 2026-09-16 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 Managed Better Auth's unique features is native support for [database branching](https://neon.com/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. **Info:** Managed Better Auth branching is also supported via API. See the [Managed Better Auth API reference](https://neon.com/docs/reference/api/auth/get-neon-auth) for a full set of REST API endpoints. ## How it works When you create a [database branch](https://neon.com/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 (for example, 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: alice@co.com ├── New user: test@co.com ├── 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) ``` **Note:** Managed Better Auth uses your branch's default database, typically `neondb`, when you don't specify a database. You can select another database in the same branch when you enable Auth through the API by setting `database_name`. Managed Better Auth requires a read-write endpoint. ## 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 supports several useful 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 Managed Better 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://neon.com/docs/reference/api/auth/add-branch-neon-auth-trusted-domain). 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. **Tip:** See the [GitHub Actions guide](https://neon.com/docs/guides/branching-github-actions) for instructions on how to automate branch creation for preview environments. ### 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 Managed Better 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 (for example, 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. **Note: 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. ### 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 Managed Better 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. **The branch provides a full production-like environment without touching 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. Agents can spin up full-stack environments (Database + Auth + Compute) in seconds and run autonomous test loops against real user-facing security flows, with no manual setup. **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. ## What's Next - [Database Branching](https://neon.com/docs/introduction/branching): Learn about database branching fundamentals - [Branching with CLI](https://neon.com/docs/guides/branching-neon-cli): Create and manage branches with CLI - [Branching with GitHub Actions](https://neon.com/docs/guides/branching-github-actions): Automate branching in CI/CD - [Row-Level Security](https://neon.com/docs/guides/row-level-security): Secure data with RLS --- [Document source](https://neon.com/docs/auth/guides/configure-domains.md) --- > Summary: Managed Better Auth's trusted domain allowlist restricts OAuth and email verification redirects to domains you explicitly approve, blocking unauthorized redirects. Add exact production origins (https://myapp.com) or wildcard patterns (https://*.preview.vercel.app) in Console > Auth > Configuration > Domains. Localhost ports are pre-approved and need no entry. # Configure trusted domains Add your application domains to enable secure authentication redirects Last updated: 2026-11-05 Add your application domains to Managed Better Auth's allowlist to enable OAuth and email verification redirects in production. ## Why domains are required Managed Better 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. The same list decides which `Origin` headers the Auth API accepts, so sign-in and sign-up requests from an origin that isn't on it fail with `INVALID_ORIGIN`. See [Origin errors](https://neon.com/docs/auth/troubleshooting#origin-errors). ## Add a domain **Console** 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. **CLI** Add a domain with [`neon neon-auth domain add`](https://neon.com/docs/cli/neon-auth#domain-add): ```bash neon neon-auth domain add https://myapp.com ``` Use `neon neon-auth domain list` and `neon neon-auth domain delete` to view and remove entries. **API** Send a `POST` request to the [add trusted domain](https://neon.com/docs/reference/api/auth/add-branch-neon-auth-trusted-domain) endpoint. Replace `{project_id}` and `{branch_id}` with your project and branch IDs. ```bash curl -X POST 'https://console.neon.tech/api/v2/projects/{project_id}/branches/{branch_id}/auth/domains' \ -H 'Authorization: Bearer $NEON_API_KEY' \ -H 'Content-Type: application/json' \ -d '{"domain": "https://myapp.com", "auth_provider": "better_auth"}' ``` Use [`GET`](https://neon.com/docs/reference/api/auth/list-branch-neon-auth-trusted-domains) on the same path to list domains, and [`DELETE`](https://neon.com/docs/reference/api/auth/delete-branch-neon-auth-trusted-domain) to remove them. See [Manage Managed Better Auth via the API](https://neon.com/docs/auth/guides/manage-auth-api#related-auth-endpoints) for the full set of auth endpoints. **Note:** Include the protocol (`https://`) and omit trailing slashes. For example: `https://myapp.com` not `https://myapp.com/` ## 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) ## Wildcard domains for previews For preview environments with dynamic hostnames (for example Vercel preview deployments), you can add a **wildcard trusted domain** such as `https://*.my-app-preview.vercel.app`. One entry can match every preview under that pattern instead of adding hosts one by one. Use the same rules as fixed domains: include `https://` (or `http://` where appropriate) and omit trailing slashes after the pattern. **Note:** Wildcard patterns apply to the hostname segment you replace with `*`. Production apex domains (for example `https://myapp.com`) are usually still added as exact entries unless your wildcard covers them. ## 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](https://neon.com/docs/auth/production-checklist) - Complete setup for launch --- [Document source](https://neon.com/docs/auth/guides/customize-emails.md) --- > Summary: Managed Better Auth email customization lets you intercept OTP code and magic link delivery events via webhooks and send fully branded emails through your own provider (Resend, SendGrid, Postmark, or any SMTP service) instead of Neon's default shared-branded emails. Use this page when you need custom sender addresses, HTML templates, multi-language support, or your own branding for sign-in, email-verification, and password-reset emails. Dashboard-based email templates are not yet available; webhook-based delivery is the current customization path. # Customize emails Custom branding, content, and delivery for Managed Better Auth emails Last updated: 2026-09-16 Managed Better Auth sends verification codes, magic links, and password reset emails using its built-in email provider. By default, emails use shared Neon branding and your Neon project name as the main header. To make emails recognizable to users, update the Application Name in your [Auth settings](https://neon.com/docs/auth/production-checklist#application-name) to match your app's public-facing name. For deeper customization, use webhooks to intercept email events and send fully branded emails through your preferred provider. Dashboard-based email templates aren't available yet, but they're planned for a future release. If you only need a custom sender address without changing the email content, you can configure a custom SMTP provider instead (see the [Auth production checklist](https://neon.com/docs/auth/production-checklist#email-provider)). ## How it works Managed Better Auth fires two events when it needs to send an email to a user: | Event | Triggers when | Without webhook | | ----------------- | -------------------------------------------------- | ----------------------------------------- | | `send.otp` | A verification code needs delivery | Neon sends the code via its default email | | `send.magic_link` | A magic link or password reset link needs delivery | Neon sends the link via its default email | When you subscribe to either event, Managed Better Auth **skips its default email** and calls your webhook handler instead. Your handler receives the code or link in the payload and is responsible for sending it through Resend, SendGrid, Postmark, or any email provider you choose. See the [Webhooks reference](https://neon.com/docs/auth/guides/webhooks) for configuration, payload structure, signature verification, and retry behavior. ## What you can customize Using webhooks, you can customize every aspect of the email experience: - **Sender identity:** Use your own domain and sender name instead of `auth@mail.myneon.app` - **App name and branding:** Replace Neon's default branding with your app's logo, colors, and name - **Subject line and body:** Write custom HTML templates with your own copy - **Verification links:** Wrap the link from the `send.magic_link` payload in your branded email template, or build a custom redirect URL using the raw `token` - **Multi-language support:** Detect the user's locale and deliver emails in their language - **Delivery channel:** Send codes via email, SMS (with the [Phone Number plugin](https://neon.com/docs/auth/guides/plugins/phone-number)), or both ## Event payloads When your webhook receives a `send.otp` or `send.magic_link` event, the payload includes the user's email and name, the OTP code or magic link URL, the type of email being sent, and the expiration time. ### `send.otp` Your handler receives a 6-digit OTP code, the OTP type (`sign-in`, `email-verification`, or `forget-password`), and the user's email. Send it through your email provider. ```json { "event_id": "xxx-yyy-zzz", "event_type": "send.otp", "timestamp": "20xx-xx-xxTxx:xx:xx.xxxZ", "context": { "endpoint_id": "ep-xxx", "project_name": "Your App Name" }, "user": { "name": "User Name", "email": "user@email.com", "image": null, "role": "user", "banned": false, "id": "user-id", "email_verified": true, "created_at": "20xx-xx-xxTxx:xx:xx.xxxZ", "updated_at": "20xx-xx-xxTxx:xx:xx.xxxZ", "ban_reason": null, "ban_expires": null }, "event_data": { "otp_code": "123456", "otp_type": "sign-in", "expires_at": "20xx-xx-xxTxx:xx:xx.xxxZ", "ip_address": "IP_ADDRESS_OF_USER", "user_agent": "USER_AGENT_OF_USER" } } ``` ### `send.magic_link` Your handler receives a full verification URL and a raw token. The `link_type` is `sign-in`, `email-verification`, or `forget-password`. Wrap the link in your branded email template. ```json { "event_id": "xxx-yyy-zzz", "event_type": "send.magic_link", "timestamp": "20xx-xx-xxTxx:xx:xx.xxxZ", "context": { "endpoint_id": "ep-xxx", "project_name": "Your App Name" }, "user": { "email": "user@email.com" }, "event_data": { "link_type": "sign-in", "link_url": "https://magic-link-url", "token": "raw-token-value", "expires_at": "20xx-xx-xxTxx:xx:xx.xxxZ", "ip_address": "IP_ADDRESS_OF_USER", "user_agent": "USER_AGENT_OF_USER" } } ``` ## Example handler Before your handler can receive events, you must register its endpoint. Follow the [Webhooks guide](https://neon.com/docs/auth/guides/webhooks) to configure your webhook URL and subscribe to the `send.otp` and `send.magic_link` events. Here's an example Next.js API route that verifies the webhook signature, handles the `send.otp` and `send.magic_link` events, and sends emails through Resend. ```ts import crypto from 'node:crypto'; import { NextRequest, NextResponse } from 'next/server'; import { Resend } from 'resend'; const resend = new Resend(process.env.RESEND_API_KEY); async function verifyWebhook(rawBody: string, headers: Headers) { const signature = headers.get('x-neon-signature'); const kid = headers.get('x-neon-signature-kid'); const timestamp = headers.get('x-neon-timestamp'); if (!signature || !kid || !timestamp) { throw new Error('Missing required Neon webhook headers'); } // 1. Fetch JWKS and find the matching key const res = await fetch(`${process.env.NEON_AUTH_BASE_URL}/.well-known/jwks.json`); const jwks = await res.json(); const jwk = jwks.keys.find((k: { kid: string }) => k.kid === kid); if (!jwk) throw new Error(`Key ${kid} not found in JWKS`); // 2. Import the Ed25519 public key const publicKey = crypto.createPublicKey({ key: jwk, format: 'jwk' }); // 3. Parse detached JWS (header..signature) const [headerB64, emptyPayload, signatureB64] = signature.split('.'); if (emptyPayload !== '') throw new Error('Expected detached JWS format'); // 4. Reconstruct signing input (standard JWS, double base64url encoding) const payloadB64 = Buffer.from(rawBody, 'utf8').toString('base64url'); const signaturePayload = `${timestamp}.${payloadB64}`; const signaturePayloadB64 = Buffer.from(signaturePayload, 'utf8').toString('base64url'); const signingInput = `${headerB64}.${signaturePayloadB64}`; // 5. Verify Ed25519 signature const isValid = crypto.verify( null, Buffer.from(signingInput), publicKey, Buffer.from(signatureB64, 'base64url') ); if (!isValid) throw new Error('Invalid webhook signature'); // 6. Check timestamp freshness (recommended) const ageMs = Date.now() - parseInt(timestamp, 10); if (ageMs > 5 * 60 * 1000) throw new Error('Webhook timestamp too old'); return JSON.parse(rawBody); } export async function POST(request: NextRequest) { const rawBody = await request.text(); const payload = await verifyWebhook(rawBody, request.headers); const { event_type, event_data, user, context } = payload; const appName = context.project_name || 'My App'; if (event_type === 'send.otp') { await resend.emails.send({ from: 'My App ', to: user.email, subject: 'Your verification code', html: `

Welcome to ${appName}

Your code: ${event_data.otp_code}

`, }); } if (event_type === 'send.magic_link') { await resend.emails.send({ from: 'My App ', to: user.email, subject: 'Your sign-in link', html: `

Welcome to ${appName}

Sign in

`, }); } return NextResponse.json({ success: true }); } ``` You can customize your emails to reflect your brand by adding your logo and using your brand colors in the HTML templates. --- [Document source](https://neon.com/docs/auth/guides/email-verification.md) --- > Summary: Managed Better Auth email verification confirms that users own the email address they register with, using either a numeric OTP code (works with shared or custom email providers) or a click-through verification link (requires a custom email provider). Both methods expire after 15 minutes and can be resent; verification can be configured as required or optional in the Neon Console, controlling whether unverified users can sign in. # Email verification Verify user email addresses during sign-up or account creation Last updated: 2026-11-05 Email verification ensures users own the email addresses they register with. The application name shown in these emails is configurable per branch. See [Application name](https://neon.com/docs/auth/production-checklist#application-name). Managed Better 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 **Note:** Verification links require a [custom email provider](https://neon.com/docs/auth/production-checklist#email-provider). If you're using the shared email provider, use verification codes instead. ## Enable email verification **Console** In your project's **Settings** → **Better Auth** page, enable **Sign-up with Email** and **Verify at Sign-up**. Choose your verification method. ![Email verification settings in Neon Console](https://neon.com/docs/auth/email-verification-settings.png) **CLI** Enable email and password authentication with verification required using [`neon neon-auth config email-password update`](https://neon.com/docs/cli/neon-auth#config-email-password-update): ```bash neon neon-auth config email-password update --enabled --require-email-verification ``` **API** Update the configuration with the [Update email and password configuration](https://neon.com/docs/reference/api/auth/update-neon-auth-email-and-password-config) endpoint. Replace `{project_id}` and `{branch_id}` with your project and branch IDs: ```bash curl -X PATCH 'https://console.neon.tech/api/v2/projects/{project_id}/branches/{branch_id}/auth/email_and_password' \ -H 'Authorization: Bearer $NEON_API_KEY' \ -H 'Content-Type: application/json' \ -d '{ "enabled": true, "require_email_verification": true }' ``` ## Verification links Verification links require a custom email provider. See [Email provider configuration](https://neon.com/docs/auth/production-checklist#email-provider) to set this up. When a user clicks the verification link in their email, the Managed Better 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 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 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 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 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 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 When `step` is `'verify'`, show the verification form: ```jsx filename="src/App.jsx" if (step === 'verify') { return (

Verify Your Email

Enter the code sent to {email}

setCode(e.target.value)} required />
{message &&

{message}

}
); } ``` ### 4. Switch to verification after sign-up 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 } ```
Complete example: App.jsx with verification codes 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(''); const [step, setStep] = useState('auth'); // 'auth' or 'verify' const [code, setCode] = useState(''); const [isSignUp, setIsSignUp] = useState(true); 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; } if (data?.user && !data.user.emailVerified) { setMessage('Check your email for a verification code'); setStep('verify'); // Switch to verification form } else { const sessionResult = await authClient.getSession(); if (sessionResult.data?.session && sessionResult.data?.user) { setSession(sessionResult.data.session); setUser(sessionResult.data.user); } } }; 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); } }; const handleVerify = async (e) => { e.preventDefault(); setMessage(''); try { const { data, error } = await authClient.emailOtp.verifyEmail({ email, otp: code, }); if (error) throw error; if (data?.session) { setSession(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'); } }; const handleSignOut = async () => { await authClient.signOut(); setSession(null); setUser(null); }; if (loading) return
Loading...
; if (session && user) { return (

Logged in as {user.email}

); } if (step === 'verify') { return (
{' '}

Verify Your Email

Enter the code sent to {email}

{' '} setCode(e.target.value)} required />{' '}
{' '} {message &&

{message}

}
); } return (

{isSignUp ? 'Sign Up' : 'Sign In'}

{message &&

{message}

}
setEmail(e.target.value)} required /> setPassword(e.target.value)} required />

); } ```
## 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**, which is the default, users can sign in immediately but their `emailVerified` field remains `false` until verified. If your app links a signed-in user to existing data by matching their email address, check that `emailVerified` is `true` first. Otherwise, anyone who signs up with that address gets that data. --- [Document source](https://neon.com/docs/auth/guides/manage-auth-api.md) --- > Summary: Managed Better Auth REST API operations for enabling (POST), retrieving (GET), updating (PATCH), and disabling (DELETE) auth on a per-branch basis, with curl examples and a full response field reference. Use this page when automating auth provisioning or teardown: the enable response is the only call that returns `pub_client_key` and `secret_server_key`, and the `delete_data` flag on DELETE controls whether the `neon_auth` schema is permanently removed. Also covers related branch-scoped endpoints for OAuth providers, email configuration, domains, users, plugins, and webhooks, plus equivalent MCP tools for AI-editor workflows. # Manage Managed Better Auth via the API Enable, configure, and disable Managed Better Auth using the Neon API Last updated: 2026-10-09 You can manage Managed Better Auth programmatically using the [Neon API](https://neon.com/docs/reference/api), or from the terminal with the [Neon CLI](https://neon.com/docs/cli/neon-auth) (`neon neon-auth`), which wraps these same operations. You can also enable and configure Managed Better Auth from an AI editor using the [Neon MCP server](https://neon.com/docs/ai/neon-mcp-server#available-tools) (`provision_neon_auth`, `update_auth_config`, `add_auth_oauth_provider`, `get_neon_auth_config`). See [Set up with your AI editor](https://neon.com/docs/auth/about#set-up-with-your-ai-editor). **Note:** Managed Better Auth operates at the **branch level**. Each branch can have its own independent auth configuration, which means preview and development branches can have separate auth state from your production branch. ## Prerequisites - A [Neon API key](https://neon.com/docs/manage/api-keys) - A Neon project with at least one branch All requests use the base URL `https://console.neon.tech/api/v2` and require the `Authorization: Bearer $NEON_API_KEY` header. The `project_id` and `branch_id` values are returned when you [create a project](https://neon.com/docs/manage/projects#create-a-project-with-the-api) or [list branches](https://neon.com/docs/manage/branches#list-branches-with-the-api) via the API. ## Enable Managed Better Auth Send a `POST` request to enable Managed Better Auth on a branch: ```bash curl -X POST 'https://console.neon.tech/api/v2/projects/{project_id}/branches/{branch_id}/auth' \ -H 'Authorization: Bearer $NEON_API_KEY' \ -H 'Content-Type: application/json' \ -d '{"auth_provider": "better_auth"}' ``` Response (201 Created): ```json { "auth_provider": "better_auth", "auth_provider_project_id": "cab6949a-10e3-4d25-a879-512beed281e3", "pub_client_key": "", "secret_server_key": "", "jwks_url": "https://ep-example.neonauth.us-east-1.aws.neon.tech/neondb/auth/.well-known/jwks.json", "schema_name": "neon_auth", "table_name": "users_sync", "base_url": "https://ep-example.neonauth.us-east-1.aws.neon.tech/neondb/auth" } ``` The response includes: | Field | Description | | -------------------------- | --------------------------------------------------------------------------------------------------------- | | `auth_provider` | The configured provider (`better_auth`) | | `auth_provider_project_id` | Unique ID for the auth provider instance | | `pub_client_key` | Public client key (shown once at creation, may be empty for `better_auth`) | | `secret_server_key` | Secret server key (shown once at creation, may be empty for `better_auth`) | | `jwks_url` | JWKS endpoint for JWT verification | | `schema_name` | Database schema created for auth tables (`neon_auth`) | | `table_name` | Table name for synced user data (`users_sync`) | | `base_url` | Base URL of the auth service, used for SDK configuration and the interactive API reference (`/reference`) | **Important:** The enable response is the only time the API returns `pub_client_key` and `secret_server_key`. Store them securely. Subsequent `GET` requests do not include these fields. For client initialization examples that combine Managed Better Auth and the Data API from a single Neon URL, see [`createClient()` in the JavaScript SDK reference](https://neon.com/docs/reference/javascript-sdk#initializing). If Managed Better Auth is already enabled on the branch, this call returns an error. **Tip: Using a non-default database** By default, Managed Better Auth uses the branch's default database. To target a different database, add `database_name` to the request body: `{"auth_provider": "better_auth", "database_name": "my_other_db"}` ## Get Auth configuration Retrieve the current Managed Better Auth configuration for a branch: ```bash curl -X GET 'https://console.neon.tech/api/v2/projects/{project_id}/branches/{branch_id}/auth' \ -H 'Authorization: Bearer $NEON_API_KEY' ``` Response (200 OK): ```json { "auth_provider": "better_auth", "auth_provider_project_id": "cab6949a-10e3-4d25-a879-512beed281e3", "branch_id": "br-example-abc123", "db_name": "neondb", "created_at": "2026-02-26T04:29:05Z", "owned_by": "neon", "jwks_url": "https://ep-example.neonauth.us-east-1.aws.neon.tech/neondb/auth/.well-known/jwks.json", "base_url": "https://ep-example.neonauth.us-east-1.aws.neon.tech/neondb/auth", "name": "My App" } ``` ## Update auth configuration Update auth settings for a branch. Currently supports changing the application name shown in user-facing auth messages. Applies to Managed Better Auth integrations only. Defaults to the Neon project name. ```bash curl -X PATCH 'https://console.neon.tech/api/v2/projects/{project_id}/branches/{branch_id}/auth/config' \ -H 'Authorization: Bearer $NEON_API_KEY' \ -H 'Content-Type: application/json' \ -d '{"name": "My App"}' ``` Response (200 OK): ```json { "name": "My App" } ``` | Field | Description | | ------ | -------------------------------------------------------------- | | `name` | The name shown in user-facing auth messages (1-256 characters) | Each branch manages its own application name independently. You can also update this from **Settings** > **Better Auth** > **Project Info** in the Neon Console. ## Disable Managed Better Auth Send a `DELETE` request to disable Managed Better Auth on a branch: ```bash curl -X DELETE 'https://console.neon.tech/api/v2/projects/{project_id}/branches/{branch_id}/auth' \ -H 'Authorization: Bearer $NEON_API_KEY' \ -H 'Content-Type: application/json' \ -d '{"delete_data": true}' ``` Response (200 OK): Empty body. The `delete_data` field controls whether the system removes the `neon_auth` schema from your database: - **`true`**: Deletes the `neon_auth` schema and all auth tables (users, sessions, accounts). - **`false`** (default): Disables the auth service but leaves the schema and data intact. You can re-enable later without losing user data. **Warning:** Setting `delete_data` to `true` permanently removes all auth data from the database. You cannot undo this. ## Related auth endpoints The Neon API also provides endpoints for managing auth configuration at the branch level. These are available at `https://console.neon.tech/api/v2/projects/{project_id}/branches/{branch_id}/auth/...`: | Endpoint | Methods | Description | | ------------------------- | ------------------------ | ---------------------------------------------------------------------------------------------------------------- | | `/domains` | GET, POST, DELETE | Manage trusted redirect domains | | `/oauth_providers` | GET, POST, PATCH, DELETE | Configure OAuth providers (Google, GitHub, etc.) | | `/email_provider` | GET, PATCH | Configure the email provider | | `/email_and_password` | GET, PATCH | Configure email/password authentication | | `/users` | POST, DELETE, PUT | Create, delete, and manage user roles | | `/plugins` | GET, PATCH | View and configure [auth plugins](https://neon.com/docs/auth/guides/plugins) | | `/plugins/magic-link` | PATCH | Configure the [Magic Link plugin](https://neon.com/docs/auth/guides/plugins/magic-link) | | `/plugins/phone-number` | GET, PATCH | Configure the [Phone Number plugin](https://neon.com/docs/auth/guides/plugins/phone-number) | | `/plugins/oauth-provider` | GET, PATCH | Configure the [OAuth provider plugin](https://neon.com/docs/auth/guides/plugins/oauth-provider) | | `/oauth-provider/clients` | GET, POST, PATCH, DELETE | Manage [OAuth clients](https://neon.com/docs/auth/guides/plugins/oauth-provider#create-and-manage-oauth-clients) | | `/webhooks` | GET, PUT | Configure webhook notifications | | `/allow_localhost` | GET, PATCH | Toggle localhost access for development | | `/config` | PATCH | Update auth configuration (application name) | | `/send_test_email` | POST | Send a test email to verify email configuration | For full request/response details on these endpoints, see the [interactive API Reference](https://neon.com/docs/reference/api). For the OAuth provider, see the reference for [retrieving](https://neon.com/docs/reference/api/auth/get-neon-auth-o-auth-provider-plugin) and [updating](https://neon.com/docs/reference/api/auth/update-neon-auth-o-auth-provider-plugin) the plugin configuration, and for [listing](https://neon.com/docs/reference/api/auth/list-neon-auth-o-auth-clients), [creating](https://neon.com/docs/reference/api/auth/create-neon-auth-o-auth-client), [retrieving](https://neon.com/docs/reference/api/auth/get-neon-auth-o-auth-client), [updating](https://neon.com/docs/reference/api/auth/update-neon-auth-o-auth-client), [deleting](https://neon.com/docs/reference/api/auth/delete-neon-auth-o-auth-client), and [rotating the secret of](https://neon.com/docs/reference/api/auth/rotate-neon-auth-o-auth-client-secret) OAuth clients. **Tip: TypeScript SDK** You can also manage Managed Better Auth using the [Neon TypeScript SDK](https://neon.com/docs/reference/typescript-sdk). --- [Document source](https://neon.com/docs/auth/guides/password-reset.md) --- > Summary: Managed Better Auth password reset sends a verification link to the user's email and requires email authentication to be enabled in project Settings. The pre-built `` and `` components handle the full forgot-password flow; reset links expire after 15 minutes, and the SDK `resetPasswordForEmail` method is not yet supported. An optional per-branch setting, `revoke_sessions_on_password_reset`, signs the user out of every existing session after a successful reset. # Password reset Allow users to reset forgotten passwords Last updated: 2026-11-05 Password reset allows users to securely reset forgotten passwords. Managed Better Auth supports password reset via verification links sent to the user's email address. ## Enable password reset In your project's **Settings** → **Better Auth** page, ensure **Sign-in with Email** is enabled. Password reset is automatically available when email authentication is enabled. ## Using UI components With [Better Auth UI](https://neon.com/docs/auth/reference/ui-components), password reset is built in. `npx shadcn@latest add @better-auth-ui/auth` adds the `forgot-password`, `reset-link-sent`, and `reset-password` views, and the sign-in view links to **Forgot password?**. ### 1. Route the auth views Render `` for every auth path, as in the [Next.js App Router example](https://neon.com/docs/auth/reference/ui-components#nextjs-app-router): ```tsx filename="app/auth/[path]/page.tsx" import { viewPaths } from '@better-auth-ui/core'; import { Auth } from '@/components/auth/auth'; export const dynamicParams = false; export function generateStaticParams() { return Object.values(viewPaths.auth).map((path) => ({ path })); } export default async function AuthPage({ params }: { params: Promise<{ path: string }> }) { const { path } = await params; return ; } ``` `/auth/forgot-password` asks for the email and sends the reset link. The link opens `/auth/reset-password`, where the user sets a new password. ### 2. Render a single view To place a view somewhere else, pass the view name instead of a path: ```tsx filename="src/ForgotPasswordPage.tsx" import { Auth } from '@/components/auth/auth'; export function ForgotPasswordPage() { return ; } ``` The copied components (`components/auth/forgot-password.tsx` and `components/auth/reset-password.tsx`) are yours to edit. **Note:** SDK methods for password reset (`resetPasswordForEmail`) are not fully supported yet. Use the UI components for password reset functionality. ## 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. ## Sign users out after a reset By default, resetting a password doesn't end the user's existing sessions. Turn on **Revoke sessions on password reset** to sign the user out of every existing session when they reset their password. This applies to resets through a reset link (`/reset-password`) and through [Email OTP](https://neon.com/docs/auth/guides/plugins/email-otp#reset-password-with-otp) (`/email-otp/reset-password`), whether your app calls those endpoints directly or through a proxy. **Console** In your project's **Settings** → **Better Auth** page, turn on **Revoke sessions on password reset**. The switch appears under **Sign-in with Email** while that switch is on. **CLI** Turn on the setting using [`neon neon-auth config email-password update`](https://neon.com/docs/cli/neon-auth#config-email-password-update): ```bash neon neon-auth config email-password update --revoke-sessions-on-password-reset ``` `neon neon-auth config email-password get` shows the current value. **API** Use the [Update email and password configuration](https://neon.com/docs/reference/api/auth/update-neon-auth-email-and-password-config) endpoint. Replace `{project_id}` and `{branch_id}` with your project and branch IDs: ```bash curl -X PATCH 'https://console.neon.tech/api/v2/projects/{project_id}/branches/{branch_id}/auth/email_and_password' \ -H 'Authorization: Bearer $NEON_API_KEY' \ -H 'Content-Type: application/json' \ -d '{"revoke_sessions_on_password_reset": true}' ``` A `GET` request to the same endpoint returns the current value. Consuming the reset link or code, deleting the user's sessions, and saving the new password happen in a single database transaction. If any step fails, the reset returns an error, so a successful reset never leaves an old session valid. A revoked session is rejected on its next request. Managed Better Auth doesn't use a session cookie cache or secondary session storage, so every session check reads the database. The setting is off by default so existing apps don't sign users out unexpectedly. It's configured per branch. A new branch copies its parent's auth configuration when you create it, so turning the setting on for a parent doesn't change branches that already exist. To sign out other devices when a signed-in user changes their password, pass `revokeOtherSessions: true` to `changePassword()`. See [Revoke other sessions](https://neon.com/docs/auth/guides/user-management#revoke-other-sessions). ## Next steps - [Add email verification](https://neon.com/docs/auth/guides/email-verification) to ensure users own their email addresses - [Customize the application name](https://neon.com/docs/auth/production-checklist#application-name) shown in password reset emails - [Learn how to branch your auth](https://neon.com/docs/auth/branching-authentication) to use database branches with isolated auth environments --- [Document source](https://neon.com/docs/auth/guides/plugins.md) --- > Summary: Managed Better Auth exposes a managed subset of Better Auth plugins (Admin, Email OTP, JWT, Magic Link, OAuth Provider, Organization, Open API, Phone Number) through the Neon SDK; plugins are not installed or configured directly. Use this page to check which plugins are fully supported versus partially supported, and how to configure them via the Neon Console or Neon API. The Organization plugin has partial support. # Plugins Supported Better Auth plugins in Managed Better Auth Last updated: 2026-10-30 Managed Better Auth is built on [Better Auth](https://www.better-auth.com/), which supports a variety of plugins to extend authentication functionality. **Info: Plugins are managed by Managed Better Auth** Managed Better Auth is a **managed** Better Auth service. You **don't install or configure Better Auth plugins directly** - instead, Managed Better Auth exposes a supported subset of plugins through the Neon SDK. For plugins that have Console settings (for example [Organization](https://neon.com/docs/auth/guides/plugins/organization)), open **Settings** > **Better Auth** in the Neon Console, or use the Neon API. From the terminal, [`neon neon-auth config organization update`](https://neon.com/docs/cli/neon-auth#config-organization-update) configures the Organization plugin, [`neon neon-auth config oauth-server update`](https://neon.com/docs/cli/neon-auth#config-oauth-server-update) configures the OAuth Provider plugin, and [`neon neon-auth plugins list`](https://neon.com/docs/cli/neon-auth#plugins-list) shows the current plugin configurations. Additional plugin options may still arrive over time; see the [Managed Better Auth roadmap](https://neon.com/docs/auth/roadmap). The following Better Auth plugins are currently supported in Managed Better Auth: ## Supported plugins | Plugin | Status | | -------------------------------------------------------------------------- | ----------- | | [Admin](https://neon.com/docs/auth/guides/plugins/admin) | ✅ Supported | | [Email OTP](https://neon.com/docs/auth/guides/plugins/email-otp) | ✅ Supported | | [JWT](https://neon.com/docs/auth/guides/plugins/jwt) | ✅ Supported | | [Magic Link](https://neon.com/docs/auth/guides/plugins/magic-link) | ✅ Supported | | [OAuth Provider](https://neon.com/docs/auth/guides/plugins/oauth-provider) | ✅ Supported | | [Organization](https://neon.com/docs/auth/guides/plugins/organization) | ⚠️ Partial | | [Open API](https://neon.com/docs/auth/guides/plugins/openapi) | ✅ Supported | | [Phone Number](https://neon.com/docs/auth/guides/plugins/phone-number) | ✅ Supported | For more runnable Managed Better Auth samples, see the [neondatabase/neon-js](https://github.com/neondatabase/neon-js/tree/main/examples) examples repository: | Plugin | Demo | | ------------ | ----------------------------------------------------------------------------------------------------------------------- | | Organization | [neon-auth-orgs-example](https://github.com/neondatabase/neon-js/tree/main/examples/neon-auth-orgs-example) | | Magic Link | [neon-auth-magic-link-example](https://github.com/neondatabase/neon-js/tree/main/examples/neon-auth-magic-link-example) | | Phone Number | [nextjs-phone-login](https://github.com/neondatabase/neon-js/tree/main/examples/nextjs-phone-login) | For the latest status (including what's coming next), see the [Managed Better Auth roadmap](https://neon.com/docs/auth/roadmap). --- [Document source](https://neon.com/docs/auth/guides/plugins/admin.md) --- > Summary: The Managed Better Auth Admin plugin exposes Better Auth admin APIs through the Neon SDK without manual plugin configuration, letting server-side code create users, assign roles, ban accounts, list or revoke sessions, and impersonate users for support and debugging. Use this page when building admin dashboards or support tooling that must manage user authentication state programmatically. Admin operations require an authenticated session with HTTP-only cookies, and impersonation sessions are capped at 1 hour. # Admin Manage users, roles, bans, sessions, and impersonation Last updated: 2026-09-16 Managed Better 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](https://neon.com/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 Managed Better Auth yet, follow the [Next.js](https://neon.com/docs/auth/quick-start/nextjs-api-only) or [React](https://neon.com/docs/auth/quick-start/react) quick start to create an `authClient`. ### Create a user Use the Admin APIs to create users on behalf of others (for example, back-office onboarding). #### Parameters
View parameters | Parameter | Type | Required | Notes | | --------- | --------------------------------- | :------: | -------------------------------------------------------- | | email | string | ✓ | Email address for the new user | | password | string | ✓ | Password for the new user | | name | string | ✓ | Display name | | role | string \| string\[] \| undefined | | Optional role(s) for the user (for example: user, admin) | | data | Record\ \| undefined | | Optional custom fields |
```ts const { data, error } = await authClient.admin.createUser({ email: 'user@email.com', password: 'secure-password', name: 'User Name', role: 'user', data: { customUserField: 'value' }, }); ``` ### List users List users with optional search, filtering, sorting, and pagination. #### Parameters
View parameters | Parameter | Type | Required | Notes | | -------------- | ----------------------------------------------------------- | :------: | ------------------------------------ | | searchValue | string \| undefined | | Value to search for | | searchField | 'email' \| 'name' \| undefined | | Field to search in | | searchOperator | 'contains' \| 'starts\_with' \| 'ends\_with' \| undefined | | Search operator | | limit | number \| string \| undefined | | Max users to return (page size) | | offset | number \| string \| undefined | | Number of users to skip (pagination) | | sortBy | string \| undefined | | Field to sort by | | sortDirection | 'asc' \| 'desc' \| undefined | | Sort direction | | filterField | string \| undefined | | Field to filter by | | filterValue | string \| number \| boolean \| undefined | | Filter value | | filterOperator | 'eq' \| 'ne' \| 'lt' \| 'lte' \| 'gt' \| 'gte' \| undefined | | Filter operator |
```ts 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
View parameters | Parameter | Type | Required | Notes | | --------- | ------------------- | :------: | ------------------------------------- | | userId | string | ✓ | The user ID to update | | role | string \| string\[] | ✓ | Role(s) to apply (for example, admin) |
```ts const { error } = await authClient.admin.setRole({ userId: 'user-id', role: 'admin' }); ``` ### Set a user password Set or reset a user's password.
View parameters | Parameter | Type | Required | Notes | | ----------- | ------ | :------: | --------------------- | | userId | string | ✓ | The user ID to update | | newPassword | string | ✓ | The new password |
```ts 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.
View parameters | Parameter | Type | Required | Notes | | --------- | -------------------- | :------: | --------------------------------------------- | | userId | string | ✓ | The user ID to update | | data | Record\ | ✓ | Fields to update (email, name, custom fields) |
```ts 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.
View parameters | Parameter | Type | Required | Notes | | ------------ | ------------------- | :------: | ----------------------------------------------------------------------------------- | | userId | string | ✓ | The user ID to ban | | banReason | string \| undefined | | Reason for the ban | | banExpiresIn | number \| undefined | | Duration in seconds until the ban expires. If not provided, the ban does not expire |
```ts 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.
View parameters | Parameter | Type | Required | Notes | | --------- | ------ | :------: | -------------------- | | userId | string | ✓ | The user ID to unban |
```ts const { error } = await authClient.admin.unbanUser({ userId: 'user-id' }); ``` ### Manage sessions Use session APIs to view active sessions and revoke them. #### List sessions
View parameters | Parameter | Type | Required | Notes | | --------- | ------ | :------: | ------------------------------------------- | | userId | string | ✓ | The user ID whose sessions you want to list |
```ts const { data, error } = await authClient.admin.listUserSessions({ userId: 'user-id' }); ``` #### Revoke a session
View parameters | Parameter | Type | Required | Notes | | ------------ | ------ | :------: | --------------------------- | | sessionToken | string | ✓ | The session token to revoke |
```ts const { error } = await authClient.admin.revokeUserSession({ sessionToken: 'session-token' }); ``` #### Revoke all sessions
View parameters | Parameter | Type | Required | Notes | | --------- | ------ | :------: | --------------------------------------------- | | userId | string | ✓ | The user ID whose sessions you want to revoke |
```ts 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).
View parameters | Parameter | Type | Required | Notes | | --------- | ------ | :------: | -------------------------- | | userId | string | ✓ | The user ID to impersonate |
```ts const { data, error } = await authClient.admin.impersonateUser({ userId: 'user-id' }); ``` ### Stop impersonation Stop an active impersonation session.
View parameters This method does not take any parameters.
```ts 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 Managed Better 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. --- [Document source](https://neon.com/docs/auth/guides/plugins/email-otp.md) --- > Summary: Managed Better Auth Email OTP delivers one-time passwords by email for passwordless sign-in, password reset, and email verification without requiring manual installation of the Better Auth plugin. Use this page to implement these flows via Neon SDK methods or with Better Auth UI's Email OTP plugin (`emailOtpPlugin()`) for pre-built UI components. OTP codes are time-limited and rate-limited (exceeding attempts returns `TOO_MANY_ATTEMPTS`), and production deployments require a dedicated SMTP provider. # Email OTP Sign in and verify email addresses with one-time passwords Last updated: 2026-11-05 Managed Better 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) Managed Better 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** → **Better Auth**. **Note: 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](https://neon.com/docs/auth/email-otp.png) ## Use Email OTP with UI components If you're using [Better Auth UI](https://neon.com/docs/auth/reference/ui-components), add its Email OTP components and pass the plugin to `AuthProvider`. `emailOtpPlugin()` adds OTP sign-in; pass `emailOtpPlugin({ passwordReset: true, emailVerification: true })` to also use codes for password reset and email verification. ```bash npx shadcn@latest add @better-auth-ui/email-otp ``` ```tsx filename="components/providers.tsx" import { emailOtpPlugin } from '@/lib/auth/email-otp-plugin'; {children} ``` Add the plugin's views to your auth route's paths with `emailOtpPlugin().viewPaths.auth` from `@better-auth-ui/core/plugins/email-otp`. The UI plugin doesn't enable Email OTP on your branch; enable it in Managed Better Auth first. 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](https://neon.com/docs/auth/email-otp-verification.png) > If you haven't set up Managed Better Auth UI components yet, see the [UI components reference](https://neon.com/docs/auth/reference/ui-components) and the [Next.js](https://neon.com/docs/auth/quick-start/nextjs-api-only) or [React](https://neon.com/docs/auth/quick-start/react) quick start. ## Use Email OTP with SDK methods You can also implement OTP flows directly using the [Neon SDK](https://neon.com/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 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](https://neon.com/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 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](https://neon.com/docs/reference/javascript-sdk#auth-signinwithemailotp) in Neon SDK. ### Verify email with OTP If your project has email verification enabled with **verification codes**, Managed Better Auth sends an OTP during sign-up. Once the user enters the code, verify the email address using `emailOtp.verifyEmail()`: ```ts 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](https://neon.com/docs/reference/javascript-sdk#auth-verifyemail) in Neon SDK. Check out our [Email verification guide](https://neon.com/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 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](https://neon.com/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 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 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 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, password: newPassword, }); } ``` To sign the user out of every existing session after an OTP reset, turn on [Revoke sessions on password reset](https://neon.com/docs/auth/guides/password-reset#sign-users-out-after-a-reset). ## 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](https://neon.com/docs/auth/production-checklist#email-provider) for setup instructions. A custom SMTP provider changes the sender address but still sends Neon's default templates. For full branding control, use webhooks. See [Customize emails](https://neon.com/docs/auth/guides/customize-emails). --- [Document source](https://neon.com/docs/auth/guides/plugins/jwt.md) --- > Summary: Managed Better Auth's JWT plugin lets backend services, CLI tools, and cross-domain API requests retrieve raw JSON Web Tokens via `authClient.getSession()` (`data.session.token`) or the `set-auth-jwt` response header, rather than relying on HTTP-only session cookies. Tokens are signed with EdDSA (Ed25519) and expire in 15 minutes; verify them using the JWKS endpoint at `/.well-known/jwks.json`. This plugin is not a substitute for session management in browser-based apps, and custom JWT claims are not supported. # JWT Authenticate using JSON Web Tokens (JWT) for external services Last updated: 2026-11-05 Managed Better 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 Managed Better 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. **Warning: 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. ## 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 get a raw token string, call `authClient.getSession()`. The SDK puts the session's JWT in `data.session.token`. This is the recommended approach for client applications that need to attach a token to an API request header manually. ```ts filename="src/get-token.ts" import { authClient } from './auth'; export async function getJwtToken() { const { data, error } = await authClient.getSession(); if (error) throw error; // The JWT string (for example, "eyJhbGciOiJFZ..."), or undefined when no one is signed in return data?.session.token; } ``` If your app is served from a different origin than your Managed Better Auth URL (for example a Vite or SPA dev server on `localhost` talking to auth on `*.neon.tech`), make sure the auth client sends the session cookie on cross-origin requests, so that `getSession()` can find the session: ```ts filename="src/auth.ts" import { createAuthClient } from '@neon/auth'; import { BetterAuthReactAdapter } from '@neon/auth/react/adapters'; export const authClient = createAuthClient(import.meta.env.VITE_NEON_AUTH_URL, { adapter: BetterAuthReactAdapter({ fetchOptions: { credentials: 'include' } }), }); ``` Cross-domain setups have further limitations, notably Safari ITP blocking third-party cookies, with reverse-proxy or shared-parent-domain workarounds. See [Better Auth: Safari, ITP, and Cross-Domain Setups](https://www.better-auth.com/docs/concepts/cookies#safari-itp-and-cross-domain-setups). ### Using the session header When you call `authClient.getSession()`, Managed Better 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": "user@email.com", "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": "", "aud": "" } ``` ### Organization claim If the user belongs to an [organization](https://neon.com/docs/auth/guides/plugins/organization), the JWT includes an `o` claim describing the session's active organization: ```json { "o": { "id": "2644b1c7-6d77-46bf-bcf1-832f7616db16", "slug": "example-org", "role": "owner" } } ``` - `id`: the organization ID - `slug`: the organization slug - `role`: the user's role in the organization, such as `owner`, `admin`, or `member` The `o` claim is `null` when the session has no active organization or the Organization plugin is disabled for the branch. Creating an organization makes it the active organization for that session. To switch, call `authClient.organization.setActive()`. The `role` value is read when the token is issued. If a user's role changes, tokens issued afterward include the new role, but an existing token keeps the old role until it expires. Tokens expire after 15 minutes. ## 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). Managed Better Auth exposes a public JWKS endpoint that contains the public keys necessary to verify the signature of your JWTs. ### The JWKS endpoint Your Managed Better Auth JWKS endpoint is located at: ``` /.well-known/jwks.json ``` If you verify Managed Better Auth JWTs inside [Neon Functions](https://neon.com/docs/compute/functions/overview), the platform injects `NEON_AUTH_BASE_URL` and `NEON_AUTH_JWKS_URL` when Managed Better Auth is provisioned on the branch. Use `NEON_AUTH_JWKS_URL` directly instead of deriving it yourself. See [Functions environment variables](https://neon.com/docs/compute/functions/environment-variables#neon-injected-variables). ### Verification example The following examples demonstrate how to verify a Managed Better 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. **Info: 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. **Node.js** 1. Install the library: ```bash npm install jose ``` 2. Use the following example code as a reference to verify a JWT: ```ts import { jwtVerify, createRemoteJWKSet } from 'jose'; const NEON_AUTH_BASE_URL = process.env.NEON_AUTH_BASE_URL!; const NEON_JWKS_URL = `${NEON_AUTH_BASE_URL}/.well-known/jwks.json`; const JWKS = createRemoteJWKSet(new URL(NEON_JWKS_URL)); // Managed Better Auth sets both `iss` and `aud` to the origin of your auth URL const ORIGIN = new URL(NEON_AUTH_BASE_URL).origin; export async function validateNeonToken(token: string) { try { const { payload } = await jwtVerify(token, JWKS, { algorithms: ['EdDSA'], issuer: ORIGIN, audience: ORIGIN, }); return payload; } catch (error) { console.error('Token validation failed:', error); return null; } } validateNeonToken('').then((payload) => { if (payload) { console.log('Token is valid. Payload:', payload); } else { console.log('Token is invalid.'); } }); ``` > Replace `` with the actual JWT token you want to verify. **Python** 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("") if payload: print("Token is valid. Payload:", payload) else: print("Token is invalid.") ``` > Replace `` with the actual JWT token you want to verify. **Go** 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 := "" 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 `` with the actual JWT token you want to verify. ## Limitations Because Managed Better 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:** Managed Better 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). Call `authClient.getSession()` whenever you need a token. The SDK fetches a new one when the cached token is about to expire. - **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 Managed Better Auth instance. The issuer (`iss`) and audience (`aud`) of the token must both match the origin of your Managed Better Auth URL, not the full URL. For example, if your Managed Better Auth URL is `https://ep-xx.aws.neon.tech/neondb/auth`, both 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. --- [Document source](https://neon.com/docs/auth/guides/plugins/magic-link.md) --- > Summary: Magic Link is a Managed Better Auth plugin that lets users sign in without a password by clicking a time-limited link sent to their email, with expiration configurable from 5 to 1440 minutes. Use this page when you want to add passwordless email authentication to a project that already has Managed Better Auth enabled, using either the Neon SDK's `signIn.magicLink()` method or Better Auth UI's Magic Link plugin (`magicLinkPlugin()`). The plugin also supports a webhook event (`send.magic_link`) to bypass the built-in mailer and deliver links through a custom email provider. # Magic Link Passwordless sign-in via email magic links Last updated: 2026-10-09 Managed Better Auth is built on [Better Auth](https://www.better-auth.com/) and provides full support for the [Magic Link](https://www.better-auth.com/docs/plugins/magic-link) plugin APIs through the Neon SDK. You do not need to manually install or configure the Better Auth Magic Link plugin. Magic Link lets users sign in by clicking a link sent to their email. No password is required. The flow works like this: 1. The user enters their email address. 2. Managed Better Auth sends an email containing a unique, time-limited link. 3. The user clicks the link, which verifies the token, creates a session, and redirects them to your app. ## Prerequisites - A Neon project with **Auth enabled** - The **Magic Link plugin enabled** (see [Enable Magic Link](https://neon.com/docs/auth/guides/plugins/magic-link#enable-magic-link) below) ## Enable Magic Link **Console** 1. Open the [Neon Console](https://console.neon.tech). 2. Select your project and go to **Settings** > **Better Auth**. 3. In the **Magic Link** section, toggle **Enable Magic Link** on. 4. Configure the options: - **Link Expiration** (5-1440 minutes, default: 5) controls how long a magic link stays valid. - **Allow New User Registration** controls whether magic links can be used to create new accounts. When off, magic links only work for existing users. **API** Send a `PATCH` request to configure the Magic Link plugin. All request body fields are optional; send only the fields you want to change. ```bash curl -X PATCH \ "https://console.neon.tech/api/v2/projects/{project_id}/branches/{branch_id}/auth/plugins/magic-link" \ -H "Authorization: Bearer $NEON_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "enabled": true, "expires_in": 5, "disable_sign_up": false }' ``` | Field | Type | Default | Description | | ----------------- | ------- | ------- | ----------------------------------------------------- | | `enabled` | boolean | `false` | Whether the Magic Link plugin is active | | `expires_in` | integer | `5` | Minutes before the magic link expires (5-1440) | | `disable_sign_up` | boolean | `false` | When `true`, magic links only work for existing users | ## Use Magic Link with SDK methods Build a custom magic link flow using the [Neon SDK](https://neon.com/docs/reference/javascript-sdk). Call `signIn.magicLink()` with the user's email and a callback URL. Managed Better Auth sends the email and redirects the user to `callbackURL` after they click the link. ```ts filename="src/send-magic-link.ts" import { authClient } from '@/lib/auth/client'; export async function sendMagicLink(email: string) { const { error } = await authClient.signIn.magicLink({ email, callbackURL: '/dashboard', }); if (error) throw error; } ``` After calling `signIn.magicLink()`, show the user a "check your email" message. For a complete working example with error handling, resend, and state management, see the [magic link example app](https://github.com/neondatabase/neon-js/tree/main/examples/neon-auth-magic-link-example) in the neon-js repository. ## Use Magic Link with UI components If you're already using [Better Auth UI](https://neon.com/docs/auth/reference/ui-components), add its Magic Link components and pass the plugin to `AuthProvider` instead of building a custom form: ```bash npx shadcn@latest add @better-auth-ui/magic-link ``` ```tsx filename="components/providers.tsx" import { magicLinkPlugin } from '@/lib/auth/magic-link-plugin'; {children} ``` Add the plugin's views to your auth route's paths with `magicLinkPlugin().viewPaths.auth` from `@better-auth-ui/core/plugins/magic-link`. The UI plugin doesn't enable Magic Link on your branch; enable it in Managed Better Auth first. Users can now sign in with a magic link by selecting the option on the sign-in screen and entering their email. > If you haven't set up Better Auth UI yet, see the [UI components reference](https://neon.com/docs/auth/reference/ui-components) for setup, or the [Next.js](https://neon.com/docs/auth/quick-start/nextjs-api-only) or [React](https://neon.com/docs/auth/quick-start/react) quick start for building custom forms instead. ## Webhooks If you subscribe to the `send.magic_link` event, Managed Better Auth skips its built-in email and calls your webhook instead, passing `link_type: "sign-in"` in the payload. Your handler is responsible for delivering the link (for example, via a custom email template or SMS). See the [Webhooks guide](https://neon.com/docs/auth/guides/webhooks) for configuration details and payload format. ## Email provider configuration For production environments, we strongly recommend using a dedicated email provider. The default shared SMTP should be used only during development. See the [Email provider configuration guide](https://neon.com/docs/auth/production-checklist#email-provider) for setup instructions. --- [Document source](https://neon.com/docs/auth/guides/plugins/oauth-provider.md) --- > Summary: The OAuth provider plugin turns Managed Better Auth into an OAuth 2.1 authorization server for your own apps. Use it to protect an MCP server so MCP clients can sign in your users, or to let other apps call your API on behalf of your users. Covers enabling the plugin in the Console or API, the login and consent pages you host, Client ID Metadata Documents and legacy dynamic client registration, managed confidential and public clients, scopes and refresh tokens, and how a resource server verifies the issuer, audience, and signature of access tokens. # OAuth Provider Let your MCP server, API, or other apps sign in your Managed Better Auth users Last updated: 2026-11-06 Managed Better Auth is built on [Better Auth](https://www.better-auth.com/) and can act as an OAuth 2.1 authorization server for your own apps. With the OAuth provider plugin enabled, Managed Better Auth issues access tokens to OAuth clients on behalf of your signed-in users, and your MCP server or API verifies those tokens. Use it to: - **Protect an MCP server.** MCP clients discover your authorization server, identify themselves with a [Client ID Metadata Document](https://neon.com/docs/auth/guides/plugins/oauth-provider#client-id-metadata-documents) (CIMD), and call your tools with an access token for your users. Legacy [dynamic client registration](https://neon.com/docs/auth/guides/plugins/oauth-provider#dynamic-client-registration-legacy) (DCR) is available as an opt-in. MCP support is part of this plugin, not a separate plugin: you set it up with the **Server URL** field in the **MCP server** section. - **Sign in your users to another app or API.** A web app, single-page app, desktop app, or CLI runs the authorization code flow with PKCE and calls your API with the resulting token. The OAuth provider plugin is available to all Managed Better Auth projects. ## Prerequisites - A Neon project with **Auth enabled**. - **A login page and a consent page, both hosted by you.** Both are required. Managed Better Auth doesn't provide default pages. Authorization requests redirect users to your login page, and then to your consent page to approve the client. See [Build your consent page](https://neon.com/docs/auth/guides/plugins/oauth-provider#build-your-consent-page) and [How the pages complete the flow](https://neon.com/docs/auth/guides/plugins/oauth-provider#how-the-pages-complete-the-flow). - The origin of each page added as a [trusted domain](https://neon.com/docs/auth/guides/configure-domains) for the branch. Pages must use `https`, with no query string or fragment. `http` is allowed on `localhost` when [localhost access](https://neon.com/docs/auth/guides/manage-auth-api#related-auth-endpoints) is enabled for the branch. - At least one protected resource: an MCP server URL, or an API identifier. A resource is an absolute URL that identifies what the token is for. It becomes the token's `aud` claim and doesn't need to resolve. Configuration is per branch. Each branch has its own issuer, OAuth clients, and settings. ## Enable the OAuth provider **Console** 1. Open the [Neon Console](https://console.neon.tech). 2. Select your project and go to **Settings** > **Better Auth**. 3. In the **OAuth provider** section, toggle **Enable OAuth provider** on. 4. Fill in the settings: - **Login page URL**: where authorization requests redirect for sign-in. - **Consent page URL**: where authorization requests redirect for user consent. - **Server URL** (in the **MCP server** section): the URL of your MCP server, if you're protecting one. MCP is configured here, in the OAuth provider panel. - **Client ID Metadata Documents**: on by default once you set a server URL. See [Client ID Metadata Documents](https://neon.com/docs/auth/guides/plugins/oauth-provider#client-id-metadata-documents). - **Dynamic client registration (legacy)**: off by default. Requires a server URL. See [Dynamic client registration (legacy)](https://neon.com/docs/auth/guides/plugins/oauth-provider#dynamic-client-registration-legacy). - **Resource URLs**: URLs of other APIs that clients can request tokens for. 5. Click **Enable**. You need an MCP server URL or at least one protected resource to enable the provider. **CLI** Use [`neon neon-auth config oauth-server`](https://neon.com/docs/cli/neon-auth#config-oauth-server). Add a protected resource, then enable the server with its login and consent pages, which must be on a [trusted domain](https://neon.com/docs/auth/guides/configure-domains): ```bash neon neon-auth config oauth-server resource add https://api.example.com/reports neon neon-auth config oauth-server update --enabled --login-page https://app.example.com/login --consent-page https://app.example.com/consent ``` To protect an MCP server, add `--mcp-resource https://mcp.example.com/mcp`. `neon neon-auth config oauth-server get` shows the current configuration. **API** Send a `PATCH` request to the [update OAuth provider plugin](https://neon.com/docs/reference/api/auth/update-neon-auth-o-auth-provider-plugin) endpoint. A `GET` on the same path ([retrieve](https://neon.com/docs/reference/api/auth/get-neon-auth-o-auth-provider-plugin)) returns the current configuration. ```bash curl -X PATCH \ "https://console.neon.tech/api/v2/projects/{project_id}/branches/{branch_id}/auth/plugins/oauth-provider" \ -H "Authorization: Bearer $NEON_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "enabled": true, "login_page": "https://app.example.com/login", "consent_page": "https://app.example.com/consent", "mcp": { "resource": "https://mcp.example.com/mcp" }, "resources": [ { "identifier": "https://api.example.com/reports" } ] }' ``` The response returns the stored configuration: ```json { "enabled": true, "login_page": "https://app.example.com/login", "consent_page": "https://app.example.com/consent", "mcp": { "resource": "https://mcp.example.com/mcp", "dynamic_registration": false, "client_id_metadata_documents": true }, "resources": [{ "identifier": "https://api.example.com/reports" }] } ``` | Field | Type | Description | | ---------------------------------- | ------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `enabled` | boolean | Whether the OAuth provider is active | | `login_page` | string | URL of your login page | | `consent_page` | string | URL of your consent page | | `mcp.resource` | string | URL of your MCP server. Required whenever `mcp` is sent | | `mcp.client_id_metadata_documents` | boolean | Allow MCP clients to identify themselves with a Client ID Metadata Document. Defaults to `true`; takes effect only when `mcp.resource` is set | | `mcp.dynamic_registration` | boolean | Legacy. Allow MCP clients to register themselves with RFC 7591 dynamic client registration. Defaults to `false`; takes effect only when `mcp.resource` is set | | `resources` | array | Other protected resources, as `{ "identifier": "" }` objects. Up to 10 | To remove MCP support, send `"mcp": { "resource": "" }`. CIMD and DCR then have no effect, and clients that onboarded through them stop working. Omitted fields keep their current values. A provided `resources` list replaces the stored list, so send the full list when you add a resource. A provided `mcp` object must include `resource`; its toggles keep their stored values when omitted. Enabling requires `login_page`, `consent_page`, and at least one of `mcp.resource` or `resources`. Resource identifiers must be absolute `https` URLs (or `http` on a loopback host) without credentials, query string, or fragment. They can't point at your Managed Better Auth host. ## Protect an MCP server An MCP client connects to your MCP server and learns where to authenticate from the server's protected resource metadata ([RFC 9728](https://datatracker.ietf.org/doc/html/rfc9728)). The flow is: 1. The client calls your MCP server and receives a `401` response that points to the server's protected resource metadata. 2. The metadata lists your Managed Better Auth issuer as the authorization server. The client reads the issuer's metadata to find the authorize and token endpoints, and whether the issuer supports client ID metadata documents. The issuer serves the same metadata at `/.well-known/oauth-authorization-server` and `/.well-known/openid-configuration`, so clients that append the well-known path to the issuer URL find it either way. 3. The client identifies itself, usually with a [Client ID Metadata Document](https://neon.com/docs/auth/guides/plugins/oauth-provider#client-id-metadata-documents) (or, if you enabled it, [dynamic client registration](https://neon.com/docs/auth/guides/plugins/oauth-provider#dynamic-client-registration-legacy)). 4. The user signs in on your login page and approves the client on your consent page. 5. The client exchanges the authorization code (with PKCE) for an access token and calls your MCP server with it. Your MCP server is responsible for two things: serving its protected resource metadata, and verifying access tokens. For a full walkthrough that runs the MCP server on a Neon Function with Managed Better Auth, see [Build an MCP server with Managed Better Auth](https://neon.com/docs/compute/functions/mcp-server). ### Find the issuer The issuer is the Auth URL of the branch, for example `https://ep-example.neonauth.us-east-1.aws.neon.tech/neondb/auth`. Copy it from the Console, or read `base_url` from `GET .../auth`. Don't build it from the endpoint ID. The issuer is different on every branch, so keep it in configuration per branch and check that the `issuer` field of the metadata document equals it. ### Verify access tokens When the client sends the `resource` parameter, access tokens are signed JWTs (EdDSA). Verify them against the JWKS at `/.well-known/jwks.json`. Your resource server must check both of these claims: - `iss` equals the exact issuer of your branch. - `aud` contains the exact resource identifier of your server. **Important: Verify iss and aud, not only the signature** All branches of a project share the same signing keys, and only the issuer (`iss`) differs per branch. A token issued by one branch has a valid signature on every other branch, so the signature alone doesn't tell you which branch issued it. A resource server must verify `iss` against the issuer of its own branch and `aud` against its own resource identifier. The `aud` claim can be an array: with the `openid` [scope](https://neon.com/docs/auth/guides/plugins/oauth-provider#scopes-and-refresh-tokens) it also contains the issuer's userinfo endpoint, so check for membership rather than equality. When you create a branch, it starts with the parent's OAuth clients (same client ID and secret), so also pin the issuer in each branch's resource server. The following example protects an MCP server built with the [MCP TypeScript SDK](https://github.com/modelcontextprotocol/typescript-sdk) and Express. The [`@neon/oauth`](https://www.npmjs.com/package/@neon/oauth) SDK (beta) does the token work: install it with `npm install @neon/oauth`. ```ts filename="src/server.ts" import express from 'express'; import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'; import { StreamableHTTPServerTransport } from '@modelcontextprotocol/sdk/server/streamableHttp.js'; import { createMcpAuth } from '@neon/oauth/mcp'; import { expressMcp } from '@neon/oauth/mcp/express'; const auth = createMcpAuth({ baseUrl: process.env.NEON_AUTH_BASE_URL!, // the Auth URL of your branch resource: 'https://mcp.example.com/mcp', // the MCP server URL configured on the provider }); const app = express(); app.use(expressMcp(auth)); app.use(express.json()); // A stateless transport serves one request, so create the server and transport per request. app.post('/mcp', async (req, res) => { const server = new McpServer({ name: 'reports', version: '1.0.0' }); const transport = new StreamableHTTPServerTransport({ sessionIdGenerator: undefined, }); res.on('close', () => { transport.close(); server.close(); }); await server.connect(transport); await transport.handleRequest(req, res, req.body); }); app.listen(3000); ``` `createMcpAuth()` verifies the signature, `iss`, and `aud` of each access token. `expressMcp()` serves the protected resource metadata, answers requests without a valid token with a `401` that points to it, and sets `req.auth` for valid ones, in the MCP SDK's `AuthInfo` shape, so the transport passes it to your tools as `extra.authInfo`. The full verification result is on `req.authResult`. Use `@neon/oauth` 0.3.0 or later. The SDK also has adapters for Hono, Next.js, and `node:http`. #### Without the SDK The same server using only [`jose`](https://github.com/panva/jose) and the MCP TypeScript SDK: ```ts filename="src/server.ts" import express from 'express'; import { createRemoteJWKSet, errors, jwtVerify } from 'jose'; import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'; import { StreamableHTTPServerTransport } from '@modelcontextprotocol/sdk/server/streamableHttp.js'; import { requireBearerAuth } from '@modelcontextprotocol/sdk/server/auth/middleware/bearerAuth.js'; import { getOAuthProtectedResourceMetadataUrl, mcpAuthMetadataRouter, } from '@modelcontextprotocol/sdk/server/auth/router.js'; import { InvalidTokenError } from '@modelcontextprotocol/sdk/server/auth/errors.js'; const AUTH_URL = 'https://ep-example.neonauth.us-east-1.aws.neon.tech/neondb/auth'; // the Auth URL of your branch const RESOURCE = new URL('https://mcp.example.com/mcp'); // the MCP server URL configured on the provider const discovery = await fetch( `${AUTH_URL}/.well-known/oauth-authorization-server` ); if (!discovery.ok) { throw new Error(`Discovery failed with status ${discovery.status}`); } const oauthMetadata = await discovery.json(); if (oauthMetadata.issuer !== AUTH_URL) throw new Error('Unexpected issuer'); // RFC 8414 section 3.3 const jwks = createRemoteJWKSet(new URL(oauthMetadata.jwks_uri)); const verifier = { async verifyAccessToken(token: string) { try { const { payload } = await jwtVerify(token, jwks, { issuer: AUTH_URL, // exact match audience: RESOURCE.href, // must be one of the token's aud values algorithms: ['EdDSA'], }); return { token, clientId: String(payload.client_id ?? ''), scopes: String(payload.scope ?? '') .split(' ') .filter(Boolean), expiresAt: payload.exp, resource: RESOURCE, extra: { sub: payload.sub }, }; } catch (error) { if (error instanceof errors.JOSEError) { throw new InvalidTokenError('Invalid access token'); } throw error; } }, }; const app = express(); // Serves /.well-known/oauth-protected-resource/mcp, which names the issuer as the authorization server. // It also mirrors the authorization server metadata at /.well-known/oauth-authorization-server on this origin. app.use(mcpAuthMetadataRouter({ oauthMetadata, resourceServerUrl: RESOURCE })); app.use( '/mcp', requireBearerAuth({ verifier, resourceMetadataUrl: getOAuthProtectedResourceMetadataUrl(RESOURCE), }) ); app.use(express.json()); // A stateless transport serves one request, so create the server and transport per request. // requireBearerAuth sets req.auth, which the transport passes to your tool handlers. app.post('/mcp', async (req, res) => { const server = new McpServer({ name: 'reports', version: '1.0.0' }); const transport = new StreamableHTTPServerTransport({ sessionIdGenerator: undefined, }); res.on('close', () => { transport.close(); server.close(); }); await server.connect(transport); await transport.handleRequest(req, res, req.body); }); app.listen(3000); ``` ### Client ID Metadata Documents With Client ID Metadata Documents (CIMD), an MCP client uses an `https` URL as its `client_id`. The URL serves a JSON document that describes the client, including its `client_name` and `redirect_uris`. Managed Better Auth fetches the document the first time the client is used, so you don't create clients for MCP clients that support CIMD. CIMD is on by default once you set an MCP server, and the authorization server metadata advertises `client_id_metadata_document_supported`. If you build an MCP client, `createClientMetadataDocument` from `@neon/oauth` produces a valid document. A CIMD client: - Is a public client that uses PKCE, or a confidential client that authenticates with `private_key_jwt` and publishes its public keys in the document (`jwks` or `jwks_uri`). Symmetric methods such as `client_secret_basic` are rejected. - Can request tokens for the MCP server resource only. The document can't link the client to other resources. - Can't skip the consent screen. A document that sets `skip_consent` is rejected with `invalid_client`. - Must use redirect URIs that follow the [redirect URI rules](https://neon.com/docs/auth/guides/plugins/oauth-provider#redirect-uri-rules). A loopback `http` redirect URI matches on any port. All other redirect URIs must match the document exactly. Clear **Client ID Metadata Documents** in the Console, or set `mcp.client_id_metadata_documents` to `false` in the API, if you want to control which clients can request tokens. New CIMD clients are then rejected and existing ones stop working. Clients you create yourself keep working. **Warning: Consent screens for self-onboarded clients** A client's name comes from a document the client controls (or, with DCR, from anyone who registers), so don't treat it as proof of identity. Follow [Build your consent page](https://neon.com/docs/auth/guides/plugins/oauth-provider#build-your-consent-page) so users can tell what they're approving. ### Dynamic client registration (legacy) Dynamic client registration (DCR, [RFC 7591](https://datatracker.ietf.org/doc/html/rfc7591)) is the older way for MCP clients to register themselves, at the issuer's `/oauth2/register` endpoint. Prefer [Client ID Metadata Documents](https://neon.com/docs/auth/guides/plugins/oauth-provider#client-id-metadata-documents). DCR is off by default. To accept clients that only support DCR, turn on **Dynamic client registration (legacy)** (`mcp.dynamic_registration: true`), which requires an MCP server URL. It applies only to your MCP server resource. A client registered this way can request tokens for the MCP server only, and it can't skip the consent screen on first use. While DCR is on, anyone can register a client with any name and redirect URI, so the consent-screen warning above applies in full. Branches configured before October 2026 may have relied on DCR being on by default. If yours did, set `mcp.dynamic_registration` to `true` explicitly to keep it. While DCR is off, `/oauth2/register` returns `403`, and the authorization server metadata omits `registration_endpoint`. Turning DCR off stops new registrations only. Existing clients are unaffected: to stop one, disable or delete it. ### Build your consent page You host the consent page, so you control what users see before they approve a client. Show: - The client name. - The client's host, if the client registered a client URI. - The host of each redirect URI, because that's where the authorization code is sent. - The scopes the client requests and the resource it wants a token for. Both are in the `scope` and `resource` parameters of the authorization request your page receives. Warn the user when the only redirect URIs are `localhost` or loopback addresses. The client then runs on the user's own machine, and a self-asserted name gives no assurance about who built it. Users approve a client once. Later authorizations for the same client, scopes, and resource reuse the stored consent, and your consent page is shown again when a client asks for scopes or a resource the user hasn't approved. ### How the pages complete the flow Both pages receive the authorization request as query parameters. The query is signed and expires, so pass it back to Managed Better Auth exactly as received, as the `oauth_query` value. - **Login page.** The authorization request redirects here when the user has no session. Send `oauth_query` in the body of the sign-in request. This works for email and password sign-in and for social sign-in, such as Google or GitHub. Managed Better Auth verifies the signature, signs the user in, and resumes the authorization request. With email and password, the sign-in response tells your page where to go next, usually your consent page. With social sign-in, the provider returns the user to your login page, signed in, with the same query. When your login page loads with a session, send `POST /oauth2/continue` with `{ "selected": true, "oauth_query": "" }` and navigate to the returned `url`. Do the same when a signed-in user reaches the login page. - **Consent page.** Show what the user is approving, then send `POST /oauth2/consent` with a JSON body of `{ "accept": true, "oauth_query": "" }`, or `"accept": false` to deny. The response is JSON with a `redirect` flag and the `url` to navigate the browser to. That URL is the client's redirect URI with the authorization code, or an error. - **Client details.** To display the client name, call `GET /oauth2/public-client?client_id=` with the user's session. It returns `client_id` and `client_name` for every client. Clients that identify with a Client ID Metadata Document also return the `client_uri` and `logo_uri` from their document when it sets them. Managed clients don't have these fields. For example, the buttons on your consent page can call: ```ts filename="consent.ts" const ISSUER = 'https://ep-example.neonauth.us-east-1.aws.neon.tech/neondb/auth'; // the Auth URL of your branch async function respond(accept: boolean) { const res = await fetch(`${ISSUER}/oauth2/consent`, { method: 'POST', credentials: 'include', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ accept, oauth_query: window.location.search.slice(1), // the query exactly as received }), }); if (!res.ok) throw new Error(`Consent failed with status ${res.status}`); const { url } = await res.json(); window.location.assign(url); // the client's redirect URI, with the code or an error } ``` Calls from your pages carry the user's session cookie, so make them with `credentials: 'include'` and add your pages' origins as [trusted domains](https://neon.com/docs/auth/guides/configure-domains). Navigate the browser to the returned `url`. Neither the sign-in nor the consent response is an HTTP redirect. **Tip: Use the Neon Auth client** If your pages use [`@neon/auth`](https://neon.com/docs/auth/overview) 0.8.0 or later (or `@neon/neon-js` 0.10.0 or later), the client handles `oauth_query` for you. Sign-in requests on your login page attach it automatically. When your login page loads with a session, call `authClient.oauth2.continue({ selected: true })`. On your consent page, `authClient.oauth2.consent({ accept })` replaces the `fetch` call above. The client navigates to the returned `url` itself, so don't navigate again. ## Sign in users to your own apps and APIs To let an app call your API on behalf of your users, add the API as a protected resource and create a managed OAuth client for the app. 1. Add the API identifier under **Resource URLs**, or in the `resources` list of the API request. 2. [Create an OAuth client](https://neon.com/docs/auth/guides/plugins/oauth-provider#create-and-manage-oauth-clients) linked to that resource. 3. In the app, run the authorization code flow with PKCE. Send the API identifier as the `resource` parameter on both the authorize and token requests. 4. The API verifies the access token the same way as the MCP example above, with its own identifier as the expected `aud`. Send the user to the authorize endpoint of the issuer with the PKCE challenge, the `resource`, and the scopes you need (see [Scopes and refresh tokens](https://neon.com/docs/auth/guides/plugins/oauth-provider#scopes-and-refresh-tokens)): ```text https://ep-example.neonauth.us-east-1.aws.neon.tech/neondb/auth/oauth2/authorize ?response_type=code &client_id= &redirect_uri=https%3A%2F%2Freports.example.com%2Fcallback &scope=openid%20offline_access &state= &code_challenge= &code_challenge_method=S256 &resource=https%3A%2F%2Fapi.example.com%2Freports ``` The authorize endpoint is `authorization_endpoint` in the issuer's metadata. After the user signs in and approves the client on your [pages](https://neon.com/docs/auth/guides/plugins/oauth-provider#how-the-pages-complete-the-flow), the browser returns to `redirect_uri` with `code` and `state`. A confidential client exchanges the code on the server and authenticates with `client_secret_basic`: ```bash curl -X POST "$ISSUER/oauth2/token" \ -u "$CLIENT_ID:$CLIENT_SECRET" \ -d grant_type=authorization_code \ -d code="$CODE" \ -d code_verifier="$CODE_VERIFIER" \ -d redirect_uri="https://reports.example.com/callback" \ -d resource="https://api.example.com/reports" ``` A token is issued for the `resource` requested in that call. A token for your API isn't valid at your MCP server, and the reverse. The `@neon/oauth` SDK (beta) implements this flow for you. `createOAuth()` from `@neon/oauth` handles discovery, PKCE sign-in with encrypted session cookies, token refresh, and token verification for your API. It has adapters for Hono, Express, Next.js, and `node:http`. The sign-in client uses `node:crypto` for cookie encryption, so it doesn't run on the Edge runtime. Token verification doesn't have that limit. ## Create and manage OAuth clients Managed clients are for resources that clients can't register for themselves. You can also link a managed client to your MCP server resource, which is how you onboard known clients when you turn off CIMD and DCR. If you work with an AI assistant, the [Neon MCP Server](https://neon.com/docs/ai/neon-mcp-server) can also manage the provider and its clients with the `*_auth_oauth_server` and `*_auth_oauth_client` tools. **Warning: Keep the MCP server URL out of the resources list** For an MCP server, set the URL in `mcp.resource` (the **Server URL** field) and turn off `client_id_metadata_documents` and `dynamic_registration` so that only managed clients can connect. Don't list the MCP server URL under `resources` instead. The refresh-token reuse window (30 seconds) is configured only when `mcp.resource` is set. Without it, an MCP client that refreshes concurrently presents an already-rotated refresh token, and Managed Better Auth revokes that user's refresh tokens for the client. | Type | Secret | Token endpoint auth | Typical use | | -------------- | ------------------------- | --------------------- | ------------------------------------------ | | `confidential` | Client secret, shown once | `client_secret_basic` | Server-side web apps and backends | | `public` | None | `none`, with PKCE | Single-page, mobile, desktop, and CLI apps | The type can't be changed after creation. Redirect URIs must match exactly. **Console** Under the OAuth provider settings, use the **OAuth clients** list: - **Create OAuth client**: set a name, client type, redirect URIs, and the protected resources the client can request tokens for. For a confidential client, the console shows the client secret once. Copy it before you close the dialog. - **Edit**: change the name, redirect URIs, resources, **Skip consent**, or **Disabled**. A disabled client can't obtain new tokens. - **Rotate secret**: generates a new secret for a confidential client. The previous secret stops working immediately. - **Delete**: removes the client. **CLI** Use [`neon neon-auth oauth-client`](https://neon.com/docs/cli/neon-auth#oauth-client). Every resource you link must already be configured on the OAuth provider: ```bash neon neon-auth oauth-client create --name "Reports" --type confidential --redirect-uris https://reports.example.com/callback --resources https://api.example.com/reports ``` For a confidential client, the command prints the client secret only once. Store it before you continue. The `list`, `get`, `update`, `rotate-secret`, and `delete` subcommands manage existing clients. **API** Create a client with the [create OAuth client](https://neon.com/docs/reference/api/auth/create-neon-auth-o-auth-client) endpoint. Every entry in `resources` must already be configured on the OAuth provider. ```bash curl -X POST \ "https://console.neon.tech/api/v2/projects/{project_id}/branches/{branch_id}/auth/oauth-provider/clients" \ -H "Authorization: Bearer $NEON_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "name": "Reports", "type": "confidential", "redirect_uris": ["https://reports.example.com/callback"], "resources": ["https://api.example.com/reports"] }' ``` The response includes the `client_secret` for confidential clients. It's returned only in this response. ```json { "client_id": "", "client_secret": "", "name": "Reports", "type": "confidential", "redirect_uris": ["https://reports.example.com/callback"], "resources": ["https://api.example.com/reports"], "skip_consent": false, "disabled": false, "created_at": "2026-01-01T00:00:00Z" } ``` | Field | Description | | --------------- | ----------------------------------------------------------------------------------------------------------------------------------- | | `name` | Display name, 1-100 characters | | `type` | `confidential` or `public` | | `redirect_uris` | 1-10 redirect URIs, following the [redirect URI rules](https://neon.com/docs/auth/guides/plugins/oauth-provider#redirect-uri-rules) | | `resources` | 1-11 protected resource identifiers (up to 10 configured resources plus the MCP server resource) | | `skip_consent` | Optional. Skip the consent screen for this client. Defaults to `false` | The other client operations are under the same path: | Operation | Request | | ----------------------------------------------------------------------------------------------- | ---------------------------------------------------------------- | | [List](https://neon.com/docs/reference/api/auth/list-neon-auth-o-auth-clients) | `GET .../auth/oauth-provider/clients` | | [Retrieve](https://neon.com/docs/reference/api/auth/get-neon-auth-o-auth-client) | `GET .../auth/oauth-provider/clients/{client_id}` | | [Update](https://neon.com/docs/reference/api/auth/update-neon-auth-o-auth-client) | `PATCH .../auth/oauth-provider/clients/{client_id}` | | [Delete](https://neon.com/docs/reference/api/auth/delete-neon-auth-o-auth-client) | `DELETE .../auth/oauth-provider/clients/{client_id}` | | [Rotate secret](https://neon.com/docs/reference/api/auth/rotate-neon-auth-o-auth-client-secret) | `POST .../auth/oauth-provider/clients/{client_id}/rotate_secret` | Update accepts `name`, `redirect_uris`, `resources`, `skip_consent`, and `disabled`. At least one field is required, and a provided `redirect_uris` or `resources` list replaces the stored list. Rotating the secret of a public client fails because it has no secret. Deleting a client doesn't revoke tokens that were already issued to it. ### Redirect URI rules Redirect URIs can't contain a fragment or credentials, and they must match exactly (except for the loopback port rule for CIMD clients). Register only the redirect URIs the app uses: a broad redirect URI lets another app receive the authorization code. What else is accepted depends on how the client is created: - **Managed clients.** `https`, or `http` on a loopback host (`localhost`, `127.0.0.1`, or `[::1]`) when [localhost access](https://neon.com/docs/auth/guides/manage-auth-api#related-auth-endpoints) is enabled for the branch. Any other URI, including custom schemes such as `myapp://`, makes the request fail. - **Dynamic client registration.** `https`, `http` on the same loopback hosts, and reverse-domain private-use schemes for native clients (for example, `com.example.app:/callback`). When the registration doesn't set `application_type`, Managed Better Auth drops the redirect URIs that aren't accepted (custom schemes such as `cursor://` among them), and the registration fails only if none remain. A client that relies on a custom scheme can only connect through an `https` or loopback redirect URI. - **Client ID Metadata Documents.** `https`, `http` on a loopback host, and reverse-domain private-use schemes, as listed in the document. A loopback `http` redirect URI matches on any port. ### Skip consent **Skip consent** hides the consent screen for a client. Use it only for first-party apps you control. Don't use it for third-party clients, or for public clients: a public client's ID isn't secret, so any app that can receive a registered redirect URI could complete sign-in without the user seeing a consent screen. ## Token details - **Send `resource`.** If the authorize and token requests don't include the `resource` parameter, Managed Better Auth issues an opaque token instead of a JWT, and your resource server can't verify it. - **Access tokens** are JWTs signed with EdDSA and expire after one hour. The `aud` claim contains the requested resource. The `client_id` claim identifies the client, and `scope` lists the granted scopes. - **JWKS** is at `/.well-known/jwks.json`. - **ID tokens** don't include `name` or `email`. Call the issuer's userinfo endpoint (`/oauth2/userinfo`) with the access token to get them. - **Disabling a resource** (removing it from the configuration) stops new tokens from being issued for it. Clients stop listing it until you add it back. Access tokens that were already issued stay valid until they expire. ### Scopes and refresh tokens The scopes are fixed. A client can request any of these: | Scope | Grants | | ---------------- | ---------------------------------------------------------------- | | `openid` | An ID token, and access to the userinfo endpoint | | `profile` | `name`, `given_name`, `family_name`, and `picture` from userinfo | | `email` | `email` and `email_verified` from userinfo | | `offline_access` | A refresh token, so the client can renew access without the user | The supported grant types are `authorization_code` and `refresh_token`. Managed clients are created with both. To get a refresh token, request `offline_access` on the authorize request, with PKCE. Refresh tokens expire after 30 days and rotate on every use: each refresh returns a new refresh token. When you [protect an MCP server](https://neon.com/docs/auth/guides/plugins/oauth-provider#protect-an-mcp-server) with `mcp.resource`, Managed Better Auth sets a 30-second refresh-token reuse window for every client on the branch, not only MCP clients: a client can repeat the same refresh request for 30 seconds after the token rotates and gets the same response, so concurrent refreshes from one client succeed. ```bash curl -X POST "$ISSUER/oauth2/token" \ -u "$CLIENT_ID:$CLIENT_SECRET" \ -d grant_type=refresh_token \ -d refresh_token="$REFRESH_TOKEN" ``` A refreshed access token keeps the resource of the original authorization unless you send a `resource` that is one of those resources. ## Limitations - You must host both the login page and the consent page. There's no default UI. - Self-onboarding (CIMD or DCR) is available for the MCP server resource only. Other resources need managed clients. - No `client_credentials` grant. Tokens are always issued on behalf of a signed-in user, so machine-to-machine access isn't supported. The authorization server metadata can still list `client_credentials` in `grant_types_supported`, but token requests that use it are rejected. - CIMD `client_id` URLs must use `https` on the default port (443) and a hostname, not an IP address. They can't point at a Neon domain (such as `neon.tech` or `neon.com`, including subdomains), so a Neon Function URL doesn't work. The document must be served as JSON without redirects and be at most 5 KiB. If the fetch fails for any of these reasons, the client sees a generic "Failed to fetch metadata document" error. See the [redirect URI rules](https://neon.com/docs/auth/guides/plugins/oauth-provider#redirect-uri-rules) for what each kind of client can register. - Managed clients: up to 100 per branch, 10 redirect URIs each, and links to up to 11 resources: up to 10 configured resources plus the MCP server resource. - Scopes, token lifetimes, and other provider options aren't configurable. - Authorization requests with `prompt=login` or `max_age=0` loop back to the login page after sign-in, because continuing the flow doesn't clear these parameters. --- [Document source](https://neon.com/docs/auth/guides/plugins/openapi.md) --- > Summary: The OpenAPI plugin for Managed Better Auth ships enabled by default and exposes a Scalar-powered interactive API reference UI at /reference and an OpenAPI 3.x JSON schema endpoint at /open-api/generate-schema. Use it to browse and live-test auth endpoints (session, user, organization, admin) directly against your database, or to import the spec into Postman, Insomnia, or a Scalar SDK generator for type-safe clients in languages without a dedicated Managed Better Auth SDK. # Open API Interactive API documentation and client generation Last updated: 2026-09-16 Managed Better 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 Managed Better 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 Managed Better Auth URL. **URL Format:** ``` /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. ![Managed Better Auth Open API Reference](https://neon.com/docs/auth/openapi-reference.png) **Note: 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`). ## 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:** ``` /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 Managed Better 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 Managed Better Auth is set up according to the [Next.js quick start](https://neon.com/docs/auth/quick-start/nextjs-api-only). Unlike the default Managed Better 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 Managed Better 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 Managed Better Auth instance. --- [Document source](https://neon.com/docs/auth/guides/plugins/organization.md) --- > Summary: The Managed Better Auth Organization plugin adds multi-tenancy to apps built on Better Auth, letting each tenant share a Neon branch with role-based access (owner, admin, and member roles). Use it when your app needs workspaces or tenant isolation with invitation workflows, configurable membership limits, and per-branch enable/disable control via the Neon Console or API. The plugin exposes authClient.organization methods for creating, listing, and deleting organizations, inviting and removing members, and checking role permissions client-side. # Organization Manage multi-tenant organizations, members, and invitations Last updated: 2026-10-14 Managed Better Auth is built on [Better Auth](https://www.better-auth.com/) and comes with a pre-configured Organization plugin, so your app can support multi-tenancy without additional setup. **Note: Beta** The Organization plugin is currently in **beta**. Support for JWT token claims is available. ## Why use this plugin? Use the Organization plugin when you need multi-tenancy in your app. It supports: - Multi-tenant apps where each tenant is an organization - Workspaces or groups that share a Neon branch (same database) - Inviting users and assigning roles: owner, admin, or member - Role-based access: owners and admins can manage the org; the member role has read-only access Better Auth also has a **Teams** feature (sub-groups within an org); that feature is not currently enabled in Managed Better Auth. ## Prerequisites - A Neon project with **Auth enabled** - A signed-in user (organizations are associated with users) ## Example application **[neon-auth-orgs-example](https://github.com/neondatabase/neon-js/tree/main/examples/neon-auth-orgs-example)** is a multi-tenant sample that uses the Organization plugin with **Drizzle** and **`@neon/auth`** (see that folder's README for **bun** setup from the monorepo root). For other runnable Managed Better Auth apps, see [Example applications](https://neon.com/docs/auth/about#example-applications). ## Configure the organization plugin The Organization plugin is enabled by default for each branch; you can disable it or change settings in the Console or via the API. If the plugin is disabled, your application users and admins cannot create or manage organizations, and any organization-related API calls will return an error. **Console** Open your project in the Neon Console, then go to **Settings** > **Better Auth** and use the **Organizations** section (per branch). This section is available when your project uses **Managed Better Auth**. From there you can customize: - **Enable Organizations** (toggle): Turn the Organization plugin on or off for the branch. When off, all organization API calls are disabled and return an error. - **Limit:** Maximum total organization memberships (created + joined) per user. Once reached, the user cannot create new organizations. Default: 10. - **Membership Limit:** Maximum number of members per organization (default: 100). - **Creator role:** Role assigned to the user who creates an organization: **Owner** or **Admin**. Choose Admin if you want the org creator to have fewer privileges than Owner (for example, they cannot delete the org or change the owner). - **Send Invitation Email** (toggle): When on, invited users receive an email with an accept link. This requires **Verify email at signup** to be enabled in the Authentication configuration. Accepting the invitation requires Better Auth UI's organization components (`npx shadcn@latest add @better-auth-ui/organization`, with its `accept-invitation` view) or a custom route that handles `/auth/accept-invitation?invitationId=` in your application. When off, no email is sent and you handle invitations in your app (for example, via the [invitation ID](https://neon.com/docs/auth/guides/plugins/organization#accept-invitation) or the [user invitation list](https://neon.com/docs/auth/guides/plugins/organization#list-user-invitations)). **API** You can also configure the plugin via the [Neon API](https://neon.com/docs/reference/api). Use your API key in the `Authorization` header. **Get current plugin config (including organization):** ```bash curl -X GET \ 'https://console.neon.tech/api/v2/projects/{project_id}/branches/{branch_id}/auth/plugins' \ -H 'Accept: application/json' \ -H 'Authorization: Bearer $NEON_API_KEY' ``` Example response (excerpt showing the `organization` object): ```json { "organization": { "enabled": true, "organization_limit": 10, "membership_limit": 100, "creator_role": "owner", "send_invitation_email": false } } ``` The full response includes other plugin configs (email provider, OAuth, etc.). `creator_role` is either `owner` or `admin`. **Update the organization plugin:** Send only the fields you want to change; all request body fields are optional. ```bash curl -X PATCH \ 'https://console.neon.tech/api/v2/projects/{project_id}/branches/{branch_id}/auth/plugins/organization' \ -H 'Accept: application/json' \ -H 'Authorization: Bearer $NEON_API_KEY' \ -H 'Content-Type: application/json' \ -d '{ "enabled": true, "organization_limit": 10, "membership_limit": 100, "creator_role": "owner", "send_invitation_email": false }' ``` Example response: ```json { "enabled": true, "organization_limit": 10, "membership_limit": 100, "creator_role": "owner", "send_invitation_email": false } ``` ### API fields reference | Field | Type | Description | | :---------------------- | :-------------------------- | :----------------------------------------------------------------------------------------------------------------------------------- | | `enabled` | boolean | Turn the Organization plugin on or off for the branch. When false, all organization API calls return an error. | | `organization_limit` | number (≥ 1) | Max total organization memberships (created + joined) per user. Once reached, the user cannot create new organizations. Default: 10. | | `membership_limit` | number (≥ 1) | Max members per organization. Default: 100. | | `creator_role` | string (`owner` \| `admin`) | Role for the user who creates an org. Owner has full control; Admin cannot delete the org or change the owner. | | `send_invitation_email` | boolean | When true, invited users receive an email with an accept link. Requires verified email at signup. Default: false. | ### API Documentation - [Get all plugin configurations](https://neon.com/docs/reference/api/auth/get-neon-auth-plugin-configs) - [Update organization plugin configuration](https://neon.com/docs/reference/api/auth/update-neon-auth-organization-plugin) ## Organizations Use the following methods to manage the organization lifecycle. ### Create an organization Creates a new organization. The user creating it automatically becomes the **Owner**.
View parameters | Parameter | Type | Required | Notes | | :---------------------------- | :--------------------------------- | :------: | :-------------------------------------------------------------------- | | name | string | ✓ | The display name of the organization | | slug | string | ✓ | A URL-friendly identifier | | logo | string \| undefined | | Optional URL to a logo image for the organization | | metadata | `Record` \| undefined | | Optional JSON metadata for the organization | | userId | string \| undefined | | The user ID of the organization creator | | keepCurrentActiveOrganization | boolean \| undefined | | If `true`, does not switch the active session to the new organization |
```ts const { data, error } = await authClient.organization.create({ name: 'My Organization', slug: 'my-org', logo: 'https://example.com/logo.png', metadata: { plan: 'pro' }, keepCurrentActiveOrganization: false, }); ``` ### Check organization slug Checks if an organization slug is available.
View parameters | Parameter | Type | Required | Notes | | :-------- | :----- | :------: | :---------------- | | slug | string | ✓ | The slug to check |
```ts const { data, error } = await authClient.organization.checkSlug({ slug: 'my-org', }); ``` ### List organizations Lists all organizations the current user is a member of.
View parameters This method does not take any parameters.
```ts const { data, error } = await authClient.organization.list(); ``` In a React component, you can use the `useListOrganizations` hook to fetch and display organizations: ```tsx import { authClient } from './auth'; export default function OrganizationList() { const { data: organizations } = authClient.useListOrganizations(); return (
{organizations?.map((org) => (

{org.name}

))}
); } ``` ### Set active organization Switches the user's active context to a specific organization.
View parameters | Parameter | Type | Required | Notes | | :--------------- | :------------------ | :------: | :--------------------------------------------- | | organizationId | string \| null | | The ID to set as active. Pass `null` to unset. | | organizationSlug | string \| undefined | | Alternatively, pass the slug to set as active. |
```ts const { data, error } = await authClient.organization.setActive({ organizationId: 'org_12345678', }); ``` ### Get active organization Retrieves full details of the currently active organization.
View parameters | Parameter | Type | Required | Notes | | :--------------- | :------------------ | :------: | :------------------------------------------------------ | | organizationId | string \| undefined | | Optional ID to get details for (defaults to active org) | | organizationSlug | string \| undefined | | Optional slug to get details for | | membersLimit | number \| undefined | | Limit members returned in the response (default: 100) |
```ts const { data, error } = await authClient.organization.getFullOrganization({ query: { organizationId: 'org-id', organizationSlug: 'org-slug', membersLimit: 10, }, }); ``` In a React component, you can use the `useActiveOrganization` hook to fetch and display the active organization: ```tsx import { authClient } from './auth'; export default function ActiveOrganization() { const { data: organization } = authClient.useActiveOrganization(); return (

{organization?.name}

Members: {organization?.members.length}

); } ``` ### Update organization Updates organization details. Requires **Owner** or **Admin** permissions.
View parameters | Parameter | Type | Required | Notes | | :------------- | :----- | :------: | :---------------------------------------------------------------------- | | data | object | ✓ | Object containing fields to update (`name`, `slug`, `logo`, `metadata`) | | organizationId | string | | The ID of the organization to update |
```ts await authClient.organization.update({ data: { name: 'New Name', metadata: { plan: 'enterprise' }, }, organizationId: 'org-id', }); ``` ### Delete organization Deletes the organization and all associated data. Requires **Owner** permission.
View parameters | Parameter | Type | Required | Notes | | :------------- | :----- | :------: | :----------------------------------- | | organizationId | string | ✓ | The ID of the organization to delete |
```ts const { data, error } = await authClient.organization.delete({ organizationId: 'org-id', }); ``` ## Invitations Manage invitations to join an organization. **Note: Invitation Emails** Invitation emails are supported when [**Send Invitation Email**](https://neon.com/docs/auth/guides/plugins/organization#configure-the-organization-plugin) is enabled in the organization config. This also requires **Verify email at signup** in the Authentication configuration. Accepting an email invitation requires Better Auth UI's organization components (`npx shadcn@latest add @better-auth-ui/organization`, with its `accept-invitation` view) or a custom route handling `/auth/accept-invitation?invitationId=` in your app. When the email toggle is off, handle invitations in your app using the [invitation ID](https://neon.com/docs/auth/guides/plugins/organization#accept-invitation) or the [user invitation list](https://neon.com/docs/auth/guides/plugins/organization#list-user-invitations). ### Invite member Sends an invitation to a user.
View parameters | Parameter | Type | Required | Notes | | :------------- | :------------------- | :------: | :-------------------------------------------------- | | email | string | ✓ | Email address to invite | | role | string | ✓ | Role to assign (`owner`, `admin`, `member`) | | organizationId | string \| undefined | | ID of the organization (defaults to active org) | | resend | boolean \| undefined | | If true, resends email if invitation already exists |
```ts const { data, error } = await authClient.organization.inviteMember({ email: 'new-user@example.com', role: 'member', resend: true, }); ``` ### Accept invitation Accepts an invitation using the invitation ID.
View parameters | Parameter | Type | Required | Notes | | :----------- | :----- | :------: | :------------------------------ | | invitationId | string | ✓ | The ID from the invitation link |
```ts const { data, error } = await authClient.organization.acceptInvitation({ invitationId: 'invitation-id', }); ``` ### Reject invitation Declines an invitation that the user has received and chooses not to accept.
View parameters | Parameter | Type | Required | Notes | | :----------- | :----- | :------: | :--------------------------------- | | invitationId | string | ✓ | The ID of the invitation to reject |
```ts const { data, error } = await authClient.organization.rejectInvitation({ invitationId: 'invitation-id', }); ``` ### Cancel invitation Cancel a pending invitation that has been sent to a user.
View parameters | Parameter | Type | Required | Notes | | :----------- | :----- | :------: | :--------------------------------- | | invitationId | string | ✓ | The ID of the invitation to cancel |
```ts const { data, error } = await authClient.organization.cancelInvitation({ invitationId: 'invitation-id', }); ``` ### Get invitation Retrieves details of a specific invitation.
View parameters | Parameter | Type | Required | Notes | | :-------- | :----- | :------: | :----------------------------------- | | query.id | string | ✓ | The ID of the invitation to retrieve |
```ts const { data, error } = await authClient.organization.getInvitation({ query: { id: 'invitation-id', }, }); ``` ### List invitations Lists all pending invitations for an organization.
View parameters | Parameter | Type | Required | Notes | | :------------------- | :------------------ | :------: | :---------------------------------- | | query.organizationId | string \| undefined | | Defaults to the active organization |
```ts const { data, error } = await authClient.organization.listInvitations({ query: { organizationId: 'org-id', }, }); ``` ### List user invitations Lists all invitations received by the current user.
View parameters This method does not take any parameters.
```ts const { data, error } = await authClient.organization.listUserInvitations(); ``` ## Members Manage users within the organization. ### List members Lists members with support for pagination, sorting, and filtering.
View parameters | Parameter | Type | Required | Notes | | :------------------- | :-------------------------------------- | :------: | :------------------------------------------ | | query.organizationId | string \| undefined | | Defaults to the active organization | | query.limit | number \| undefined | | Items per page (default: 100) | | query.offset | number \| undefined | | Items to skip | | query.sortBy | string \| undefined | | Field to sort by (for example, `createdAt`) | | query.sortDirection | "asc" \| "desc" \| undefined | | Sort direction | | query.filterField | string \| undefined | | Field to filter by | | query.filterOperator | "eq" \| "ne" \| "gt" \| "contains" etc. | | Operator for filtering | | query.filterValue | string \| undefined | | Value to filter for |
```ts const { data, error } = await authClient.organization.listMembers({ query: { limit: 20, offset: 0, sortBy: 'createdAt', sortDirection: 'desc', filterField: 'role', filterOperator: 'eq', filterValue: 'admin', }, }); ``` ### Update member role Updates a member's role.
View parameters | Parameter | Type | Required | Notes | | :------------- | :------------------ | :------: | :------------------------------------------------- | | memberId | string | ✓ | The ID of the member to update | | role | string\| string\[] | ✓ | New role(s) to assign (`owner`, `admin`, `member`) | | organizationId | string \| undefined | | Defaults to active organization |
```ts const { data, error } = await authClient.organization.updateMemberRole({ memberId: 'member-id', role: 'admin', }); ``` ### Remove member Removes a member from the organization.
View parameters | Parameter | Type | Required | Notes | | :-------------- | :------------------ | :------: | :------------------------------ | | memberIdOrEmail | string | ✓ | Member ID or Email address | | organizationId | string \| undefined | | Defaults to active organization |
```ts const { data, error } = await authClient.organization.removeMember({ memberIdOrEmail: 'member-id-or-email', }); ``` ### Get active member Gets the current user's membership details for the active organization.
View parameters This method does not take any parameters.
```ts const { data, error } = await authClient.organization.getActiveMember(); ``` ### Get Active Member Role Gets the current user's role(s) in the active organization.
View parameters This method does not take any parameters.
```ts const { data, error } = await authClient.organization.getActiveMemberRole(); ``` ### Leave organization Removes the current user from an organization.
View parameters | Parameter | Type | Required | Notes | | :------------- | :----- | :------: | :---------------------------------- | | organizationId | string | ✓ | The ID of the organization to leave |
```ts const { data, error } = await authClient.organization.leave({ organizationId: 'org-id', }); ``` ## Access Control The Organization plugin includes a Role-Based Access Control (RBAC) system. | Role | Permissions | | :--------- | :----------------------------------------------------------------------------------------------------------------------------------------- | | **Owner** | Full control. Can delete the organization and manage all roles. The user who creates the organization is automatically assigned this role. | | **Admin** | Can invite members, update roles, and manage organization settings. Cannot delete the organization. | | **Member** | Read-only access to organization data. Cannot manage other members. | You can check permissions on the client side using `checkRolePermission`: ```ts const canDelete = authClient.organization.checkRolePermission({ permission: { organization: ['delete'], }, role: 'admin', // returns false, admins cannot delete orgs }); // console.log(canDelete); // false ``` ## Limitations Because Managed Better Auth is a managed service, some Better Auth features are not currently supported: - **Teams:** The Teams sub-feature is not currently enabled. - **Hooks:** Server-side hooks (for example, `beforeCreateOrganization`) are not supported. - **Custom Permissions:** You cannot currently define custom roles or modify default permissions. - **Dynamic Access Control:** Dynamic creation of roles via API is not enabled. Check the [Managed Better Auth roadmap](https://neon.com/docs/auth/roadmap) for updates on these features. --- [Document source](https://neon.com/docs/auth/guides/plugins/phone-number.md) --- > Summary: The Phone Number plugin for Managed Better Auth adds SMS OTP sign-in for existing users: when a user submits their E.164 phone number, Managed Better Auth fires a `send.otp` webhook carrying a numeric code that your handler forwards to your SMS provider (Twilio, Vonage, MessageBird, etc.). Use this page when you need phone OTP sign-in for users who already have a verified phone number linked to their account; phone-first sign-up is not supported. OTP expiry is configurable, requests are rate-limited per IP, and an OTP is invalidated after too many incorrect attempts. # Phone Number Sign in existing users with phone OTP codes delivered via your SMS provider Last updated: 2026-10-09 Managed Better Auth is built on [Better Auth](https://www.better-auth.com/) and supports the [Phone Number](https://www.better-auth.com/docs/plugins/phone-number) plugin through the Neon SDK. Phone Number lets an existing user sign in with a one-time password (OTP) delivered to their phone. The flow works like this: 1. The user enters their phone number in E.164 format (for example, `+15551234567`). 2. Managed Better Auth generates a 6-digit OTP and fires the `send.otp` webhook with `delivery_preference: "sms"`. Your webhook handler delivers the code via your SMS provider. 3. The user enters the code. Managed Better Auth verifies it, creates a session, and signs them in. **Important:** The Phone Number plugin is **sign-in only**. Users must already exist in your project with a phone number linked to their account. There is no phone-first sign-up path. Managed Better Auth does **not** deliver SMS for you. The plugin requires a `send.otp` webhook that forwards codes to your SMS provider (Twilio, MessageBird, Vonage, etc.). ## Prerequisites - A Neon project with **Auth enabled** - An existing user with a phone number linked to their account - A webhook subscribed to the `send.otp` event that forwards the code to your SMS provider (see the [Webhooks guide](https://neon.com/docs/auth/guides/webhooks)) ## Enable Phone Number **Console** 1. Open the [Neon Console](https://console.neon.tech). 2. Select your project and go to **Settings** > **Better Auth**. 3. In the **Phone Authentication** section, toggle **Enable Phone Authentication** on. 4. Configure the options: - **OTP Expiry** (60-600 seconds, default: 300) controls how long a generated OTP stays valid. **API** Configure the Phone Number plugin with a `PATCH` request. All request body fields are optional; send only the fields you want to change. A `GET` on the same endpoint returns the current configuration. ```bash curl -X PATCH \ "https://console.neon.tech/api/v2/projects/{project_id}/branches/{branch_id}/auth/plugins/phone-number" \ -H "Authorization: Bearer $NEON_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "enabled": true, "otp_expires_in": 300 }' ``` Both `PATCH` and `GET` return the configuration: ```json { "enabled": true, "otp_expires_in": 300 } ``` | Field | Type | Default | Description | | ---------------- | ------- | ------- | ----------------------------------------- | | `enabled` | boolean | `false` | Whether the Phone Number plugin is active | | `otp_expires_in` | integer | `300` | Seconds before the OTP expires (60-600) | ## Deliver OTPs via your SMS provider Managed Better Auth fires the `send.otp` webhook with `delivery_preference: "sms"` when an OTP needs delivery. Your handler must deliver the code through your SMS provider (Twilio, MessageBird, Vonage, etc.). Without a `send.otp` webhook, `authClient.phoneNumber.sendOtp()` fails. Configure a webhook subscribed to `send.otp` (see the [Webhooks guide](https://neon.com/docs/auth/guides/webhooks) for full setup and signature verification), then branch on `delivery_preference` in your handler: ```ts filename="app/api/webhooks/neon-auth/route.ts" import { NextResponse } from 'next/server'; import twilio from 'twilio'; const twilioClient = twilio( process.env.TWILIO_ACCOUNT_SID!, process.env.TWILIO_AUTH_TOKEN! ); export async function POST(request: Request) { const payload = await request.json(); // verify the signature first in production if (payload.event_type === 'send.otp' && payload.event_data.delivery_preference === 'sms') { const toNumber = payload.user?.phone_number; if (!toNumber) { return NextResponse.json({ error: 'missing phone number' }, { status: 400 }); } await twilioClient.messages.create({ from: process.env.TWILIO_FROM_NUMBER!, to: toNumber, body: `Your code is ${payload.event_data.otp_code}.`, }); } return NextResponse.json({ ok: true }); } ``` **Note: User context for first OTPs** When an unauthenticated user requests their first phone OTP (no prior account linked to that phone number), the webhook `user` object contains the `phone_number` only. Do not rely on `user.name`, `user.email`, or other profile fields when templating the SMS for first-time sends. For a runnable Next.js handler, signature verification, and a local tunneling setup, see the [nextjs-phone-login example](https://github.com/neondatabase/neon-js/tree/main/examples/nextjs-phone-login). ## Link a phone number to a user Link a phone to an existing user from an authenticated session by calling `authClient.phoneNumber.verify()` with `updatePhoneNumber: true`: ```ts filename="src/link-phone-number.ts" import { authClient } from '@/lib/auth/client'; export async function sendLinkingOtp(phoneNumber: string) { const { error } = await authClient.phoneNumber.sendOtp({ phoneNumber }); if (error) throw error; } export async function linkPhoneNumber(phoneNumber: string, code: string) { const { data, error } = await authClient.phoneNumber.verify({ phoneNumber, code, updatePhoneNumber: true, }); if (error) throw error; return data; } ``` For a complete "Add phone number" form with session-aware state (no number, unverified, verified), see the `AddPhoneForm` component in the [nextjs-phone-login example](https://github.com/neondatabase/neon-js/tree/main/examples/nextjs-phone-login). ## Sign in an existing user with phone OTP Build a two-step phone sign-in form: send the OTP, then verify it. Do **not** pass `updatePhoneNumber`. Omitting it tells Better Auth to sign in the existing user rather than link a phone number: ```ts filename="src/phone-otp.ts" import { authClient } from '@/lib/auth/client'; export async function sendPhoneOtp(phoneNumber: string) { const { error } = await authClient.phoneNumber.sendOtp({ phoneNumber }); if (error) throw error; } export async function signInWithPhoneOtp(phoneNumber: string, code: string) { const { data, error } = await authClient.phoneNumber.verify({ phoneNumber, code, }); if (error) throw error; return data; } ``` For a complete working form with resend, error handling, and attempt-budget awareness, see the [nextjs-phone-login example](https://github.com/neondatabase/neon-js/tree/main/examples/nextjs-phone-login). ## Use Phone Number alongside UI components If you're using [Better Auth UI](https://neon.com/docs/auth/reference/ui-components), render your own phone sign-in form next to `` on the sign-in route: ```tsx filename="app/auth/[path]/page.tsx" import { viewPaths } from '@better-auth-ui/core'; import { Auth } from '@/components/auth/auth'; import { PhoneSignInSection } from './phone-sign-in-section'; // your own component export default async function AuthPage({ params }: { params: Promise<{ path: string }> }) { const { path } = await params; const isSignIn = path === viewPaths.auth.signIn; return ( <> {isSignIn && } ); } ``` `PhoneSignInSection` is a component you write that wraps your phone sign-in form. See the [nextjs-phone-login example](https://github.com/neondatabase/neon-js/tree/main/examples/nextjs-phone-login) for a complete implementation. **Info:** If you haven't set up Better Auth UI yet, see the [UI components reference](https://neon.com/docs/auth/reference/ui-components) for setup, or the [Next.js](https://neon.com/docs/auth/quick-start/nextjs-api-only) or [React](https://neon.com/docs/auth/quick-start/react) quick start for building custom forms instead. ## Webhook events The Phone Number plugin uses two webhook events: - `send.otp` (blocking). See [Deliver OTPs via your SMS provider](https://neon.com/docs/auth/guides/plugins/phone-number#deliver-otps-via-your-sms-provider). - `phone_number.verified` (non-blocking). Fires after a user successfully verifies a phone number. See the [Webhooks guide](https://neon.com/docs/auth/guides/webhooks) for payload structure, signature verification, and retry behavior. ## Limitations - **Sign-in only.** Users must already exist with a linked, verified phone number. No phone-first sign-up. - **Bring your own SMS provider.** No built-in SMS delivery. Requires a `send.otp` webhook forwarding to your SMS provider. - **E.164 format required.** Phone numbers must match `^\+[1-9]\d{1,14}$` (for example, `+15551234567`). Numbers with spaces, dashes, or parentheses are rejected. - **OTP length is fixed at 6 digits.** Not configurable. - **Rate limit.** Calls to `/phone-number/*` endpoints are limited to 10 requests per 60 seconds per IP, in addition to Managed Better Auth's global rate limits. - **Attempt lockout.** After 3 incorrect codes, the OTP is invalidated. Request a new one to try again. --- [Document source](https://neon.com/docs/auth/guides/setup-oauth.md) --- > Summary: Managed Better Auth OAuth setup adds Google, GitHub, Vercel, Microsoft, and Apple social sign-in to an application using `signIn.social()`, with Google enabled in development via shared credentials and the other providers requiring custom OAuth app credentials. For production, register the provider's authorized redirect URI as `{NEON_AUTH_BASE_URL}/callback/{provider}` in each provider's console (not the app's callbackURL), and add every callbackURL origin to Managed Better Auth's trusted domains allowlist. Because each Neon branch has its own Auth base URL, OAuth credentials and redirect URIs must be configured per branch; preview deployments can use wildcard trusted domain patterns to cover multiple hosts. # Set up OAuth Add Google, GitHub, Vercel, Microsoft, or Apple sign-in to your application Last updated: 2026-09-17 OAuth lets users sign in with their Google, GitHub, Vercel, Microsoft, or Apple account. Managed Better 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. ### About shared credentials Shared credentials let you add Google sign-in with no setup, using a Google OAuth app that Neon owns. That one app is shared by every project that uses shared credentials, including projects belonging to other Neon users. It isn't unique to you. When someone signs in, Google shows them Neon's name and logo, not your app's, because the sign-in runs through Neon's app rather than one you own. Your users are effectively trusting Neon, and you don't control the app's branding, its permission scopes, or the credentials. This is safe for development and testing. An outside website can't use the shared app to capture your users, because Google only ever redirects sign-ins back to Neon, and Neon keeps each project's sign-ins separate. The reason not to use it in production is trust and control. Real users should see your app on the consent screen, and you should own the credentials. For production, add your own Google Client ID and secret. See [Production setup](https://neon.com/docs/auth/guides/setup-oauth#production-setup). **Note:** GitHub, Vercel, Microsoft, and Apple OAuth require custom credentials and are not available with shared credentials. See [Production setup](https://neon.com/docs/auth/guides/setup-oauth#production-setup) to configure your own OAuth apps. ## Sign in with OAuth Call `signIn.social()` with your provider (`"google"`, `"github"`, `"vercel"`, `"microsoft"`, or `"apple"`). The SDK sends the user to the provider's sign-in page. After the user authorizes, the provider redirects to Managed Better Auth's OAuth callback route (see [Production setup](https://neon.com/docs/auth/guides/setup-oauth#production-setup)), then Managed Better Auth redirects the browser to your **`callbackURL`** (must use a [trusted domain](https://neon.com/docs/auth/guides/configure-domains) in production). **Google** ```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); } }; ``` **GitHub** ```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); } }; ``` **Vercel** ```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); } }; ``` **Microsoft** ```jsx {6} filename="src/App.jsx" import { authClient } from './auth'; const handleMicrosoftSignIn = async () => { try { await authClient.signIn.social({ provider: "microsoft", callbackURL: window.location.origin, }); } catch (error) { console.error("Microsoft sign-in error:", error); } }; ``` **Apple** ```jsx {6} filename="src/App.jsx" import { authClient } from './auth'; const handleAppleSignIn = async () => { try { await authClient.signIn.social({ provider: "apple", callbackURL: window.location.origin, }); } catch (error) { console.error("Apple sign-in error:", error); } }; ``` ## Handle the callback After the OAuth exchange completes, Managed Better Auth redirects the browser to your **`callbackURL`**. Then load or refresh session state in your client: ```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", "microsoft", "apple" callbackURL: "/dashboard", newUserCallbackURL: "/welcome", errorCallbackURL: "/error", }); ``` ## Production setup For production, configure your own OAuth app credentials. GitHub, Vercel, Microsoft, and Apple OAuth require custom credentials, while Google OAuth works with shared credentials for development but should use custom credentials in production. ### 1. Register redirect URIs with each provider Managed Better Auth uses [Better Auth](https://www.better-auth.com/) callback routes. For each OAuth provider you enable, register a redirect URI with this shape: ```text {NEON_AUTH_BASE_URL}/callback/{provider} ``` Use the **Auth base URL** from the Neon Console for that branch. In your app it is usually the `NEON_AUTH_BASE_URL` or `VITE_NEON_AUTH_URL` value, or the URL you pass to `createAuthClient`. Do not add a trailing slash before `/callback`. Replace `{provider}` with `google`, `github`, `vercel`, `microsoft`, or `apple`. Example authorized redirect URI for Google: ```text https://ep-example.neonauth.us-east-2.aws.neon.tech/neondb/auth/callback/google ``` Whether you use the [Next.js auth proxy](https://neon.com/docs/auth/reference/nextjs-server#auth-handler) (`app/api/auth/[...path]/route.ts`) or call Managed Better Auth from the browser, the provider redirects to **`{NEON_AUTH_BASE_URL}/callback/{provider}`** for that branch. **Important: Do not confuse two different URLs** The **`callbackURL`** argument in `signIn.social()` is where users land **after** Managed Better Auth finishes the flow. That URL must live on an origin you add under [trusted domains](https://neon.com/docs/auth/guides/configure-domains). The provider's **authorized redirect URI** is where Google (or GitHub, and so on) sends the browser **during** the OAuth handshake. It must be **`{NEON_AUTH_BASE_URL}/callback/{provider}`**, not your app's homepage or only the `callbackURL`. Using only your marketing site's URL in Google Cloud Console, or only the `callbackURL`, is a common cause of `redirect_uri_mismatch`. **Google Cloud Console** Create an OAuth client with application type **Web application**. Under **Authorized redirect URIs**, add **`{NEON_AUTH_BASE_URL}/callback/google`** for each branch or environment (production, local testing against a branch, previews). Under **Authorized JavaScript origins**, include origins where your UI runs (for example `http://localhost:5173`, `https://myapp.com`) when Google asks for them, and include your Managed Better Auth origin (the scheme and host of `NEON_AUTH_BASE_URL`) if required. **GitHub** Set **Authorization callback URL** to **`{NEON_AUTH_BASE_URL}/callback/github`**. **Vercel** Set the authorization callback URL to **`{NEON_AUTH_BASE_URL}/callback/vercel`**. In the Vercel app's permissions, enable the **`openid`**, **`email`**, and **`profile`** scopes, which Managed Better Auth requires to create a session. See [Vercel's OAuth app docs](https://vercel.com/docs/sign-in-with-vercel/manage-from-dashboard#create-an-app). **Microsoft** See [Microsoft setup](https://neon.com/docs/auth/guides/setup-oauth#microsoft-setup) for the redirect URI, tenant, and email verification settings. **Apple** See [Apple setup](https://neon.com/docs/auth/guides/setup-oauth#apple-setup). Apple requires an HTTPS redirect URI, so it can't be used with `localhost`. ### 2. Add trusted domains for your app Before testing production OAuth, add every origin you pass as **`callbackURL`** (and related URLs) to Managed Better Auth's allowlist. See [Configure trusted domains](https://neon.com/docs/auth/guides/configure-domains). ### 3. Create OAuth apps and paste credentials into Neon Create OAuth apps with your providers: - [Google OAuth setup](https://developers.google.com/identity/protocols/oauth2/web-server) (see [Google OAuth branding](https://neon.com/docs/auth/guides/setup-oauth#google-oauth-branding) below before going live) - [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) - [Microsoft setup](https://neon.com/docs/auth/guides/setup-oauth#microsoft-setup) - [Apple setup](https://neon.com/docs/auth/guides/setup-oauth#apple-setup) Then give the **Client ID** and **Client Secret** to Managed Better Auth for that branch. Apple and Microsoft take a few extra fields, described in their sections below. **Console** In the Neon Console, open your **project** and select the **branch**, then go to **Settings → Auth**. Under **OAuth providers**, click **Add OAuth provider** (or open an existing provider's **⋮** menu and choose **Configure**). The dialog shows the exact **authorization callback URL** to register with the provider (for example, `{NEON_AUTH_BASE_URL}/callback/github`). Copy it from the dialog rather than assembling it by hand, then enter your **Client ID** and **Client Secret**. Click **Add** (or **Update** when editing an existing provider) to save. Neon applies the change to the branch and confirms with a success message. Your app uses the new credentials on the next sign-in. A provider using Neon's shared credentials shows a **Shared credentials** badge until you add your own. To disable a provider, open its **⋮** menu and choose **Remove**. Its sign-in button no longer appears in your app. **CLI** Add a provider with [`neon neon-auth oauth-provider add`](https://neon.com/docs/cli/neon-auth#oauth-provider-add): ```bash neon neon-auth oauth-provider add --provider-id google --oauth-client-id --oauth-client-secret ``` For Apple, pass the `.p8` key file, your Team ID, and the Key ID. For Microsoft, `--microsoft-tenant-id` is optional: ```bash neon neon-auth oauth-provider add --provider-id apple --oauth-client-id --oauth-client-secret-file AuthKey_XXXXXXXXXX.p8 --apple-team-id --apple-key-id neon neon-auth oauth-provider add --provider-id microsoft --oauth-client-id --oauth-client-secret --microsoft-tenant-id ``` **API** Send a `POST` request to the [add OAuth provider](https://neon.com/docs/reference/api/auth/add-branch-neon-auth-oauth-provider) endpoint. Replace `{project_id}` and `{branch_id}` with your project and branch IDs. ```bash curl -X POST 'https://console.neon.tech/api/v2/projects/{project_id}/branches/{branch_id}/auth/oauth_providers' \ -H 'Authorization: Bearer $NEON_API_KEY' \ -H 'Content-Type: application/json' \ -d '{"id": "google", "client_id": "", "client_secret": ""}' ``` Apple and Microsoft accept additional fields. For Apple, `client_secret` is the full contents of the `.p8` file, including the `BEGIN` and `END` lines, with newlines encoded as `\n` in JSON: ```json { "id": "apple", "client_id": "", "client_secret": "", "apple_team_id": "", "apple_key_id": "" } ``` ```json { "id": "microsoft", "client_id": "", "client_secret": "", "microsoft_tenant_id": "" } ``` Managed Better Auth will use your configured credentials for that branch. ### Branches and preview deployments Each branch has its own **`NEON_AUTH_BASE_URL`**. Register **`{NEON_AUTH_BASE_URL}/callback/google`** (and other providers you use) for every branch you test against (for example preview databases). For preview deployments, trusted domains support **wildcard patterns** (for example `https://*.my-app-preview.vercel.app`), so you can cover many preview hosts without listing each one. See [Configure trusted domains](https://neon.com/docs/auth/guides/configure-domains), [Branching authentication](https://neon.com/docs/auth/branching-authentication), and the API for [trusted domains](https://neon.com/docs/reference/api/auth/add-branch-neon-auth-trusted-domain). ## Microsoft setup Register an app in the [Microsoft Entra admin center](https://entra.microsoft.com) and give its credentials to Managed Better Auth. 1. Go to **Entra ID** > **App registrations** and select **New registration**. 2. Choose the **Supported account types** that match who should be able to sign in. This setting should agree with the tenant value you set in Neon (see below). 3. Under **Redirect URI**, select the **Web** platform and enter **`{NEON_AUTH_BASE_URL}/callback/microsoft`**. 4. After you register the app, copy the **Application (client) ID**. 5. Go to **Certificates & secrets**, create a **New client secret**, and copy its **Value**. Microsoft shows the value only once. 6. Add the Client ID and Client Secret to the branch, as described in [Create OAuth apps and paste credentials into Neon](https://neon.com/docs/auth/guides/setup-oauth#3-create-oauth-apps-and-paste-credentials-into-neon). Microsoft client secrets expire. Create a new secret and update the provider in Neon before the old one expires. ### Tenant By default, Managed Better Auth signs users in against the `common` Microsoft endpoint. To restrict sign-in, set the optional **`microsoft_tenant_id`** (`--microsoft-tenant-id` in the CLI) to one of: | Value | Who can sign in | | --------------- | ---------------------------------------------------------------- | | `common` | Work or school accounts from any tenant, and personal accounts | | `organizations` | Work or school accounts from any tenant | | `consumers` | Personal Microsoft accounts only | | A tenant ID | Accounts in that tenant (a GUID) | | A tenant domain | Accounts in that tenant (for example, `contoso.onmicrosoft.com`) | The tenant value must be compatible with the **Supported account types** you chose for the app registration. The tenant ID is returned in API responses. ### Email verification Managed Better Auth treats a Microsoft email as verified only when Microsoft says the user's home tenant owns the email domain. Microsoft sends this in two optional ID token claims, `xms_edov` and `acct`. They aren't in the token by default, so you add them to your app registration. Without these claims, Microsoft sign-in still works, but the email is treated as unverified: - If a user with the same email already exists (for example, from Google, GitHub, or email and password), Microsoft sign-in fails with `account_not_linked` and no account is created. - A new user who signs in with Microsoft is created with an unverified email. - A signed-in user can't link a Microsoft account, and the attempt fails with `unable_to_link_account`. To add the claims: 1. In the Entra admin center, go to **Entra ID** > **App registrations** and select your app. 2. Under **Manage**, select **Token configuration**. 3. Select **Add optional claim**, choose the **ID** token type, select `acct` and `xms_edov`, then select **Add**. 4. If you're asked to turn on the Microsoft Graph `email` permission, accept. `xms_edov` is sent only when the token also has the `email` claim. You can also edit the app manifest (**Manage** > **Manifest**). Keep any optional claims you already have: ```json "optionalClaims": { "idToken": [ { "name": "acct", "essential": false }, { "name": "xms_edov", "essential": false }, { "name": "email", "essential": false } ] } ``` Managed Better Auth marks the email verified only when `xms_edov` is `true` and `acct` is `0`: - `xms_edov` is `true` when the email belongs to a domain that the user's tenant has verified. - `acct` is `0` for a member of the tenant and `1` for a guest. Users who sign in as guests or with a personal Microsoft account don't meet both conditions, so their emails stay unverified. See Microsoft's [optional claims reference](https://learn.microsoft.com/en-us/entra/identity-platform/optional-claims-reference) and [Configure optional claims](https://learn.microsoft.com/en-us/entra/identity-platform/optional-claims). ## Apple setup Sign in with Apple needs four values from your [Apple Developer account](https://developer.apple.com/account): | Apple value | Managed Better Auth field | | ------------------------------ | ----------------------------------------------------------------- | | Services ID | Client ID (`client_id`) | | Sign in with Apple key (`.p8`) | Client secret (`client_secret`), the full multi-line PEM contents | | Team ID | `apple_team_id` | | Key ID (10 characters) | `apple_key_id` | To get them: 1. Under **Certificates, Identifiers & Profiles** > **Identifiers**, create an **App ID** with the **Sign in with Apple** capability enabled if you don't have one. 2. Create a **Services ID**. Enable **Sign in with Apple** for it and select **Configure**. 3. Set the primary App ID. Add your Auth base URL's host as a **Domain**, and add **`{NEON_AUTH_BASE_URL}/callback/apple`** as a **Return URL**. For example: ```text https://ep-example.neonauth.us-east-2.aws.neon.tech/neondb/auth/callback/apple ``` 4. Under **Keys**, create a key with **Sign in with Apple** enabled, associated with your App ID. Download the `.p8` file (Apple lets you download it once) and note the **Key ID**. 5. Copy your **Team ID** from the Membership details page. Apple requires an HTTPS return URL, so `localhost` URLs aren't accepted. Managed Better Auth signs the client secret JWT that Apple expects, using your private key, so you don't generate or rotate a client secret yourself. API responses show a masked fingerprint of the key and never return the key itself. To rotate the key, create a new key in Apple Developer and update the provider with the new `.p8` contents. The request must include the new key's `apple_key_id` (`--apple-key-id`) in the same request. ## Google OAuth branding When using your own Google OAuth credentials, users will see a consent screen before signing in. Google shows a **Continue to** label that uses the hostname from your OAuth redirect URI (see [Production setup](https://neon.com/docs/auth/guides/setup-oauth#production-setup)), typically the Neon-managed host from your **`NEON_AUTH_BASE_URL`**. Without completing the OAuth consent screen branding (app name, support email, and authorized domains in Google Cloud Console), the consent UI can look generic or confusing even when your Client ID and Client Secret are correct. To show your app's name on the consent screen: 1. Go to [Google Cloud Console → OAuth consent screen](https://console.cloud.google.com/auth/branding) 2. Fill in the required app information: - **App name**: the name users will see on the consent screen - **User support email**: a contact email for users with auth questions - **Developer contact information**: your email address (not shown to users) 3. Under **Authorized domains**, add your app's domain (for example, `myapp.com`) 4. Save your changes **Important: Verification required for public apps** Apps in **Testing** status only allow Google accounts you list as **test users**. Everyone else sees errors or a blocked consent flow regardless of branding. To show your production branding and allow all users, publish the OAuth consent screen and complete Google verification when required. Verification typically takes a few business days but can take longer depending on the scopes you request. - [Email Verification](https://neon.com/docs/auth/guides/email-verification): Add email verification --- [Document source](https://neon.com/docs/auth/guides/user-management.md) --- > Summary: Managed Better Auth user management exposes `updateUser()` to edit profile fields such as display name, and `changePassword()` to change passwords for signed-in users while requiring the current password for verification. Use this page when you need to update account settings or change credentials after sign-in, not for password reset flows or email verification, which are covered in separate guides. The `revokeOtherSessions` flag in `changePassword()` lets you sign out all other devices in the same call. # User management Update profiles, change passwords, and manage account settings Last updated: 2026-11-05 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 **Note:** Email address changes are not currently supported. To reset a forgotten password, see [Password Reset](https://neon.com/docs/auth/guides/password-reset). ## Change password Passwords can be up to 128 characters. Sign-up and sign-in reject longer passwords with a `400` `PASSWORD_TOO_LONG` error. 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 }); ``` **Note:** If a user forgot their password, use the password reset flow (`requestPasswordReset()` and `resetPassword()`) instead. See [Password Reset](https://neon.com/docs/auth/guides/password-reset). To sign users out of every session after a reset, turn on [Revoke sessions on password reset](https://neon.com/docs/auth/guides/password-reset#sign-users-out-after-a-reset). ## 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. - [Password Reset](https://neon.com/docs/auth/guides/password-reset): Reset forgotten passwords - [Email Verification](https://neon.com/docs/auth/guides/email-verification): Verify email addresses - [Authentication Flow](https://neon.com/docs/auth/authentication-flow): Understand the auth flow --- [Document source](https://neon.com/docs/auth/guides/webhooks.md) --- > Summary: Managed Better Auth webhooks send HTTP POST requests to your server when authentication events occur, letting you replace the built-in email provider with custom delivery channels (SMS, WhatsApp, custom email) and intercept user signups before they are written to the database. Use this page when you need to override OTP or magic link delivery, block signups by domain, or sync new users to external systems. Webhooks support events including send.otp, send.magic_link, user.before_create, user.created, organization.invitation.created, organization.invitation.accepted, and phone_number.verified, use EdDSA Ed25519 detached JWS signatures for verification, and retry blocking events within a global timeout. # Webhooks Handle authentication events with custom server logic Last updated: 2026-09-16 Managed Better Auth webhooks send HTTP POST requests to your server when authentication events occur. By default, Managed Better Auth handles OTP and magic link delivery through its built-in email provider. Webhooks let you replace this with your own delivery channels (SMS, custom email templates, WhatsApp) so you control how verification messages reach your users. Webhooks also let you hook into the user creation lifecycle to validate signups before they happen or sync new user data to external systems like CRMs and analytics platforms. For a quick overview of available email customization options, check out [Customize emails](https://neon.com/docs/auth/guides/customize-emails). For a step-by-step Next.js walkthrough that implements signature verification, custom OTP and magic link emails with Resend, blocking signups by email domain, optional SMS delivery, and local testing with ngrok, see [Customizing Managed Better Auth with Webhooks](https://neon.com/guides/neon-auth-webhooks-nextjs). ## Supported events | Event | Type | Trigger | Use case | | ---------------------------------- | ------------ | -------------------------------------------------------------- | ------------------------------------------------------------------------- | | `send.otp` | Blocking | OTP code needs delivery | Custom OTP delivery via SMS or email service | | `send.magic_link` | Blocking | Magic link needs delivery | Custom link delivery via any channel | | `user.before_create` | Blocking | User attempts to sign up (before database write) | Signup validation, allowlists, user data enrichment | | `user.created` | Non-blocking | User created in the database | Sync to CRM, analytics, post-signup workflows | | `phone_number.verified` | Non-blocking | User successfully verified a phone number | Post-verification workflows for phone OTP sign-in or phone number linking | | `organization.invitation.created` | Non-blocking | An organization invitation is created | Custom invitation emails, audit logging, sync with external systems | | `organization.invitation.accepted` | Non-blocking | A user accepts an organization invitation and becomes a member | Provision resources, update permissions, post-acceptance workflows | **Blocking** events pause the auth flow until your server responds (or the timeout expires). **Non-blocking** events are fire-and-forget; failures do not affect the user. When you subscribe to `send.otp` or `send.magic_link`, Managed Better Auth skips its built-in email delivery for that event. Your webhook handler is responsible for delivering the code or link. ## Configure webhooks Configure webhooks per project and branch using the Neon Console, CLI, or API. Your webhook URL must use HTTPS protocol. See the API reference for [Get webhook configuration](https://neon.com/docs/reference/api/auth/get-neon-auth-webhook-config) and [Update webhook configuration](https://neon.com/docs/reference/api/auth/update-neon-auth-webhook-config). ```bash PUT /projects/{project_id}/branches/{branch_id}/auth/webhooks GET /projects/{project_id}/branches/{branch_id}/auth/webhooks ``` Both endpoints use the following fields: | Field | Type | Description | | ----------------- | ------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | `enabled` | boolean (required) | Enable or disable webhook delivery | | `webhook_url` | string | HTTPS endpoint to receive webhook POST requests | | `enabled_events` | string\[] | Event types to subscribe to: `send.otp`, `send.magic_link`, `user.before_create`, `user.created`, `phone_number.verified`, `organization.invitation.created`, `organization.invitation.accepted` | | `timeout_seconds` | integer (1-10) | Per-attempt timeout in seconds. Default: 5. Total delivery time across all attempts is capped at 15 seconds. See [Retry behavior](https://neon.com/docs/auth/guides/webhooks#retry-behavior). | ### Webhook URL requirements Managed Better Auth validates `webhook_url` when you configure webhooks to reduce SSRF risk. Your URL must meet these rules: - **HTTPS only** — HTTP URLs are rejected. - **Hostname required** — Use a domain name (for example `https://your-app.com/webhooks/neon-auth`). Raw IP addresses (for example `https://93.184.216.34/webhook`) are rejected, including public IPs. - **No internal targets** — Localhost, private IP addresses, link-local addresses (including cloud metadata endpoints), and encoded IP bypass formats (octal, decimal, hex) are blocked. - **No redirects** — Webhook delivery does not follow HTTP `3xx` redirects. Configure the final HTTPS endpoint directly. - **DNS pinning during delivery** — Managed Better Auth validates the hostname's resolved IP addresses and only connects to that validated set. If DNS later resolves the same hostname to a different IP during delivery, the delivery is blocked as a DNS rebinding attempt. Digit-prefixed domains such as `1password.com` are allowed. If configuration fails validation, the API returns an error with code `INVALID_WEBHOOK_URL_FORMAT`. **Warning: Internal webhook targets are not supported** Webhook endpoints that point at private networks, localhost, cloud metadata services, raw IP literals, or endpoints reached only after a redirect are rejected or blocked during delivery. If an existing webhook depended on an internal target, move it behind a public HTTPS hostname before enabling Managed Better Auth webhooks. ### Set or update configuration **Console** In the Neon Console, go to **Auth → Configuration → Webhooks** to enable webhook delivery, set the **Webhook URL** (an HTTPS endpoint; see [Webhook URL requirements](https://neon.com/docs/auth/guides/webhooks#webhook-url-requirements)), choose which events to send, and set the per-attempt timeout in seconds (1-10, default 5). Save to apply. **CLI** ```bash neon neon-auth config webhook update --enabled --url https://your-app.com/webhooks/neon-auth --enabled-events user.created --timeout 5 ``` **API** ```bash curl -X PUT "https://console.neon.tech/api/v2/projects/{project_id}/branches/{branch_id}/auth/webhooks" \ -H "Content-Type: application/json" \ -H "Authorization: Bearer $NEON_API_KEY" \ -d '{ "enabled": true, "webhook_url": "https://your-app.com/webhooks/neon-auth", "enabled_events": ["send.otp", "send.magic_link", "user.before_create", "user.created", "phone_number.verified", "organization.invitation.created", "organization.invitation.accepted"], "timeout_seconds": 5 }' ``` ### Get current configuration **Console** View the current webhook configuration under **Auth → Configuration → Webhooks** in the Neon Console. **CLI** ```bash neon neon-auth config webhook get ``` **API** ```bash curl "https://console.neon.tech/api/v2/projects/{project_id}/branches/{branch_id}/auth/webhooks" \ -H "Authorization: Bearer $NEON_API_KEY" ``` Both endpoints return the configuration in the same format: ```json { "enabled": true, "webhook_url": "https://your-app.com/webhooks/neon-auth", "enabled_events": [ "send.otp", "send.magic_link", "user.before_create", "user.created", "phone_number.verified", "organization.invitation.created", "organization.invitation.accepted" ], "timeout_seconds": 5 } ``` ### Delete a webhook To delete a webhook and stop receiving authentication events, update your configuration by setting the `enabled` field to `false` using the update endpoint. This disables the webhook and resumes Managed Better Auth's default delivery behavior for all events. ```bash curl -X PUT "https://console.neon.tech/api/v2/projects/{project_id}/branches/{branch_id}/auth/webhooks" \ -H "Content-Type: application/json" \ -H "Authorization: Bearer $NEON_API_KEY" \ -d '{ "enabled": false }' ``` ## Payload structure All events share a common JSON envelope: ```json { "event_id": "550e8400-e29b-41d4-a716-446655440000", "event_type": "send.otp", "timestamp": "2026-02-23T12:00:00.000Z", "context": { "endpoint_id": "ep-cool-sound-12345678", "project_name": "My SaaS App" }, "user": { "id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890", "email": "user@example.com", "name": "Jane Smith", "email_verified": false, "created_at": "2026-02-23T12:00:00.000Z" }, "event_data": { "otp_code": "123456", "otp_type": "sign-in", "expires_at": "2026-02-23T12:10:00.000Z", "ip_address": "192.0.2.1", "user_agent": "Mozilla/5.0" } } ``` The `user` object uses a fixed allowlist. Fields are optional and vary by event; fields that are not present are omitted. Available fields: `id`, `name`, `email`, `image`, `role`, `banned`, `email_verified`, `phone_number`, `phone_number_verified`, `created_at`, `updated_at`, `ban_reason`, `ban_expires`, `two_factor_enabled`, `is_anonymous`. Managed Better Auth drops any user fields outside this allowlist, including new Better Auth or plugin fields that have not been explicitly added to the webhook contract. ### `send.otp` event data | Field | Type | Description | | --------------------- | ----------------- | ----------------------------------------------------------- | | `otp_code` | string | 6-digit OTP code | | `otp_type` | string | `"sign-in"`, `"email-verification"`, or `"forget-password"` | | `delivery_preference` | string (optional) | `"email"` or `"sms"` | | `expires_at` | ISO datetime | Expiry time | | `ip_address` | string | Requester's IP address | | `user_agent` | string | Requester's user agent | When `delivery_preference` is `"sms"`, the event is fired by the [Phone Number plugin](https://neon.com/docs/auth/guides/plugins/phone-number). Your handler is responsible for delivering the OTP through your SMS provider. Because Managed Better Auth does not deliver SMS, a subscribed `send.otp` webhook is a hard requirement for the Phone Number plugin. ### `send.magic_link` event data | Field | Type | Description | | ------------ | ------------ | ----------------------------------------------------------- | | `link_type` | string | `"sign-in"`, `"email-verification"`, or `"forget-password"` | | `link_url` | string | Full verification URL with embedded token | | `token` | string | Raw token for building custom redirect URLs | | `expires_at` | ISO datetime | Expiry time | | `ip_address` | string | Requester's IP address | | `user_agent` | string | Requester's user agent | The `"sign-in"` link type is sent when a user signs in via the [Magic Link plugin](https://neon.com/docs/auth/guides/plugins/magic-link). Magic links do not include a `delivery_preference` field. Your webhook handler determines the delivery channel. ### `user.before_create` and `user.created` event data These events fire only when a new user record is created in the database. They do not fire on subsequent sign-ins, including returning OAuth users. | Field | Type | Description | | --------------- | ------ | ------------------------------------------------------------------------------- | | `auth_provider` | string | `"credential"`, `"google"`, `"github"`, `"vercel"`, `"microsoft"`, or `"apple"` | | `ip_address` | string | Requester's IP address | | `user_agent` | string | Requester's user agent | If sign-up metadata is present and passes validation, it is included as `event_data.signup_metadata`. To limit payload size and prevent oversized egress, Managed Better Auth only includes `signup_metadata` when it is a plain object, serializes to at most 10 KiB of UTF-8 JSON, and is nested no more than 5 levels deep. Oversized, too-deep, array, or primitive metadata is dropped from the webhook payload. ### `phone_number.verified` event data Fires non-blocking after a user successfully verifies a phone number via the [Phone Number plugin](https://neon.com/docs/auth/guides/plugins/phone-number). The `user` object includes the full user context, including `phone_number` and `phone_number_verified`. | Field | Type | Description | | ----------------- | ------- | --------------------------------------------------------------------------------- | | `phone_number` | string | The phone number that was verified, in E.164 format (for example, `+15551234567`) | | `is_phone_update` | boolean | Reserved for future use; currently always `false` | | `ip_address` | string | Requester's IP address | | `user_agent` | string | Requester's user agent | ### `organization.invitation.created` event data Fires non-blocking when an organization invitation is created, via the [Organization plugin](https://neon.com/docs/auth/guides/plugins/organization). The top-level `user` object contains the **inviter**, not the invitee. Because the inviter isn't the subject of the event, this object is limited to `id`, `name`, and `email` rather than the full user allowlist described above. The same reduced object is repeated at `event_data.inviter` for convenience. The invitee's email is available in `event_data.invitee_email`. | Field | Type | Description | | ------------------- | ------------ | ------------------------------------------------------------- | | `invitation_id` | string | Unique ID of the invitation | | `organization_id` | string | ID of the organization the invitation is for | | `organization_name` | string | Name of the organization | | `organization_slug` | string | Slug of the organization | | `invitee_email` | string | Email address of the invited user | | `role` | string | Role assigned to the invitee | | `expires_at` | ISO datetime | Invitation expiry time | | `inviter` | object | `id`, `name`, and `email` of the user who sent the invitation | | `invitee` | object | `email` of the invited user | ### `organization.invitation.accepted` event data Fires non-blocking after a user accepts an organization invitation and becomes a member, via the [Organization plugin](https://neon.com/docs/auth/guides/plugins/organization). The `user` object contains the full user context for the person who accepted the invitation. `event_data.invitee` repeats the same person as a reduced `id`, `name`, `email` object. | Field | Type | Description | | ------------------- | ------ | ----------------------------------------------------------------- | | `invitation_id` | string | Unique ID of the invitation | | `organization_id` | string | ID of the organization the user joined | | `organization_name` | string | Name of the organization | | `organization_slug` | string | Slug of the organization | | `role` | string | Role assigned to the new member | | `member_id` | string | ID of the new organization membership record | | `invitee` | object | `id`, `name`, and `email` of the user who accepted the invitation | ## Signature verification Managed Better Auth uses asymmetric EdDSA (Ed25519) signatures with detached JWS, so key rotation does not require reconfiguring your endpoint. Verify signatures before processing webhooks. ### Request headers Each webhook request includes the following headers: | Header | Description | | ------------------------- | ---------------------------------------------- | | `X-Neon-Signature` | Detached JWS signature (`header..signature`) | | `X-Neon-Signature-Kid` | Key ID for looking up the public key from JWKS | | `X-Neon-Timestamp` | Unix timestamp in milliseconds | | `X-Neon-Event-Type` | Event type (for example, `user.created`) | | `X-Neon-Event-Id` | Unique event UUID | | `X-Neon-Delivery-Attempt` | Attempt number: 1, 2, or 3 | Example incoming webhook request: ```http POST /webhooks/neon-auth HTTP/1.1 Content-Type: application/json X-Neon-Signature: eyJhbGciOiJFZERTQSIsInR5cCI6IkpXUyIsImtpZCI6IjAxZGVjNTJiIn0..MEUCIQDZ8Qs X-Neon-Signature-Kid: 01dec52b-4666-40f7-87ed-6423552eecaf X-Neon-Timestamp: 1740312000000 X-Neon-Event-Type: send.otp X-Neon-Event-Id: 550e8400-e29b-41d4-a716-446655440000 X-Neon-Delivery-Attempt: 1 {"event_id":"550e8400-e29b-41d4-a716-446655440000","event_type":"send.otp",...} ``` ### Verification steps 1. Fetch your JWKS from `/.well-known/jwks.json`. Find the key where `kid` matches the `X-Neon-Signature-Kid` header. 2. Parse the detached JWS from `X-Neon-Signature`. The format is `header..signature` (empty middle section). 3. Reconstruct the signing input using standard JWS with double base64url encoding: - `payloadB64 = base64url(rawRequestBody)` - `signaturePayload = timestamp + "." + payloadB64` - `signaturePayloadB64 = base64url(signaturePayload)` - `signingInput = header + "." + signaturePayloadB64` 4. Verify the Ed25519 signature against the signing input using the public key. The double base64url encoding occurs because the timestamp is bound into the JWS payload per RFC 7515 Compact Serialization. ### Idempotency and additional checks Retries send the same `X-Neon-Event-Id`. Your endpoint should track this value and return the same response for duplicate deliveries. This is especially important for `user.before_create`, where a lost response triggers a retry with the same event. Consider rejecting requests where `X-Neon-Timestamp` is more than 5 minutes old to prevent replay attacks. ### Node.js example ```javascript import crypto from 'node:crypto'; async function verifyWebhook(rawBody, headers) { const signature = headers['x-neon-signature']; const kid = headers['x-neon-signature-kid']; const timestamp = headers['x-neon-timestamp']; // 1. Fetch JWKS and find the matching key const res = await fetch(`${process.env.NEON_AUTH_URL}/.well-known/jwks.json`); const jwks = await res.json(); const jwk = jwks.keys.find((k) => k.kid === kid); if (!jwk) throw new Error(`Key ${kid} not found in JWKS`); // 2. Import the Ed25519 public key const publicKey = crypto.createPublicKey({ key: jwk, format: 'jwk' }); // 3. Parse detached JWS (header..signature) const [headerB64, emptyPayload, signatureB64] = signature.split('.'); if (emptyPayload !== '') throw new Error('Expected detached JWS format'); // 4. Reconstruct signing input (standard JWS, double base64url encoding) const payloadB64 = Buffer.from(rawBody, 'utf8').toString('base64url'); const signaturePayload = `${timestamp}.${payloadB64}`; const signaturePayloadB64 = Buffer.from(signaturePayload, 'utf8').toString('base64url'); const signingInput = `${headerB64}.${signaturePayloadB64}`; // 5. Verify Ed25519 signature const isValid = crypto.verify( null, Buffer.from(signingInput), publicKey, Buffer.from(signatureB64, 'base64url') ); if (!isValid) throw new Error('Invalid webhook signature'); // 6. Check timestamp freshness (recommended) const ageMs = Date.now() - parseInt(timestamp, 10); if (ageMs > 5 * 60 * 1000) throw new Error('Webhook timestamp too old'); return JSON.parse(rawBody); } ``` **Important:** Preserve the raw request body before JSON parsing. If your framework parses the body automatically, save the raw bytes first. Re-serialized JSON may differ from the original bytes and cause signature verification to fail. **Next.js App Router example:** ```javascript // app/webhooks/neon-auth/route.js export async function POST(request) { const rawBody = await request.text(); const payload = await verifyWebhook( rawBody, Object.fromEntries(request.headers) ); // process payload return Response.json({ allowed: true }); } ``` **Tip:** In production, cache the JWKS response and refresh it when you encounter an unknown key ID. Rate-limit refresh attempts to avoid excessive requests to the JWKS endpoint. ## Expected responses Webhook responses must not exceed 10KB. ### `send.otp` and `send.magic_link` Return any 2xx status code. The response body is ignored. If all 3 delivery attempts fail or the 15-second global timeout expires, the auth flow fails and the user sees an error. ### `user.before_create` Return a 2xx status code with a JSON body. **Allow signup:** ```json { "allowed": true } ``` **Reject signup:** ```json { "allowed": false, "error_message": "Signups from this domain are not allowed.", "error_code": "DOMAIN_BLOCKED" } ``` | Field | Type | Description | | --------------- | ------------------ | -------------------------------------------------- | | `allowed` | boolean (required) | Whether to permit user creation | | `error_message` | string (optional) | User-facing rejection message (max 500 characters) | | `error_code` | string (optional) | Machine-readable code for client-side handling | If the webhook fails or returns an invalid response, signup is rejected. This fail-closed behavior prevents bypassing your validation logic. **Important:** If your webhook endpoint is unreachable, all signups fail. Monitor your endpoint availability and keep response times well under the configured timeout to leave room for network latency and retries. ### `user.created` Return any 2xx status code. The response body is ignored. This event is non-blocking. Failures are logged but do not affect the user creation. Return 200 immediately and process the event asynchronously (for example, via a job queue). This prevents timeouts under load. ## Retry behavior Because blocking events pause the user's auth flow, retries happen immediately rather than using exponential backoff. The user cannot wait minutes for a retry. The 15-second global timeout runs from the start of the first attempt. Each attempt uses the lesser of `timeout_seconds` or the remaining global time. If earlier attempts consume the budget, later attempts get reduced timeouts or are skipped. | Property | Value | | -------------- | -------------------------------------------------------------------------------------------- | | Max attempts | 3 (1 initial + 2 retries, no backoff) | | Global timeout | 15 seconds across all attempts | | Retryable | 5xx, 429, 408, network errors (ECONNREFUSED, ETIMEDOUT, ECONNRESET, ENOTFOUND, ECONNABORTED) | | Non-retryable | 4xx (except 408 and 429) | ## Testing and debugging Managed Better Auth does not currently support test events, event logs, or redelivery. To test webhooks during development, expose a local server using a tunneling tool (for example, ngrok) and configure the tunnel's **HTTPS hostname** as your webhook URL. Managed Better Auth rejects localhost, private IP addresses, and raw IP literals. See [Webhook URL requirements](https://neon.com/docs/auth/guides/webhooks#webhook-url-requirements). --- [Document source](https://neon.com/docs/auth/migrate/from-legacy-auth.md) --- > Summary: Migration guide for upgrading from legacy Neon Auth (Stack Auth) to Managed Better Auth. Replace Stack Auth environment variables with a single `NEON_AUTH_BASE_URL` and swap the `@stackframe/stack` SDK for `@neon/auth`. Use this page when moving an existing Next.js or React SPA project off Stack Auth, or when ejecting to a self-managed Stack Auth project. # Migrate to Managed Better Auth Update from the legacy Stack Auth-based implementation Last updated: 2026-10-09 This guide shows you the code differences between legacy Neon Auth (Stack Auth) and Managed Better Auth. Use it as a reference to understand what changes if you decide to upgrade. **Important: Legacy Neon Auth (Stack Auth) is no longer accepting new users** If you're using legacy Neon Auth with Stack Auth, you can continue using it. We'll keep supporting it for existing users. But we encourage you to try Managed Better Auth instead. ## Why Managed Better Auth? - **Native Branching Support** Authentication branches automatically with your database. Each branch gets isolated users, sessions, and auth configuration, perfect for preview environments and testing. - **Database as Source of Truth** Your Neon database is the single source of truth for authentication data. No webhooks, no sync delays, no external dependencies. Query users directly with SQL. - **Simplified Configuration** One environment variable instead of four. Easier setup, fewer moving parts. - **Open-Source Foundation** Built on Better Auth, enabling faster development of new features and better community support. ## Environment variables Update your environment variables to use Better Auth's configuration. ```env filename=".env (before - Stack Auth)" NEXT_PUBLIC_STACK_PROJECT_ID=your-project-id NEXT_PUBLIC_STACK_PUBLISHABLE_CLIENT_KEY=your-client-key STACK_SECRET_SERVER_KEY=your-server-secret ``` ```env filename=".env (after - Better Auth)" NEON_AUTH_BASE_URL=https://ep-xxx.neonauth.us-east-2.aws.neon.build/neondb/auth NEON_AUTH_COOKIE_SECRET=your-secret-at-least-32-characters-long ``` **Note:** For React SPAs, use VITE_NEON_AUTH_URL instead. The NEON_AUTH_COOKIE_SECRET is only needed for Next.js (generate with openssl rand -base64 32). You can find your Auth URL in the Neon Console under **Settings** > **Better Auth** > **Project Info**. **What changed** You replace multiple Stack Auth-specific keys with a single Better Auth URL that points at your Neon project. For Next.js, you also need a cookie secret for session caching. ## Next.js migration ### Install packages Uninstall Stack Auth packages, install `@neon/auth`, and add [Better Auth UI](https://neon.com/docs/auth/reference/ui-components)'s components with the shadcn CLI. ```bash filename="Terminal" npm uninstall @stackframe/stack npm install @neon/auth@latest npx shadcn@latest init npx shadcn@latest add @better-auth-ui/auth @better-auth-ui/user-button npm i better-auth@~1.7.12 ``` The last command realigns `better-auth` with the version `@neon/auth` uses, because `shadcn add` installs the npm `latest` tag. **What changed** Your app now depends on Managed Better Auth's Next.js SDK instead of the Stack Auth SDK, and the auth UI components are copied into `components/auth/`. ### Update SDK initialization **Before (Stack Auth)** ```tsx // stack.ts import { StackServerApp } from '@stackframe/stack'; export const stackServerApp = new StackServerApp({ tokenStore: 'nextjs-cookie', }); ``` **After (Better Auth)** ```tsx // ./lib/auth/client.ts 'use client'; import { createAuthClient } from '@neon/auth/next'; // to use in react client components export const authClient = createAuthClient(); // ./lib/auth/server.ts import { createNeonAuth } from '@neon/auth/next/server'; // to use in react server components, server actions, and API routes export const auth = createNeonAuth({ baseUrl: process.env.NEON_AUTH_BASE_URL!, cookies: { secret: process.env.NEON_AUTH_COOKIE_SECRET!, }, }); ``` **What changed** You initialize the Managed Better Auth client with `createAuthClient` for client components and with `createNeonAuth()` for server-side auth. The unified `auth` instance provides `.handler()`, `.middleware()`, `.getSession()`, and all Better Auth server methods. ### Replace components #### Sign in page **Before (Stack Auth)** ```tsx import { SignIn } from '@stackframe/stack'; export default function SignInPage() { return ; } ``` **After (Better Auth)** ```tsx import { Auth } from '@/components/auth/auth'; export default function SignInPage() { return ; } ``` **What changed** You render Better Auth UI's `Auth` component and tell it which flow to show with the `view` prop. Also add the shared `app/auth/[path]/page.tsx` route with ``, as in the [UI components reference](https://neon.com/docs/auth/reference/ui-components#nextjs-app-router): the user menu's **Sign Out** and the password reset links open `/auth/*` paths. #### Sign up page **Before (Stack Auth)** ```tsx import { SignUp } from '@stackframe/stack'; export default function SignUpPage() { return ; } ``` **After (Better Auth)** ```tsx import { Auth } from '@/components/auth/auth'; export default function SignUpPage() { return ; } ``` **What changed** You swap the dedicated `` component for the same `Auth` component, configured with the `signUp` view. #### User button **Before (Stack Auth)** ```tsx import { UserButton } from '@stackframe/stack'; export function Header() { return ; } ``` **After (Better Auth)** ```tsx import { UserButton } from '@/components/auth/user/user-button'; export function Header() { return ; } ``` **What changed** You keep a `UserButton`, now the one the shadcn CLI copied into `components/auth/user/`. `hideSettings` drops its link to `/settings/account`; to keep it, add `@better-auth-ui/settings` and a `settings/[path]` route. ### Replace hooks **Before (Stack Auth)** ```tsx 'use client'; import { useUser } from '@stackframe/stack'; export function MyComponent() { const user = useUser(); return
{user ? `Hello, ${user.displayName}` : 'Not logged in'}
; } ``` **After (Better Auth)** ```tsx 'use client'; import { useSession } from '@/lib/auth/client'; export function MyComponent() { const { data } = useSession(); const user = data?.user; return
{user ? `Hello, ${user.name || user.email}` : 'Not logged in'}
; } ``` **What changed** Instead of `useUser()`, you call `useSession()` hook from `authClient` and read the user & session data from response. ### Update provider setup **Before (Stack Auth)** ```tsx import { StackProvider, StackTheme } from '@stackframe/stack'; import { stackServerApp } from './stack'; export default function RootLayout({ children }) { return ( {children} ); } ``` **After (Better Auth)** ```tsx // components/providers.tsx, rendered by app/layout.tsx around {children} 'use client'; import { getSafeRedirectTo } from '@better-auth-ui/core'; import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; import Link from 'next/link'; import { useRouter } from 'next/navigation'; import { useState } from 'react'; import { AuthProvider } from '@/components/auth/auth-provider'; import { Toaster } from '@/components/ui/sonner'; import { authClient } from '@/lib/auth/client'; export function Providers({ children }) { const router = useRouter(); const [queryClient] = useState(() => new QueryClient()); return ( { const path = getSafeRedirectTo(to, window.location.origin); const target = path.startsWith('//') ? '/' : path; if (replace) router.replace(target); else router.push(target); }} Link={Link} redirectTo="/" > {children} ); } ``` **What changed** You wrap your app in a TanStack Query provider and Better Auth UI's `AuthProvider`, and pass it the `authClient`. `navigate` validates the `?redirectTo=` target the components pass it after sign-in. There's no stylesheet to import: your Tailwind build compiles the copied components. **Tip: Styling options** To change how the auth UI looks, edit the shadcn/ui theme or the copied components. See [Styling](https://neon.com/docs/auth/reference/ui-components#styling). ### Replace auth handler route **Before (Stack Auth)** ```tsx // app/handler/[...stack]/page.tsx import { StackHandler } from '@stackframe/stack'; import { stackServerApp } from '@/stack'; export default function Handler(props: any) { return ; } ``` **After (Better Auth)** ```tsx // app/api/auth/[...path]/route.ts import { auth } from '@/lib/auth/server'; export const { GET, POST, PUT, PATCH, DELETE } = auth.handler(); ``` **What changed** You proxy Managed Better Auth APIs from your Next.js application. The `auth.handler()` method forwards all API requests to the Managed Better Auth server. ### Protect routes #### Component-level protection **Before (Stack Auth)** ```tsx 'use client'; import { useUser } from '@stackframe/stack'; export default function ProtectedPage() { const user = useUser({ or: 'redirect' }); return
Protected content
; } ``` **After (Better Auth)** ```tsx 'use client'; import { useSession } from '@better-auth-ui/react'; import { useRouter } from 'next/navigation'; import { useEffect } from 'react'; import { authClient } from '@/lib/auth/client'; export default function ProtectedPage() { const router = useRouter(); const { data, isFetching } = useSession(authClient); const signedOut = !data && !isFetching; useEffect(() => { if (signedOut) router.replace('/auth/sign-in'); }, [signedOut, router]); if (!data) return null; return
Protected content
; } ``` **What changed** You read the session with `useSession()` and redirect once it has loaded without a user. For page loads, prefer the middleware below, which redirects on the server. #### Middleware-based protection **Note: Next.js version compatibility** `proxy.ts` replaces `middleware.ts` in Next.js 16. On earlier versions, name the file `middleware.ts` and export `default function middleware` instead of `proxy`. The auth logic is identical. ```tsx filename="proxy.ts (new)" import { auth } from '@/lib/auth/server'; export default auth.middleware({ // Redirects unauthenticated users to sign-in page loginUrl: '/auth/sign-in', // Pages that don't require a session publicRoutes: ['/'], }); export const config = { // Run on all paths except static files matcher: ['/((?!_next/static|_next/image|favicon.ico).*)'], }; ``` **What changed** You can optionally add middleware to enforce auth at the edge. It protects every matched route except `/api/auth`, Better Auth UI's signed-out views, and the `publicRoutes` you list. ### Server-side user access **Before (Stack Auth)** ```tsx import { stackServerApp } from '@/stack'; export default async function ServerComponent() { const user = await stackServerApp.getUser(); return
{user?.displayName}
; } ``` **After (Better Auth)** ```tsx import { auth } from '@/lib/auth/server'; // Server components using auth methods must be rendered dynamically export const dynamic = 'force-dynamic'; export default async function ServerComponent() { const { data: session } = await auth.getSession(); return
{session?.user?.name || session?.user?.email}
; } ``` **What changed** Server components now call `auth.getSession()` and read the user from the returned session. Components using auth methods must set `dynamic = 'force-dynamic'`. ## React SPA migration ### Install packages Uninstall Stack Auth packages, install `@neon/auth`, and add [Better Auth UI](https://neon.com/docs/auth/reference/ui-components)'s components with the shadcn CLI. ```bash filename="Terminal" npm uninstall @stackframe/stack npm install @neon/auth@latest npx shadcn@latest init npx shadcn@latest add @better-auth-ui/auth @better-auth-ui/user-button npm i better-auth@~1.7.12 ``` The last command realigns `better-auth` with the version `@neon/auth` uses, because `shadcn add` installs the npm `latest` tag. **What changed** You use the Managed Better Auth SDK and Better Auth UI's components instead of the Stack Auth client SDK. ### Update SDK initialization **Before (Stack Auth)** ```tsx // src/stack.ts import { StackClientApp } from '@stackframe/stack'; export const stackClientApp = new StackClientApp({ urls: { signIn: '/sign-in', signUp: '/sign-up', }, }); ``` **After (Better Auth)** ```tsx // src/auth.ts import { createAuthClient } from '@neon/auth'; import { BetterAuthReactAdapter } from '@neon/auth/react/adapters'; export const authClient = createAuthClient(import.meta.env.VITE_NEON_AUTH_URL, { adapter: BetterAuthReactAdapter(), }); const { useSession } = authClient; ``` **What changed** You replace the Stack Auth client app with a Managed Better Auth `authClient` wired to your Managed Better Auth URL. ### Replace components Components are the same as Next.js. Use `` and `` from `components/auth/`, and `useSession()` from `@better-auth-ui/react` for signed-in checks. **What changed** The UI building blocks are shared across frameworks, so you can reuse the same auth components in SPAs. ### Replace hooks **Before (Stack Auth)** ```tsx import { useUser } from '@stackframe/stack'; export function MyComponent() { const user = useUser(); return
{user ? `Hello, ${user.displayName}` : 'Not logged in'}
; } ``` **After (Better Auth)** ```tsx import { useSession } from './auth'; export function MyComponent() { const { data } = useSession(); const user = data?.user; return
{user ? `Hello, ${user.name || user.email}` : 'Not logged in'}
; } ``` **What changed** Instead of a React hook from Stack Auth, you call the `useSession()` hook from `authClient` and read the user from its response. ### Update provider setup **Before (Stack Auth)** ```tsx import { StackProvider, StackTheme } from '@stackframe/stack'; import { stackClientApp } from './stack'; function App() { return ( {/* Your app */} ); } ``` **After (Better Auth)** ```tsx import { getSafeRedirectTo } from '@better-auth-ui/core'; import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; import { AuthProvider } from '@/components/auth/auth-provider'; import { Toaster } from '@/components/ui/sonner'; import { authClient } from './auth'; const queryClient = new QueryClient(); function App() { return ( { const path = getSafeRedirectTo(to, window.location.origin); window.location.assign(path.startsWith('//') ? '/' : path); }} Link={({ to: _to, ...props }) => } > {/* Your app */} ); } ``` **What changed** You drop the Stack Auth provider/theme and wrap your app in a TanStack Query provider and Better Auth UI's `AuthProvider`. `navigate` validates the `?redirectTo=` target the components pass it after sign-in. **Tip: Styling options** To change how the auth UI looks, edit the shadcn/ui theme or the copied components. See [Styling](https://neon.com/docs/auth/reference/ui-components#styling). ### Remove auth handler route Delete any `StackHandler` routes. Add one route for every auth path, for example `/auth/:path`, that renders ``. The user menu's **Sign Out** and the password reset links open `/auth/*` paths. ```tsx filename="src/pages/AuthPage.tsx" import { useParams } from 'react-router-dom'; import { Auth } from '@/components/auth/auth'; export default function AuthPage() { const { path } = useParams(); return ; } ``` **What changed** Routing is fully controlled by your SPA, and the `Auth` component renders the view for each path. ### React Router integration If you're using React Router, pass navigation helpers to the provider. ```tsx filename="src/App.tsx (React Router)" import { getSafeRedirectTo } from '@better-auth-ui/core'; import { useNavigate, Link } from 'react-router-dom'; import { AuthProvider } from '@/components/auth/auth-provider'; import { authClient } from './auth'; function App() { const navigate = useNavigate(); return ( { const path = getSafeRedirectTo(to, window.location.origin); navigate(path.startsWith('//') ? '/' : path, { replace }); }} Link={({ href, to: _to, ...props }) => } > {/* Your app */} ); } ``` **What changed** You let Better Auth reuse your router's navigation and Link components so redirects and links stay in sync with your SPA. ## Eject to Stack Auth If you prefer to continue using Stack Auth independently instead of migrating to Better Auth, you can claim your Stack Auth project and manage it directly. ## Claim your project 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. ## Update your environment variables Once claimed, update your environment variables to use Stack Auth's direct configuration. Your existing code will continue to work without changes since you're already using the Stack Auth SDK (`@stackframe/stack`). ## Manage independently After claiming, you can: - Manage OAuth providers directly in Stack Auth. - Configure production security settings. - Access Stack Auth's dashboard and features. **Important:** Ejecting to Stack Auth means you'll manage authentication independently from Neon. You'll need to handle updates, support, and infrastructure yourself. Your authentication data will no longer be managed through the Neon Console. --- [Document source](https://neon.com/docs/auth/migrate/from-supabase.md) --- > Summary: Step-by-step migration from Supabase Auth and Supabase database to Managed Better Auth and Neon Data API. Replace `@supabase/supabase-js` with `@neon/neon-js`, swap environment variables, and update client initialization while keeping existing auth method calls and `from()` database queries code-compatible. Existing password-based users cannot transfer due to incompatible password hashing algorithms, so this guide targets new projects, early development, or OAuth-only apps. Managed Better Auth does not support phone authentication (SMS/WhatsApp), SAML SSO, or Web3 wallet sign-in. # Migrate from Supabase to Neon Switch from Supabase Auth and Database to Neon in a few steps Last updated: 2026-09-16 Managed Better Auth provides a Supabase-compatible API, and Neon Data API provides PostgreSQL database access. This guide shows how to migrate from Supabase to Neon. **about user migration:** Existing password-based users cannot migrate due to different hashing algorithms. They'll need to create new accounts or re-authenticate via OAuth. This guide works best for new projects, early development, or rebuilding your app. ## Prerequisites - A Neon project ([create one here](https://console.neon.tech)) - Data API enabled (Managed Better Auth is enabled by default when you enable Data API): - Go to **Postgres database** > **Data API** in the Neon Console and enable it - In **Data API → Configuration**, verify it's configured with **Managed Better Auth** - Copy your Neon connection host and database name from **Connect** in the Console. The SDK derives both the Auth and Data API URLs from this single base URL. See [Initialize the client](https://neon.com/docs/reference/javascript-sdk#initializing) for the derivation rules, or use the separate Auth and Data API base URLs instead if you'd rather configure them explicitly ## Install Neon SDK Replace the Supabase SDK with Neon's: ```bash filename="Terminal" npm uninstall @supabase/supabase-js npm install @neon/neon-js@latest ``` ## Update environment variables Replace your Supabase credentials with a single Neon base URL. `createClient()` derives both the Auth and Data API URLs from it automatically: ```env filename=".env" # Remove these: # VITE_SUPABASE_URL=https://your-project.supabase.co # VITE_SUPABASE_ANON_KEY=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9... # Add this: VITE_NEON_URL=https://ep-xxx.c-2.us-east-2.aws.neon.build/dbname ``` **Get your URL:** Your Neon base URL is the host and database name from your Neon connection string, served over `https://`. Find these values under **Connect** in the Neon Console. **Note:** The `VITE_` prefix is for Vite. Use `NEXT_PUBLIC_` for Next.js, or no prefix for Node.js. **Tip:** If you already copied separate Auth and Data API base URLs from the Console (for example, from an earlier setup), you can still pass them explicitly with the object form. See [Initialize the client](https://neon.com/docs/reference/javascript-sdk#initializing) for both forms. ## Update client initialization Find your Supabase client file, typically `src/supabase.ts` or `src/lib/supabase.ts`, and update it: **Before (Supabase):** ```typescript filename="src/supabase.ts" import { createClient } from '@supabase/supabase-js'; export const supabase = createClient( process.env.VITE_SUPABASE_URL!, process.env.VITE_SUPABASE_ANON_KEY! ); ``` **After (Neon):** ```typescript filename="src/auth.ts" import { createClient } from '@neon/neon-js/supabase'; export const client = createClient(import.meta.env.VITE_NEON_URL); ``` This example renames the file to `auth.ts` and the variable to `client` for a provider-agnostic setup. You can use any naming, just stay consistent throughout your codebase. Find **all files that import this client** and update them: ```typescript // Before import { supabase } from './supabase'; // After import { client } from './auth'; ``` ## Your auth code stays the same After updating imports, use find/replace to change all instances throughout your codebase: **`supabase.` → `client.`** Your authentication methods, parameters, and responses work identically. Your components, hooks, and auth flows don't change. ```typescript filename="Auth methods" // Sign up await client.auth.signUp({ email, password }); // Sign in with password await client.auth.signInWithPassword({ email, password }); // OAuth sign in await client.auth.signInWithOAuth({ provider: 'google' }); // Get current user const { data: { user }, } = await client.auth.getUser(); // Get session const { data: { session }, } = await client.auth.getSession(); // Sign out await client.auth.signOut(); ``` ## Your database queries stay the same Your existing `client.from()` queries work without any code changes: ```typescript // Same as Supabase - no changes needed const { data: posts } = await client.from('posts').select('*'); const { data: user } = await client.from('users').select('*').eq('id', userId).single(); ``` **Note:** For production apps, use Row Level Security (RLS) to secure your data. See our [RLS with Drizzle guide](https://neon.com/docs/guides/rls-drizzle) for the recommended setup. ## Test the migration Run your app: ```bash filename="Terminal" npm run dev ``` **Test your app:** 1. Sign up a new user 2. Sign in with that user 3. Verify the session persists across page reloads 4. If you enabled Data API: Test user actions that involve database queries (creating posts, loading lists, etc.) Your authentication and database queries should work the same as they did with Supabase. **Verify users in Neon Console:** Go to **Auth → Users** in the Neon Console to see your newly created users, or query directly: ```sql filename="SQL Editor" SELECT id, email, "createdAt" FROM neon_auth.user ORDER BY "createdAt" DESC; ``` ## What changed? | Feature | Supabase | Neon | | ------------------------- | ----------------------------------- | --------------------------------------------------- | | **User ID type** | `UUID` | `UUID` | | **Client config** | URL + anon key | Single base URL (auto-derives Auth + Data API URLs) | | **Environment variables** | `SUPABASE_URL`, `SUPABASE_ANON_KEY` | `NEON_URL` | | **SDK package** | `@supabase/supabase-js` | `@neon/neon-js` | ## API compatibility Managed Better Auth supports most Supabase Auth methods including sign up, sign in (password and OAuth), session management, user updates, and email verification. See the [Neon TypeScript SDK](https://neon.com/docs/reference/javascript-sdk) for the complete API. **Not supported:** | Method | Details | | ------------------- | ----------------------------------- | | `signInWithPhone()` | Phone authentication (SMS/WhatsApp) | | SAML SSO methods | Enterprise SAML authentication | | Web3 authentication | Blockchain wallet sign-in | **Different behavior:** | Method | Notes | | ------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | `updateUser()` | Does not support `password` or `email` parameters | | Email verification | Unlike Supabase's automatic verification flow, Managed Better Auth requires you to build the verification UI in your app. See [Email Verification](https://neon.com/docs/auth/guides/email-verification) for implementation details. | If you're using any unsupported methods or verification flows, you'll need to adjust your implementation. --- [Document source](https://neon.com/docs/auth/overview.md) --- > Summary: Managed Better Auth is a managed authentication service built on Better Auth. It stores users, sessions, and OAuth configuration in your database under the neon_auth schema, compatible with Row Level Security. Every database branch gets its own isolated auth environment, so you can test sign-up, login, and OAuth flows in preview or CI branches without touching production. # Managed Better Auth Managed authentication that branches with your database Last updated: 2026-09-29 Neon's managed Better Auth keeps your users and sessions in your own Postgres database, so your auth state branches with your data. [View prompt](https://neon.com/prompts/auth-landing.md) ## Quick start guides Choose your framework to get started: - [Next.js](https://neon.com/docs/auth/quick-start/nextjs-api-only): Quick start with API methods - [React](https://neon.com/docs/auth/quick-start/react): Quick start with API methods - [TanStack Router](https://neon.com/docs/auth/quick-start/tanstack-router): With UI components ## Explore Managed Better Auth - [About Managed Better Auth](https://neon.com/docs/auth/about): How Neon's managed Better Auth works, when to use it instead of self-hosting, pricing, and availability. - [Branching authentication](https://neon.com/docs/auth/branching-authentication): Every database branch gets its own isolated users, sessions, and auth configuration. - [Authentication flow](https://neon.com/docs/auth/authentication-flow): Follow a request from sign-in to session through the SDK and the auth service. - [Set up OAuth](https://neon.com/docs/auth/guides/setup-oauth): Add Google, GitHub, and other OAuth providers to your app. - [Production checklist](https://neon.com/docs/auth/production-checklist): Check domains, email, and OAuth credentials before you go live. - [Roadmap](https://neon.com/docs/auth/roadmap): See which frameworks and Better Auth plugins are supported today. --- [Document source](https://neon.com/docs/auth/production-checklist.md) --- > Summary: Required steps before going live with Managed Better Auth: trusted domains, custom SMTP provider, application name, OAuth credentials, email verification, and disabling localhost access. Use this page when Managed Better Auth is already configured for development and you need to confirm every production-blocking setting before launch. The default shared SMTP provider (`auth@mail.myneon.app`) is rate-limited and does not support verification links. A custom SMTP provider is required for both. # Auth production checklist Required configuration before launching with Managed Better Auth Last updated: 2026-10-09 Complete these steps before taking your application to production with Managed Better Auth. ## Auth production checklist - [ ] [1. Configure trusted domains](https://neon.com/docs/auth/guides/configure-domains) Add your production domain(s) to enable OAuth and email verification redirects. - [ ] [2. Set up custom email provider](https://neon.com/docs/auth/production-checklist#email-provider) Replace shared SMTP (`auth@mail.myneon.app`) with your own email service for reliable delivery and higher limits. A custom email provider is also required if you want to use verification links instead of verification codes. - [ ] [3. Customize application name](https://neon.com/docs/auth/production-checklist#application-name) Set the name your users see in user-facing auth messages. Applies to Managed Better Auth integrations. Defaults to the Neon project name. - [ ] [4. Configure OAuth credentials (if using OAuth)](https://neon.com/docs/auth/guides/setup-oauth#production-setup) Set up your own OAuth apps (Google, GitHub, Vercel, Microsoft, or Apple). Google is the only provider with shared development credentials, so replace those with your own before launch. - [ ] [5. Enable email verification (recommended)](https://neon.com/docs/auth/guides/email-verification) **Email verification is not enabled by default.** Since anyone can sign up for your application, enabling email verification adds an important verification step to ensure users own their email address. - [ ] [6. Disable localhost access](https://neon.com/docs/auth/production-checklist#localhost-access) Disable the "Allow Localhost" setting in your project's **Settings** → **Better Auth** page. This setting is enabled by default for development but should be disabled in production to improve security. ## Email provider Managed Better Auth uses a shared SMTP provider (`auth@mail.myneon.app`) by default for development and testing. For production, configure your own email provider for better deliverability and higher sending limits. A custom SMTP provider uses your sender address but still sends Neon's default email templates. For full control over email branding, content, and HTML templates, use webhooks to intercept email events and send through your own email service. See [Customize emails](https://neon.com/docs/auth/guides/customize-emails). ### Configure custom SMTP **Console** In your project's **Settings** → **Better Auth** page, configure your email provider: 1. Select **Custom SMTP provider** 2. Enter your SMTP credentials: - **Host**: Your SMTP server hostname (for example, `smtp.gmail.com`) - **Port**: SMTP port (typically `465` for SSL or `587` for TLS) - **Username**: Your SMTP username - **Password**: Your SMTP password or app-specific password - **Sender email**: Email address to send from - **Sender name**: Display name for sent emails 3. Click **Save** **CLI** Configure a standard SMTP provider with [`neon neon-auth config email-provider update`](https://neon.com/docs/cli/neon-auth#config-email-provider-update): ```bash neon neon-auth config email-provider update --type standard --host smtp.example.com --port 587 --username example_username --password AbC123dEf --sender-email noreply@example.com --sender-name "Example App" ``` **API** Update the provider with the [Update email provider configuration](https://neon.com/docs/reference/api/auth/update-neon-auth-email-provider) endpoint. Replace `{project_id}` and `{branch_id}` with your project and branch IDs: ```bash curl -X PATCH 'https://console.neon.tech/api/v2/projects/{project_id}/branches/{branch_id}/auth/email_provider' \ -H 'Authorization: Bearer $NEON_API_KEY' \ -H 'Content-Type: application/json' \ -d '{"type": "standard", "host": "smtp.example.com", "port": 587, "username": "example_username", "password": "AbC123dEf", "sender_email": "noreply@example.com", "sender_name": "Example App"}' ``` ### Email provider requirements - **Verification links**: Require a custom email provider - **Verification codes**: Work with shared or custom email providers - **Password reset**: Works with shared or custom email providers **Note:** The shared email provider (`auth@mail.myneon.app`) is suitable for development and testing. For production applications, use a custom email provider for better deliverability and to avoid rate limits. ## Application name Managed Better Auth uses the application name in user-facing auth messages, such as verification emails and password resets. By default, this is set to the Neon project name. This setting is available for Managed Better Auth integrations only. To set a custom application name: 1. Go to **Settings** → **Better Auth** in your Neon project 2. In the **Project Info** section, edit the **Application Name** field Each branch manages its own application name independently, so preview and development branches can use different names than production. You can also update the application name via the API. See [Update auth configuration](https://neon.com/docs/auth/guides/manage-auth-api#update-auth-configuration). ## Localhost access The "Allow Localhost" setting in your project's **Settings** → **Better Auth** page is enabled by default to allow authentication requests from localhost during development. ### Disable for production For production environments, disable this setting to improve security: 1. Go to **Settings** → **Better Auth** in your Neon project 2. Find the **Allow Localhost** toggle 3. Disable the toggle **Important:** Only enable "Allow Localhost" for local development. Disabling this setting in production prevents unauthorized authentication requests from localhost, improving your application's security posture. --- [Document source](https://neon.com/docs/auth/quick-start/nextjs-api-only.md) --- > Summary: Managed Better Auth SDK integration for Next.js App Router using raw API methods. Call `createNeonAuth`, `auth.signUp.email()`, `auth.signIn.email()`, and `auth.middleware()` directly from the `@neon/auth` package for full control over your auth UI. Use this guide instead of the UI components reference when you need custom sign-up and sign-in forms. Requires Next.js App Router. # Use Managed Better Auth with Next.js (API methods) Build your own auth UI using SDK methods Last updated: 2026-11-06 **Tip: Using an AI coding tool?** Run `npx neon@latest init` to connect the [Neon MCP server](https://neon.com/docs/ai/neon-mcp-server) and [Agent Skills](https://neon.com/docs/ai/agent-skills) for Managed Better Auth. See [Set up with your AI editor](https://neon.com/docs/auth/about#set-up-with-your-ai-editor) for MCP tools, example prompts, and how skills help wire auth into your app. This guide shows you how to integrate Managed Better Auth into a [Next.js](https://nextjs.org) (App Router) project using SDK methods directly. For pre-built UI components, see the [UI components reference](https://neon.com/docs/auth/reference/ui-components) and the [neon-js examples](https://github.com/neondatabase/neon-js/tree/main/examples). Upgrading from v0.1? See the [migration guide](https://neon.com/docs/auth/migrate/from-auth-v0.1). ## Enable Auth in your Neon project If you don't have a Neon project yet, create one at [console.neon.tech](https://console.neon.tech). In the Neon Console, open the **Better Auth** page and click **Enable Auth**, then copy your Auth URL from **Settings** > **Better Auth** > **Project Info**. **Console path:** Project → Branch → Auth → Configuration ## Install the Neon SDK Install the Neon SDK into your Next.js app.
_If you don't have a Next.js project_ ```bash npx create-next-app@latest my-app --yes cd my-app ```
```bash filename="Terminal" npm install @neon/auth@latest ``` ## Set up environment variables Create a `.env.local` file in your project root and add your Auth URL and a cookie secret: **Note:** Replace the Auth URL with your actual Auth URL from the Neon Console. Generate a secure cookie secret with `openssl rand -base64 32`. ```bash filename=".env.local" NEON_AUTH_BASE_URL=https://ep-xxx.neonauth.us-east-1.aws.neon.tech/neondb/auth NEON_AUTH_COOKIE_SECRET=your-secret-at-least-32-characters-long ``` ## Create auth server instance Create a unified auth instance in `lib/auth/server.ts`. This single instance provides all server-side auth functionality: - `.handler()` for API routes - `.middleware()` for route protection - `.getSession()` and all Better Auth server methods See the [Next.js Server SDK reference](https://neon.com/docs/auth/reference/nextjs-server) for complete API documentation (logging, cookies, upstream errors). **Note: Server logging** The SDK logs structured **`error`** and **`warn`** messages to **`console`** by default (`logLevel: 'warn'`). This helps when the auth proxy or upstream Auth URL is misconfigured. Set **`logLevel: 'silent'`** to disable Managed Better Auth logging, or **`logLevel: 'debug'`** for more detail. See [Server logging](https://neon.com/docs/auth/reference/nextjs-server#server-logging) in the reference. ```typescript filename="lib/auth/server.ts" import { createNeonAuth } from '@neon/auth/next/server'; export const auth = createNeonAuth({ baseUrl: process.env.NEON_AUTH_BASE_URL!, cookies: { secret: process.env.NEON_AUTH_COOKIE_SECRET!, // sessionDataTtl: 300, // optional session_data cache TTL in seconds (default: 300) }, // logLevel: 'silent', // disable Managed Better Auth logging // logLevel: 'debug', // verbose proxy/upstream logging }); ``` ## Set up auth API routes Create an API route handler that proxies auth requests. All Managed Better Auth APIs will be routed through this handler. Create a route file inside `/api/auth/[...path]` directory: In `app/api/auth/[...path]/route.ts`: ```typescript filename="app/api/auth/[...path]/route.ts" import { auth } from '@/lib/auth/server'; export const { GET, POST, PUT, PATCH, DELETE } = auth.handler(); ``` ## Add authentication middleware The middleware ensures users are authenticated before accessing protected routes. Create `proxy.ts` file in your project root: **Note: Next.js version compatibility** `proxy.ts` replaces `middleware.ts` in Next.js 16. On earlier versions, name the file `middleware.ts` and export `default function middleware` instead of `proxy`. The auth logic is identical. ```typescript filename="proxy.ts" import { auth } from '@/lib/auth/server'; export default auth.middleware({ // Redirects unauthenticated users to sign-in page loginUrl: '/auth/sign-in', }); export const config = { matcher: [ // Protected routes requiring authentication '/account/:path*', ], }; ``` **Note:** Your Next.js project is now fully configured to use Managed Better Auth. Now, lets proceed with setting up the auth clients. ## Configure the auth client Create the auth client in `lib/auth/client.ts` for client-side auth operations (form submissions, hooks, etc.). **Note:** The server-side `auth` instance was already created in a previous step. The client is separate and handles browser-side auth operations. ```tsx filename="lib/auth/client.ts" 'use client'; import { createAuthClient } from '@neon/auth/next'; export const authClient = createAuthClient(); ``` ## Create Sign up form Lets create a sign-up form and action in `app/auth/sign-up/page.tsx` and `app/auth/sign-up/actions.ts` files respectively using the auth instance we created in previous step - To create user with email and password, we will use `auth.signUp.email()` with user name, email address, and password - You can optionally add business logic before invoking the API, for example restrict signups to emails ending with `@my-company.com` **Signup action** Copy and paste following code in `app/auth/sign-up/actions.ts` file: ```ts 'use server'; import { auth } from '@/lib/auth/server'; import { redirect } from 'next/navigation'; export async function signUpWithEmail( _prevState: { error: string } | null, formData: FormData ) { const email = formData.get('email') as string; if (!email) { return { error: "Email address must be provided." } } // Optionally restrict sign ups based on email address // if (!email.trim().endsWith("@my-company.com")) { // return { error: 'Email must be from my-company.com' }; // } const { error } = await auth.signUp.email({ email, name: formData.get('name') as string, password: formData.get('password') as string, }); if (error) { return { error: error.message || 'Failed to create account' }; } redirect('/'); } ``` **Signup form** Copy and paste following code in `app/auth/sign-up/page.tsx` file: ```tsx 'use client'; import { useActionState } from 'react'; import { signUpWithEmail } from './actions'; export default function SignUpForm() { const [state, formAction, isPending] = useActionState(signUpWithEmail, null); return (

Create new account

{state?.error && (
{state.error}
)}
); } ``` ## Create Sign in form Lets create a sign-in form and action in `app/auth/sign-in/page.tsx` and `app/auth/sign-in/actions.ts` files respectively. - To sign-in the user we will use `auth.signIn.email()` with user's email address and password. **Sign In:** **Sign-in action** ```ts 'use server'; import { auth } from '@/lib/auth/server'; import { redirect } from 'next/navigation'; export async function signInWithEmail( _prevState: { error: string } | null, formData: FormData ) { const { error } = await auth.signIn.email({ email: formData.get('email') as string, password: formData.get('password') as string, }); if (error) { return { error: error.message || 'Failed to sign in. Try again' }; } redirect('/'); } ``` **Sign-in form** ```tsx 'use client'; import { useActionState } from 'react'; import { signInWithEmail } from './actions'; export default function SignInForm() { const [state, formAction, isPending] = useActionState(signInWithEmail, null); return (

Sign in to your account

{state?.error && (
{state.error}
)}
); } ``` ## Create home page In last step, lets create the home page and display authenticated user status: ```typescript filename="app/page.tsx" import { auth } from '@/lib/auth/server'; import Link from 'next/link'; // Server components using auth methods must be rendered dynamically export const dynamic = 'force-dynamic'; export default async function Home() { const { data: session } = await auth.getSession(); if (session?.user) { return (

Logged in as {session.user.name}

); } return (

Not logged in

Sign-up Sign-in
); } ``` ## Start your app Start the development server: Open your browser to [http://localhost:3000](http://localhost:3000) and test sign-up and sign-in. **Note: Safari users** Safari blocks third-party cookies on non-HTTPS connections. Use `npm run dev -- --experimental-https` and open `https://localhost:3000` instead. ```bash filename="Terminal" npm run dev ``` ## Available SDK methods Both `authClient` and `auth` expose similar API methods. Use `authClient` for client components and `auth` for server components, server actions, and API routes. - [authClient.signUp.email()](https://neon.com/docs/reference/javascript-sdk#auth-signup) / `auth.signUp.email()` - Create a new user account - [authClient.signIn.email()](https://neon.com/docs/reference/javascript-sdk#auth-signinwithpassword) / `auth.signIn.email()` - Sign in with email and password - [authClient.signOut()](https://neon.com/docs/reference/javascript-sdk#auth-signout) / `auth.signOut()` - Sign out the current user - [authClient.getSession()](https://neon.com/docs/reference/javascript-sdk#auth-getsession) / `auth.getSession()` - Get the current session - `authClient.updateUser()` / `auth.updateUser()` - Update user details The `auth` instance also includes `.handler()` for API routes and `.middleware()` for route protection. ## Next steps - [Next.js Server SDK reference](https://neon.com/docs/auth/reference/nextjs-server) — logging, cookie options, and upstream error codes - [Auth troubleshooting](https://neon.com/docs/auth/troubleshooting#neon-auth-server-logging-in-the-terminal) — server logging, `NETWORK_*` errors, iframe cookies - [Add email verification](https://neon.com/docs/auth/guides/email-verification) - [Branching authentication](https://neon.com/docs/auth/branching-authentication) - [Getting started with Managed Better Auth and Next.js](https://neon.com/guides/neon-auth-nextjs), a step-by-step tutorial - [More example apps](https://neon.com/docs/auth/about#example-applications) in the **neon-js** `examples/` directory --- [Document source](https://neon.com/docs/auth/quick-start/react.md) --- > Summary: Managed Better Auth with React for Vite apps, using the `@neon/neon-js` SDK's programmatic API methods (`signUp()`, `signIn.email()`, `getSession()`) instead of pre-built UI components. Use this page when you need full control over your own auth UI rather than dropping in ready-made components. Registered users are automatically synced to the `neon_auth.user` table in your database. # Use Managed Better Auth with React (API methods) Build your own auth UI Last updated: 2026-10-09 **Tip: Using an AI coding tool?** Run `npx neon@latest init` to connect the [Neon MCP server](https://neon.com/docs/ai/neon-mcp-server) and [Agent Skills](https://neon.com/docs/ai/agent-skills) for Managed Better Auth. See [Set up with your AI editor](https://neon.com/docs/auth/about#set-up-with-your-ai-editor) for MCP tools, example prompts, and how skills help wire auth into your app. ## Create a Neon project with Auth enabled If you don't have a Neon project yet, create one at [console.neon.tech](https://console.neon.tech). In the Neon Console, open the **Better Auth** page and click **Enable Auth**. You can then find your Auth **Base URL** on the Configuration tab. Copy this URL - you'll need it in the next step. ## Create a React app Create a React app using Vite. ```bash filename="Terminal" npm create vite@latest my-app -- --template react ``` ## Install the Neon SDK The Neon SDK provides authentication methods like `signUp()`, `getSession()`, and `signOut()` for your React app. ```bash filename="Terminal" cd my-app npm install @neon/neon-js@latest ``` ## Set up environment variables Create a `.env` file in your project root and add your Auth Base URL: **Note:** Replace the URL with your actual Auth Base URL from the Neon Console. ```bash filename=".env" VITE_NEON_AUTH_URL=https://ep-xxx.neonauth.us-east-2.aws.neon.build/neondb/auth ``` ## Configure the Neon client Create a `src/auth.js` file to configure your auth client: **Tip: Using Auth and Data API together?** This quick start uses the standalone Auth client. For one `createClient()` instance that derives both Auth and Data API URLs from a single Neon URL, see [`createClient()` initialization](https://neon.com/docs/reference/javascript-sdk#initializing). ```javascript filename="src/auth.js" import { createAuthClient } from '@neon/neon-js/auth'; export const authClient = createAuthClient(import.meta.env.VITE_NEON_AUTH_URL); ``` ## Build your authentication UI Neon JS uses a programmatic approach for managing auth state. You'll use React hooks like `useEffect` to check the session and handle auth changes. Replace the contents of `src/App.jsx` with the following code to implement [sign-up](https://neon.com/docs/reference/javascript-sdk#auth-signup), [sign-in](https://neon.com/docs/reference/javascript-sdk#auth-signinwithpassword), and [sign-out](https://neon.com/docs/reference/javascript-sdk#auth-signout): ```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 [isSignUp, setIsSignUp] = useState(true); const [loading, setLoading] = useState(true); useEffect(() => { authClient.getSession().then((result) => { if (result.data?.session && result.data?.user) { setSession(result.data.session); setUser(result.data.user); } setLoading(false); }); }, []); const handleSubmit = async (e) => { e.preventDefault(); const result = isSignUp ? await authClient.signUp.email({ name: email.split('@')[0] || 'User', email, password }) : await authClient.signIn.email({ email, password }); if (result.error) { alert(result.error.message); return; } const sessionResult = await authClient.getSession(); if (sessionResult.data?.session && sessionResult.data?.user) { setSession(sessionResult.data.session); setUser(sessionResult.data.user); } }; const handleSignOut = async () => { await authClient.signOut(); setSession(null); setUser(null); }; if (loading) return
Loading...
; if (session && user) { return (

Logged in as {user.email}

); } return (

{isSignUp ? 'Sign Up' : 'Sign In'}

setEmail(e.target.value)} required /> setPassword(e.target.value)} required />

{isSignUp ? ( <> Already have an account?{' '} { e.preventDefault(); setIsSignUp(false); }} > Sign in ) : ( <> Don't have an account?{' '} { e.preventDefault(); setIsSignUp(true); }} > Sign up )}

); } ``` ## Start your app Start the development server: Open your browser to `http://localhost:5173` and create a test user. ```bash filename="Terminal" npm run dev ``` ## See your users in the database As users sign up, their profiles are synced to your Neon database in the `neon_auth.user` table. Query your users table in the SQL Editor to see your new users: ```sql filename="SQL Editor" SELECT * FROM neon_auth.user; ``` ## Next steps - [Learn about Managed Better Auth concepts](https://neon.com/docs/auth/overview) - [More example apps](https://neon.com/docs/auth/about#example-applications) in the **neon-js** `examples/` directory - [Explore the Neon Data API](https://neon.com/docs/data-api/get-started) to build a REST API for your data - [View complete SDK reference](https://neon.com/docs/reference/javascript-sdk) --- [Document source](https://neon.com/docs/auth/quick-start/tanstack-router.md) --- > Summary: Managed Better Auth quick start for TanStack Router (file-router) using the `@neon/auth` SDK and Better Auth UI's shadcn/ui components (``, ``, ``). Use this page when you need sign-in, sign-up, account settings, and route protection without writing custom auth UI. User profiles are stored automatically in the `neon_auth.user` table in your database. # Use Managed Better Auth with TanStack Router Set up authentication using pre-built UI components Last updated: 2026-11-05 **Tip: Using an AI coding tool?** Run `npx neon@latest init` to connect the [Neon MCP server](https://neon.com/docs/ai/neon-mcp-server) and [Agent Skills](https://neon.com/docs/ai/agent-skills) for Managed Better Auth. See [Set up with your AI editor](https://neon.com/docs/auth/about#set-up-with-your-ai-editor) for MCP tools, example prompts, and how skills help wire auth into your app. ## Create a Neon project with Auth enabled If you don't have a Neon project yet, create one at [console.neon.tech](https://console.neon.tech). In the Neon Console, open the **Better Auth** page and click **Enable Auth**. You can then find your Auth URL on the Configuration tab. Copy this URL - you'll need it in the next step. ## Create a TanStack Router app Create a new TanStack Router app using the file-router template. ```bash filename="Terminal" npx create-tsrouter-app@latest my-app --template file-router --tailwind ``` ## Install the Managed Better Auth SDK and UI Install the Managed Better Auth SDK, initialize [shadcn/ui](https://ui.shadcn.com), and add [Better Auth UI](https://better-auth-ui.com)'s auth views, user menu, and settings pages. The shadcn CLI copies the components into `src/components/`. The shadcn CLI installs the npm `latest` tag of `better-auth`, so run `npm i better-auth@~1.7.12` after the last `shadcn add` to match the version `@neon/auth` uses and keep one copy. To use the examples below, choose TypeScript, `src/styles.css` as the global CSS file, `@/components` as the component alias, and no React Server Components. You can use the defaults for the other prompts. ```bash filename="Terminal" cd my-app npm install @neon/auth@latest npx shadcn@latest init npx shadcn@latest add @better-auth-ui/auth @better-auth-ui/user-button @better-auth-ui/settings npm i better-auth@~1.7.12 ``` ## Set up environment variables Create a `.env` file in your project root and add your Auth URL: **Note:** Replace the URL with your actual Auth URL from the Neon Console. ```bash filename=".env" VITE_NEON_AUTH_URL=https://ep-xxx.neonauth.us-east-1.aws.neon.tech/neondb/auth ``` ## Add trusted origins Managed Better Auth only redirects to [trusted domains](https://neon.com/docs/auth/guides/configure-domains). Add the origin your app runs on, `http://localhost:3000` for local development, and your production origin when you deploy. Otherwise sign-in redirects and email verification links fail. ```bash filename="Terminal" neon neon-auth domain add http://localhost:3000 neon neon-auth domain add https://myapp.com ``` ## Configure the auth client Create a `src/auth.ts` file to initialize the auth client: **Tip: Using Auth and Data API together?** This quick start uses the standalone Auth client. For one `createClient()` instance that derives both Auth and Data API URLs from a single Neon URL, see [`createClient()` initialization](https://neon.com/docs/reference/javascript-sdk#initializing). ```typescript filename="src/auth.ts" import { createAuthClient } from '@neon/auth'; import { BetterAuthReactAdapter } from '@neon/auth/react/adapters'; export const authClient = createAuthClient(import.meta.env.VITE_NEON_AUTH_URL, { adapter: BetterAuthReactAdapter({ fetchOptions: { credentials: 'include' } }), }); ``` ## Create the Auth Provider Wrap your application in a TanStack Query `QueryClientProvider` and the `AuthProvider` the shadcn CLI copied into `src/components/auth/`. This makes the auth state available to the UI components used throughout your app. `navigate` receives the URL's `?redirectTo=` value after sign-in, so it checks the target before navigating. See [Validate redirect targets](https://neon.com/docs/auth/reference/ui-components#validate-redirect-targets). For the other props, see the [UI components reference](https://neon.com/docs/auth/reference/ui-components#provider-setup). ```tsx filename="src/routes/__root.tsx" import { getSafeRedirectTo } from '@better-auth-ui/core'; import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; import { Link, Outlet, createRootRoute, useRouter } from '@tanstack/react-router'; import type { ComponentProps } from 'react'; import { AuthProvider } from '@/components/auth/auth-provider'; import { Toaster } from '@/components/ui/sonner'; import { TooltipProvider } from '@/components/ui/tooltip'; import { authClient } from '../auth'; import '../styles.css'; const queryClient = new QueryClient(); export const Route = createRootRoute({ component: Root, }); function Root() { const router = useRouter(); return ( { const path = getSafeRedirectTo(to, window.location.origin); const target = path.startsWith('//') ? '/' : path; void router.navigate({ href: target, replace }); }} Link={RouterLink} redirectTo="/" > ); } // Better Auth UI passes an href with a query string, which `to` doesn't parse. function RouterLink({ href, to: _to, ...props }: { href: string; to?: string } & Omit, 'href'>) { const url = new URL(href, window.location.origin); return ( ); } ``` ## Create the Auth page Create a route to handle authentication views (sign in, sign up, etc.). Create `src/routes/auth.$path.tsx`. This route also serves `/auth/redirect`, which navigates on its own. Add the redirect check from [Validate redirect targets](https://neon.com/docs/auth/reference/ui-components#validate-redirect-targets) to `src/components/auth/auth-redirect.tsx`. ```tsx filename="src/routes/auth.$path.tsx" import { createFileRoute } from '@tanstack/react-router'; import { Auth } from '@/components/auth/auth'; export const Route = createFileRoute('/auth/$path')({ component: AuthPage, }); function AuthPage() { const { path } = Route.useParams(); return (
); } ``` ## Create the Settings page Create a route for the account and security settings. The user menu links to it. Create `src/routes/settings.$path.tsx`: ```tsx filename="src/routes/settings.$path.tsx" import { createFileRoute } from '@tanstack/react-router'; import { Settings } from '@/components/auth/settings/settings'; export const Route = createFileRoute('/settings/$path')({ component: SettingsPage, }); function SettingsPage() { const { path } = Route.useParams(); return (
); } ``` ## Protect your routes Read the session with `useSession`, and send signed-out visitors to the sign-in page. Wait until the session query has finished fetching: right after sign-up, the cached result is still signed out while the new session loads. Update `src/routes/index.tsx` to protect the home page: ```tsx filename="src/routes/index.tsx" import { useSession } from '@better-auth-ui/react'; import { createFileRoute, useNavigate } from '@tanstack/react-router'; import { useEffect } from 'react'; import { UserButton } from '@/components/auth/user/user-button'; import { authClient } from '@/auth'; export const Route = createFileRoute('/')({ component: Home, }); function Home() { const navigate = useNavigate(); const { data, isFetching } = useSession(authClient); const signedOut = !data && !isFetching; useEffect(() => { if (signedOut) void navigate({ to: '/auth/$path', params: { path: 'sign-in' } }); }, [signedOut, navigate]); if (!data) return null; return (

Welcome!

You're successfully authenticated.

Session and User Data:

          {JSON.stringify({ session: data.session, user: data.user }, null, 2)}
        
); } ``` ## Start your app Start the development server, then open [http://localhost:3000](http://localhost:3000). You'll be redirected to the sign-in page. ```bash filename="Terminal" npm run dev ``` ## See your users in the database As users sign up, their profiles are stored in your Neon database in the `neon_auth.user` table. Query your users table in the SQL Editor to see your new users: ```sql filename="SQL Editor" SELECT * FROM neon_auth.user; ``` ## Next steps - [Add email verification](https://neon.com/docs/auth/guides/email-verification) - [Learn how to branch your auth](https://neon.com/docs/auth/branching-authentication) - [More example apps](https://neon.com/docs/auth/about#example-applications) --- [Document source](https://neon.com/docs/auth/reference/nextjs-server.md) --- > Summary: Managed Better Auth Next.js Server SDK (`@neon/auth/next/server`) provides server-side authentication for Next.js apps via React Server Components, API routes, middleware, and server actions. Session caching uses a signed HTTP-only cookie to reduce Auth Server calls. Use this page to implement or debug server-side sign-in, sign-up, route protection, and admin user management in Next.js. Covers `createNeonAuth()` configuration, `auth.middleware()`, `auth.getSession()`, email/OTP/OAuth sign-in, organization and admin APIs, structured upstream error codes, and migration from v0.1. # Next.js Server SDK Reference Server-side authentication API for Next.js with Managed Better Auth Last updated: 2026-07-15 Reference documentation for the Managed Better Auth Next.js server SDK (`@neon/auth/next/server`). This package provides server-side authentication for Next.js applications using React Server Components, API routes, middleware, and server actions. For client-side authentication, see the [Client SDK reference](https://neon.com/docs/reference/javascript-sdk). For UI components, see the [UI Components reference](https://neon.com/docs/auth/reference/ui-components). ## Installation Install the Managed Better Auth package in your Next.js project using npm, yarn, pnpm, or bun. ```bash npm install @neon/auth@latest ``` ## Environment variables Configure these environment variables in your `.env.local` file: - **NEON_AUTH_BASE_URL** (required): Your Managed Better Auth server URL from the Neon Console - **NEON_AUTH_COOKIE_SECRET** (required): Secret for signing session cookies (must be 32+ characters for HMAC-SHA256 security) Generate a secure secret with: `openssl rand -base64 32` ```bash # Required: Your Managed Better Auth server URL NEON_AUTH_BASE_URL=https://your-neon-auth-url.neon.tech # Required: Cookie secret for session data signing (32+ characters) NEON_AUTH_COOKIE_SECRET=your-secret-at-least-32-characters-long ``` ## createNeonAuth() Method: `createNeonAuth(config)` Creates a unified auth instance that provides all server-side authentication functionality. Returns an `auth` object with: - `handler()` - Creates API route handlers - `middleware()` - Creates Next.js middleware for route protection - `getSession()` - Retrieves current session - All Better Auth server methods (signIn, signUp, signOut, etc.) ### Parameters | Parameter | Type | Required | Default | | ---------------------- | ------ | -------- | --------------------- | | baseUrl | string | ✓ | - | | cookies.secret | string | ✓ | - | | cookies.sessionDataTtl | number | | 300 | | cookies.domain | string | | - | | cookies.sameSite | string | | `strict` | | logLevel | string | | `warn` | | logger | object | | `console` (per level) | See [Server logging](https://neon.com/docs/auth/reference/nextjs-server#server-logging) and [Upstream fetch errors](https://neon.com/docs/auth/reference/nextjs-server#upstream-fetch-errors). ```typescript // lib/auth/server.ts import { createNeonAuth } from '@neon/auth/next/server'; export const auth = createNeonAuth({ baseUrl: process.env.NEON_AUTH_BASE_URL!, cookies: { secret: process.env.NEON_AUTH_COOKIE_SECRET!, }, // logLevel: 'silent', }); ``` ## Server logging Managed Better Auth emits structured logs from the API proxy, middleware, and Better Auth server `fetch` for upstream failures and session issues. **Defaults:** `logLevel: 'warn'` writes **`error`** and **`warn`** to **`console`**. Set **`logLevel: 'silent'`** to disable all Managed Better Auth `console` output (`'silent'` ignores any custom **`logger`**). Use **`info`** or **`debug`** for more detail during local troubleshooting. **Custom sink:** Pass a partial **`logger`** object with `error`, `warn`, `info`, and/or `debug` methods. Omitted methods still use `console`. Metadata may include `err` and `detail` for observability tools. `auth.middleware()` inherits the same resolved logging configuration from `createNeonAuth` (no per-request reconfiguration). ```typescript import { createNeonAuth } from '@neon/auth/next/server'; export const auth = createNeonAuth({ baseUrl: process.env.NEON_AUTH_BASE_URL!, cookies: { secret: process.env.NEON_AUTH_COOKIE_SECRET! }, logLevel: 'debug', logger: { warn(message, meta) { myLogger.warn({ message, ...meta }); }, }, }); ``` | logLevel | Console output | | ---------------- | ----------------------- | | `silent` | None | | `error` | `error` only | | `warn` (default) | `error`, `warn` | | `info` | `error`, `warn`, `info` | | `debug` | all levels | ## auth.handler() Method: `auth.handler()` Creates GET and POST route handlers for the Managed Better Auth API proxy. Create a catch-all route at `app/api/auth/[...path]/route.ts`. This handles all authentication API calls from your client, including: - Sign in/sign up requests - OAuth callbacks - Session management - Email verification - Password reset ### Returns Object with `GET`, `POST`, `PUT`, `PATCH`, and `DELETE` Next.js route handlers. ```typescript // app/api/auth/[...path]/route.ts import { auth } from '@/lib/auth/server'; export const { GET, POST, PUT, PATCH, DELETE } = auth.handler(); ``` ## auth.middleware() Method: `auth.middleware(options)` Creates Next.js middleware for session validation and route protection. The middleware automatically: - Validates session cookies on each request - Provides session data to server components - Redirects unauthenticated users to the login page - Refreshes session tokens when needed ### Parameters
View parameters | Parameter | Type | Required | Default | | ------------ | --------- | -------- | --------------------------------------------------- | | loginUrl | string | | `/auth/sign-in` | | publicRoutes | string\[] | | `/api/auth` and the Better Auth UI signed-out views | `publicRoutes` adds routes that don't require a session, on top of the defaults. An entry matches the exact path and its subpaths, so `/pricing` also matches `/pricing/enterprise`. `"/"` matches only `/`. An invalid entry throws. `/auth` itself and `/settings/*` stay protected.
**Note: Next.js version compatibility** `proxy.ts` replaces `middleware.ts` in Next.js 16. On earlier versions, name the file `middleware.ts` and export `default function middleware` instead of `proxy`. The auth logic is identical. ```typescript filename="proxy.ts" import { auth } from '@/lib/auth/server'; export default auth.middleware({ loginUrl: '/auth/sign-in', publicRoutes: ['/'] }); export const config = { matcher: [ // Match all paths except static files "/((?!_next/static|_next/image|favicon.ico).*)", ], }; ``` ## auth.getSession() Method: `auth.getSession()` Retrieves the current session in Server Components, Server Actions, and API Routes. - Returns cached session if available (fast) - Automatically refreshes expired tokens - Returns null if no active session Server Components that use `auth.getSession()` must export `dynamic = 'force-dynamic'` because session data depends on cookies. ### Returns | Field | Type | Description | | ------- | --------------- | ---------------------------------------------------- | | `data` | Session \| null | Session with user data, or null if not authenticated | | `error` | Error \| null | Error object if session retrieval failed | **Server Component** ```typescript // app/dashboard/page.tsx import { auth } from '@/lib/auth/server'; export const dynamic = 'force-dynamic'; export default async function DashboardPage() { const { data: session } = await auth.getSession(); if (!session?.user) { return
Not authenticated
; } return

Welcome, {session.user.name}

; } ``` **Server Action** ```typescript // app/actions.ts 'use server'; import { auth } from '@/lib/auth/server'; import { redirect } from 'next/navigation'; export async function updateProfile(formData: FormData) { const { data: session } = await auth.getSession(); if (!session?.user) { redirect('/auth/sign-in'); } // Update user profile... } ``` **API Route** ```typescript // app/api/user/route.ts import { auth } from '@/lib/auth/server'; export async function GET() { const { data: session } = await auth.getSession(); if (!session?.user) { return Response.json({ error: 'Unauthorized' }, { status: 401 }); } return Response.json({ user: session.user }); } ``` ## auth.signIn.email() Method: `auth.signIn.email(credentials)` Sign in with email and password. Use in Server Actions for form-based authentication. ### Parameters
View parameters | Parameter | Type | Required | | --------- | ------ | -------- | | email | string | ✓ | | password | string | ✓ |
```typescript 'use server'; import { auth } from '@/lib/auth/server'; import { redirect } from 'next/navigation'; export async function signIn(formData: FormData) { const { data, error } = await auth.signIn.email({ email: formData.get('email') as string, password: formData.get('password') as string, }); if (error) return { error: error.message }; redirect('/dashboard'); } ``` ## auth.signIn.social() Method: `auth.signIn.social(options)` Sign in with OAuth provider like Google, GitHub, etc. ### Parameters
View parameters | Parameter | Type | Required | | ----------- | ------ | -------- | | provider | string | ✓ | | callbackURL | string | |
```typescript const { data, error } = await auth.signIn.social({ provider: 'google', callbackURL: '/dashboard', }); ``` ## auth.signIn.emailOtp() Method: `auth.signIn.emailOtp(credentials)` Sign in with email OTP (one-time password). First call `emailOtp.sendVerificationOtp()` to send the code. ### Parameters
View parameters | Parameter | Type | Required | | --------- | ------ | -------- | | email | string | ✓ | | otp | string | ✓ |
```typescript const { data, error } = await auth.signIn.emailOtp({ email: 'user@example.com', otp: '123456', }); ``` ## auth.signUp.email() Method: `auth.signUp.email(credentials)` Create a new user account with email and password. ### Parameters
View parameters | Parameter | Type | Required | | --------- | ------ | -------- | | email | string | ✓ | | password | string | ✓ | | name | string | ✓ |
```typescript const { data, error } = await auth.signUp.email({ email: 'user@example.com', password: 'secure-password', name: 'John Doe', }); ``` ## auth.signOut() Method: `auth.signOut()` Sign out the current user. Clears session and authentication tokens. ```typescript 'use server'; import { auth } from '@/lib/auth/server'; import { redirect } from 'next/navigation'; export async function signOut() { await auth.signOut(); redirect('/auth/sign-in'); } ``` ## auth.updateUser() Method: `auth.updateUser(data)` Update the current user's profile. Password updates require the password reset flow for security. ### Parameters
View parameters | Parameter | Type | Required | | --------- | ------------------- | -------- | | name | string \| undefined | | | image | string \| undefined | |
```typescript const { data, error } = await auth.updateUser({ name: 'Jane Doe', image: 'https://example.com/avatar.jpg', }); ``` ## auth.changePassword() Method: `auth.changePassword(passwords)` Change the current user's password. ### Parameters
View parameters | Parameter | Type | Required | | ------------------- | ------- | -------- | | currentPassword | string | ✓ | | newPassword | string | ✓ | | revokeOtherSessions | boolean | |
```typescript const { data, error } = await auth.changePassword({ currentPassword: 'old-password', newPassword: 'new-password', revokeOtherSessions: true, }); ``` ## auth.sendVerificationEmail() Method: `auth.sendVerificationEmail(options)` Send email verification to the current user. ### Parameters
View parameters | Parameter | Type | Required | | ----------- | ------ | -------- | | callbackURL | string | |
```typescript const { data, error } = await auth.sendVerificationEmail({ callbackURL: '/dashboard', }); ``` ## auth.deleteUser() Method: `auth.deleteUser()` Delete the current user account. This action is irreversible. ```typescript const { data, error } = await auth.deleteUser(); ``` ## auth.emailOtp.sendVerificationOtp() Method: `auth.emailOtp.sendVerificationOtp(options)` Send a one-time password via email. Available when Email OTP authentication is enabled. ### Parameters
View parameters | Parameter | Type | Required | | --------- | ------ | -------- | | email | string | ✓ |
```typescript const { data, error } = await auth.emailOtp.sendVerificationOtp({ email: 'user@example.com', }); ``` ## auth.emailOtp.verifyEmail() Method: `auth.emailOtp.verifyEmail(credentials)` Verify email with OTP code. ### Parameters
View parameters | Parameter | Type | Required | | --------- | ------ | -------- | | email | string | ✓ | | otp | string | ✓ |
```typescript const { data, error } = await auth.emailOtp.verifyEmail({ email: 'user@example.com', otp: '123456', }); ``` ## auth.listSessions() Method: `auth.listSessions()` List all active sessions for the current user. ```typescript const { data, error } = await auth.listSessions(); ``` ## auth.revokeSession() Method: `auth.revokeSession(options)` Revoke a specific session by ID. ### Parameters
View parameters | Parameter | Type | Required | | --------- | ------ | -------- | | sessionId | string | ✓ |
```typescript const { data, error } = await auth.revokeSession({ sessionId: 'session-id', }); ``` ## auth.revokeOtherSessions() Method: `auth.revokeOtherSessions()` Revoke all sessions except the current one. ```typescript const { data, error } = await auth.revokeOtherSessions(); ``` ## auth.organization.create() Method: `auth.organization.create(data)` Create a new organization. Available when the organizations plugin is enabled. ### Parameters
View parameters | Parameter | Type | Required | | --------- | ------ | -------- | | name | string | ✓ | | slug | string | |
```typescript const { data, error } = await auth.organization.create({ name: 'My Organization', slug: 'my-org', }); ``` ## auth.organization.list() Method: `auth.organization.list()` List the current user's organizations. ```typescript const { data, error } = await auth.organization.list(); ``` ## auth.organization.inviteMember() Method: `auth.organization.inviteMember(options)` Invite a member to an organization. ### Parameters
View parameters | Parameter | Type | Required | | -------------- | ------ | -------- | | organizationId | string | ✓ | | email | string | ✓ | | role | string | |
```typescript const { data, error } = await auth.organization.inviteMember({ organizationId: 'org-id', email: 'member@example.com', role: 'member', }); ``` ## auth.admin.listUsers() Method: `auth.admin.listUsers(options)` List all users. Available for users with admin role. ### Parameters
View parameters | Parameter | Type | Required | | --------- | ------ | -------- | | limit | number | | | offset | number | |
```typescript const { data, error } = await auth.admin.listUsers({ limit: 100, offset: 0, }); ``` ## auth.admin.banUser() Method: `auth.admin.banUser(options)` Ban a user. Available for users with admin role. ### Parameters
View parameters | Parameter | Type | Required | | --------- | ------ | -------- | | userId | string | ✓ | | reason | string | |
```typescript const { data, error } = await auth.admin.banUser({ userId: 'user-id', reason: 'Violation of terms', }); ``` ## auth.admin.setRole() Method: `auth.admin.setRole(options)` Set a user's role. Available for users with admin role. ### Parameters
View parameters | Parameter | Type | Required | | --------- | ------ | -------- | | userId | string | ✓ | | role | string | ✓ |
```typescript const { data, error } = await auth.admin.setRole({ userId: 'user-id', role: 'admin', }); ``` ## Upstream fetch errors When the SDK cannot reach your Managed Better Auth server (wrong `baseUrl`, DNS, TLS, timeout), the API proxy returns a synthetic **502** JSON body with a stable **`code`**. Server methods such as `auth.signIn.email()` surface the same codes on **`error.code`** when the failure is transport-related. | Code | Typical cause | | ----------------- | ------------------------- | | `NETWORK_DNS` | Hostname does not resolve | | `NETWORK_REFUSED` | Connection refused | | `NETWORK_TIMEOUT` | Request timed out | | `NETWORK_TLS` | TLS / certificate error | | `NETWORK_RESET` | Connection reset | | `NETWORK_ABORT` | Request aborted | | `NETWORK_ERROR` | Other transport failure | Client-visible messages are generic (for example, "Could not resolve authentication server hostname"). Check server logs (set `logLevel: 'debug'`) for `detail` and the raw error. **Non-transport failures** (unexpected exceptions while handling a response) are **re-thrown** so Next.js error boundaries still receive the original error. HTTP **4xx** upstream responses are logged at **`info`**; **5xx** at **`warn`**. ```typescript 'use server'; import { auth } from '@/lib/auth/server'; export async function signIn(formData: FormData) { const { error } = await auth.signIn.email({ email: formData.get('email') as string, password: formData.get('password') as string, }); if (error?.code === 'NETWORK_DNS') { return { error: 'Check NEON_AUTH_BASE_URL in .env.local' }; } if (error) { return { error: error.message }; } } ``` ## Performance features ### Session caching Session data is automatically cached in a signed, HTTP-only cookie to reduce API calls to the Auth Server by 95-99%. - Default cache TTL: 5 minutes (300 seconds) - Configurable via `cookies.sessionDataTtl` - Automatic expiration based on JWT `exp` claim - Synchronous cache clearing on sign-out - Secure HMAC-SHA256 signing ### Request deduplication Multiple concurrent `getSession()` calls are automatically deduplicated: - Single network request for concurrent calls - 10x faster cold starts - Reduces server load ```typescript // First call: Fetches from Auth Server const { data: session } = await auth.getSession(); // Subsequent calls within TTL: Uses cached data (no API call) const { data: session2 } = await auth.getSession(); ``` ## Configuration reference Complete configuration options for `createNeonAuth()`: | Option | Type | Required | Default | | ------------------------ | ------ | -------- | --------- | | `baseUrl` | string | Yes | - | | `cookies.secret` | string | Yes | - | | `cookies.sessionDataTtl` | number | No | 300 | | `cookies.domain` | string | No | undefined | | `cookies.sameSite` | string | No | `strict` | | `logLevel` | string | No | `warn` | | `logger` | object | No | `console` | - **baseUrl**: Your Managed Better Auth server URL from the Neon Console - **cookies.secret**: Secret for HMAC-SHA256 signing (32+ characters) - **cookies.sessionDataTtl**: Cache TTL in seconds for the signed `session_data` cookie - **cookies.domain**: For cross-subdomain sessions (for example, ".example.com") - **cookies.sameSite**: `strict` (default), `lax`, or `none`. Use `lax` or `none` if you embed the app in a third-party iframe or need cookies on cross-site navigations - **logLevel**: `silent`, `error`, `warn`, `info`, or `debug` — see [Server logging](https://neon.com/docs/auth/reference/nextjs-server#server-logging) - **logger**: Optional custom logger; see [Server logging](https://neon.com/docs/auth/reference/nextjs-server#server-logging) ```typescript import { createNeonAuth } from '@neon/auth/next/server'; export const auth = createNeonAuth({ baseUrl: process.env.NEON_AUTH_BASE_URL!, cookies: { secret: process.env.NEON_AUTH_COOKIE_SECRET!, }, }); ``` ## Project structure Recommended file structure for Next.js with Managed Better Auth: - `app/api/auth/[...path]/route.ts` - Auth API handlers - `app/auth/[path]/page.tsx` - Auth views (sign-in, sign-up) - `app/dashboard/page.tsx` - Protected pages - `lib/auth/server.ts` - Server auth instance - `lib/auth/client.ts` - Client auth instance - `proxy.ts` (Next.js 16+) or `middleware.ts` (earlier versions) - Route protection **Note: Next.js version compatibility** `proxy.ts` replaces `middleware.ts` in Next.js 16. On earlier versions, name the file `middleware.ts` and export `default function middleware` instead of `proxy`. The auth logic is identical. ``` app/ ├── api/ │ └── auth/ │ └── [...path]/ │ └── route.ts ├── auth/ │ └── [path]/ │ └── page.tsx ├── dashboard/ │ └── page.tsx ├── actions.ts └── layout.tsx lib/ └── auth/ ├── server.ts └── client.ts proxy.ts # or middleware.ts on Next.js < 16 .env.local ``` ## Migration from v0.1 If you're upgrading from Managed Better Auth SDK v0.1, see the [migration guide](https://neon.com/docs/auth/migrate/from-auth-v0.1) for step-by-step instructions. ## Related documentation - [Client SDK Reference](https://neon.com/docs/reference/javascript-sdk) - Client-side authentication - [UI Components Reference](https://neon.com/docs/auth/reference/ui-components) - Pre-built auth UI - [Next.js quick start](https://neon.com/docs/auth/quick-start/nextjs-api-only) - Getting started guide - [Migration Guide](https://neon.com/docs/auth/migrate/from-auth-v0.1) - Upgrading from v0.1 --- [Document source](https://neon.com/docs/auth/reference/ui-components.md) --- > Summary: How to add Better Auth UI's shadcn/ui components to an app on Managed Better Auth: install them with the shadcn CLI, wrap the app in `AuthProvider` with the `@neon/auth` client, and render `` on `/auth/[path]` and `` in the header. Use this page for the provider props, redirect validation, and route protection. # UI Components Reference Sign-in, sign-up, and user menu components for Managed Better Auth Last updated: 2026-09-16 Managed Better Auth works with [Better Auth UI](https://better-auth-ui.com): sign-in, sign-up, password reset, and user menu components for Better Auth. The shadcn CLI copies the components into your app, so you can edit them. `@better-auth-ui/react` provides the hooks and data layer they use. **Note: Coming from @neondatabase/auth-ui** `@neondatabase/auth-ui` is deprecated. Existing apps keep working; new apps use Better Auth UI. `NeonAuthUIProvider` becomes `AuthProvider`, `` becomes ``, and the CSS imports go away because your app's Tailwind compiles the copied components. ## Installation Better Auth UI needs React 19.2.6 or later and Tailwind CSS 4.3.2 or later. If the project doesn't use shadcn/ui yet, initialize it first: ```bash npx shadcn@latest init ``` ### Add the components Add the auth views, and the user menu if you want one: ```bash npx shadcn@latest add @better-auth-ui/auth npx shadcn@latest add @better-auth-ui/user-button ``` The CLI writes the components to `components/auth/` and their shadcn/ui primitives to `components/ui/`, and installs `@better-auth-ui/react`, `@better-auth-ui/core`, and TanStack Query. The components list `better-auth` without a version, so the CLI installs the npm `latest` tag, which can be a newer pre-release than the version `@neon/auth` uses. After your last `shadcn add`, align it with `@neon/auth` so the app has one copy of Better Auth: ```bash npm i better-auth@~1.7.12 ``` ## Provider setup Wrap the app in a TanStack Query `QueryClientProvider` and the copied `AuthProvider`. Pass the client from `createAuthClient()` in `@neon/auth` as `authClient`; it needs no adapter or type cast. ```tsx 'use client'; import { getSafeRedirectTo } from '@better-auth-ui/core'; import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; import Link from 'next/link'; import { useRouter } from 'next/navigation'; import { useState } from 'react'; import { AuthProvider } from '@/components/auth/auth-provider'; import { Toaster } from '@/components/ui/sonner'; import { TooltipProvider } from '@/components/ui/tooltip'; import { authClient } from '@/lib/auth/client'; export function Providers({ children }: { children: React.ReactNode }) { const router = useRouter(); const [queryClient] = useState(() => new QueryClient()); return ( { const path = getSafeRedirectTo(to, window.location.origin); const target = path.startsWith('//') ? '/' : path; if (replace) router.replace(target); else router.push(target); }} Link={Link} redirectTo="/" > {children} ); } ``` Render `` once: the components report errors as toasts. In a single-page app, you can create the `QueryClient` once at module level instead. | Prop | Description | | ------------------ | --------------------------------------------------------------------------------------------------------------------------- | | `authClient` | **Required.** The client from `createAuthClient()` in `@neon/auth`. | | `navigate` | **Required.** Called with `{ to, replace }` for every navigation the components make. | | `Link` | **Required.** The router's link component, for example `next/link` or a TanStack Router `Link` adapter. | | `redirectTo` | Where to go after sign-in when the URL has no `?redirectTo=`. | | `emailAndPassword` | Email and password options. Set `requireEmailVerification` to match your branch's **Verify email at signup** setting. | | `socialProviders` | OAuth provider buttons to show, for example `['google', 'github']`. Configure the providers for your branch first. | | `plugins` | Better Auth UI plugins, for example `emailOtpPlugin()`. A UI plugin doesn't enable the matching Managed Better Auth plugin. | ### Validate redirect targets After sign-in, the components call `navigate` with the `?redirectTo=` value from the URL. Check it before you navigate, as in the example above, so a link like `/auth/sign-in?redirectTo=https://example.com` can't send a signed-in user to another site. `getSafeRedirectTo` returns `/` for other origins, but it can return a protocol-relative path such as `//example.com` for `/a/..//example.com`, so also reject a result that starts with `//`. The `/auth/redirect` view navigates without `navigate`. Add the same check to the copied `components/auth/auth-redirect.tsx`: ```tsx filename="components/auth/auth-redirect.tsx" window.location.replace(action.to); window.location.replace(action.to.startsWith('//') ? '/' : action.to); ``` ## Components | Component | Purpose | | -------------- | ------------------------------------------------------------------------------------------------------------ | | `` | Renders the auth view for a path: `sign-in`, `sign-up`, `forgot-password`, `reset-password`, `sign-out`, ... | | `` | Avatar and menu with the signed-in user and Sign Out. `hideSettings` hides the Settings link. | Hooks from `@better-auth-ui/react`: | Hook | Purpose | | ----------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------- | | `useSession(authClient)` | The session as a TanStack Query result (`data`, `isPending`, `isFetching`). | | `useAuthenticate(authClient)` | The session, and a redirect to sign-in when there is none. See [Protected routes](https://neon.com/docs/auth/reference/ui-components#protected-routes). | ## Next.js App Router Create `app/auth/[path]/page.tsx`. The valid paths come from `viewPaths.auth` in `@better-auth-ui/core`: ```tsx import { viewPaths } from '@better-auth-ui/core'; import { Auth } from '@/components/auth/auth'; export const dynamicParams = false; export function generateStaticParams() { return Object.values(viewPaths.auth).map((path) => ({ path })); } export default async function AuthPage({ params }: { params: Promise<{ path: string }> }) { const { path } = await params; return (
); } ``` The `/auth/[path]` route also serves `/auth/sign-out`, which the user menu's **Sign Out** opens. Add the user menu to a header. Its **Settings** link opens `/settings/account`: add `npx shadcn@latest add @better-auth-ui/settings` and a `settings/[path]` route that renders ``, or pass `hideSettings`. ```tsx import { UserButton } from '@/components/auth/user/user-button'; export function Header() { return (
); } ``` ## Protected routes Redirect signed-out requests on the server, with `auth.middleware()` in `proxy.ts` (see the [Next.js server reference](https://neon.com/docs/auth/reference/nextjs-server)) or your router's guard. ```typescript filename="proxy.ts" import { auth } from '@/lib/auth/server'; export default auth.middleware({ loginUrl: '/auth/sign-in', publicRoutes: ['/'] }); ``` Better Auth UI's signed-out views, such as reset password, verify email, and magic link, and `/api/auth` are public by default, so you don't need a custom `proxy.ts` for them. `/auth` itself and `/settings/*` stay protected. Use `publicRoutes` for your own public pages, such as a landing page. On the page, read the session with `useSession()` and wait for it to load. `useAuthenticate()` redirects whenever it has no session and the query isn't pending, including while a stale signed-out result refetches. Right after sign-up, that sends the new user back to sign-in. If you redirect on the client, wait until `isFetching` is `false`: ```tsx const { data: session, isFetching } = useSession(authClient); const signedOut = !session && !isFetching; ``` ## Styling The copied components use your app's Tailwind build and shadcn/ui theme variables. `shadcn init` adds the theme to your global CSS, including: ```css @import 'tailwindcss'; @import 'tw-animate-css'; @import 'shadcn/tailwind.css'; ``` To change colors, radius, or dark mode, edit the theme variables in that file or the component files in `components/auth/`. ## Next steps - See the [Neon examples](https://github.com/neondatabase/examples/tree/main/realtime) for apps that use these components with Next.js, TanStack Start, and Vite - Read the [Better Auth UI docs](https://better-auth-ui.com/docs) for every component, plugin, and hook - Check the [Neon TypeScript SDK](https://neon.com/docs/reference/javascript-sdk) for programmatic auth methods --- [Document source](https://neon.com/docs/auth/roadmap.md) --- > Summary: Managed Better Auth roadmap showing supported frameworks (Next.js, Vite+React, TanStack Router) and Better Auth plugins (email OTP, magic link, JWT, organization) alongside features still in progress. Check here to confirm whether MFA, admin plugin customization, or standalone frontend/backend architectures are available yet. Migration guides from Supabase and legacy Stack Auth, plus SDK references for the TypeScript client and Next.js server SDK, are also indexed here. # Managed Better Auth roadmap What's supported today and what's coming next Last updated: 2026-09-17 Managed Better Auth is in active development. This page shows what's currently supported and what we're working on next. ## General availability Managed Better Auth is generally available. We're actively working on additional plugins and features. ## Frameworks ### Supported | Framework | Status | Quick start | | ----------------------- | ----------- | --------------------------------------------------------------------- | | Next.js | ✅ Supported | [Get started](https://neon.com/docs/auth/quick-start/nextjs-api-only) | | Vite + React | ✅ Supported | [Get started](https://neon.com/docs/auth/quick-start/react) | | React + React Router | ✅ Supported | [Get started](https://neon.com/docs/auth/quick-start/react) | | React + TanStack Router | ✅ Supported | [Get started](https://neon.com/docs/auth/quick-start/tanstack-router) | The [React quick start](https://neon.com/docs/auth/quick-start/react) steps through a **Vite** + React app. If you use **React Router** for URLs and layouts, use the same Managed Better Auth URL, `@neon/neon-js` client, and SDK calls from that guide, then integrate them into your router and route components. For file-based routing with TanStack, use the TanStack Router quick start instead. ### On the roadmap | Framework | Status | | ----------------------------- | --------------- | | Standalone frontend + backend | 🔜 Coming soon | | Other frameworks | Based on demand | **Note: Standalone architectures** Architectures where frontend and backend are separate deployments (for example, Create-React-App with a separate Node/Express backend) are not yet supported. Managed Better Auth uses HTTP-only cookies for secure session management, and these cookies cannot be securely shared between frontend and backend applications on different domains. We're actively working on this. ## Better Auth plugins Managed Better Auth is built on [Better Auth](https://www.better-auth.com/). Not all Better Auth plugins are currently supported. ### Supported | Plugin | Status | | ---------------------------------------------------------------------------------- | ----------- | | [Email & password](https://www.better-auth.com/docs/authentication/email-password) | ✅ Supported | | Social OAuth (Google, GitHub, Vercel, Microsoft, Apple) | ✅ Supported | | [Email OTP](https://neon.com/docs/auth/guides/plugins/email-otp) | ✅ Supported | | [Admin](https://neon.com/docs/auth/guides/plugins/admin) | ✅ Supported | | [Organization](https://neon.com/docs/auth/guides/plugins/organization) | ⚠️ Partial | | [JWT](https://neon.com/docs/auth/guides/plugins/jwt) | ✅ Supported | | [Magic Link](https://neon.com/docs/auth/guides/plugins/magic-link) | ✅ Supported | | [Open API](https://neon.com/docs/auth/guides/plugins/openapi) | ✅ Supported | | [Phone Number](https://neon.com/docs/auth/guides/plugins/phone-number) | ✅ Supported | See [Set up OAuth](https://neon.com/docs/auth/guides/setup-oauth) for Neon-specific OAuth configuration (including Vercel). Email flows such as verification and password reset are covered in [Email verification](https://neon.com/docs/auth/guides/email-verification), [Password reset](https://neon.com/docs/auth/guides/password-reset), and [User management](https://neon.com/docs/auth/guides/user-management). ### Platform (Console, API, webhooks) These capabilities are documented in Managed Better Auth guides but are not Better Auth plugins you enable through the SDK. | Capability | Status | Documentation | | ------------------------------------ | --------- | ----------------------------------------------------------------------------------------- | | Trusted domains (redirect allowlist) | Supported | [Configure trusted domains](https://neon.com/docs/auth/guides/configure-domains) | | Webhooks (auth events) | Supported | [Webhooks](https://neon.com/docs/auth/guides/webhooks) | | Manage Auth via Neon API | Supported | [Manage Auth in the Neon API](https://neon.com/docs/auth/guides/manage-auth-api) | | Manage Auth via Neon MCP (AI editor) | Supported | [Set up with your AI editor](https://neon.com/docs/auth/about#set-up-with-your-ai-editor) | Branch-aware auth (separate auth state per Neon branch) is supported; see [Branching authentication](https://neon.com/docs/auth/branching-authentication) and [Authentication flow](https://neon.com/docs/auth/authentication-flow). ### On the roadmap | Plugin | Status | | ----------------------------------------------------------------------------- | --------------- | | MFA support | 🔜 Coming soon | | [Admin](https://neon.com/docs/auth/guides/plugins/admin) plugin customization | 🔜 Coming soon | | Other plugins | Based on demand | ## SDK and UI references | Surface | Documentation | | --------------------------------- | ------------------------------------------------------------------------ | | TypeScript client SDK (`neon-js`) | [Neon TypeScript SDK](https://neon.com/docs/reference/javascript-sdk) | | Next.js server SDK | [Next.js Server SDK](https://neon.com/docs/auth/reference/nextjs-server) | | Pre-built UI components | [UI components](https://neon.com/docs/auth/reference/ui-components) | ## Migration guides - [From Managed Better Auth SDK v0.1](https://neon.com/docs/auth/migrate/from-auth-v0.1) - [From Stack Auth (legacy)](https://neon.com/docs/auth/migrate/from-legacy-auth) - [From Supabase](https://neon.com/docs/auth/migrate/from-supabase) ## Production and checklist For launch readiness, see the [production checklist](https://neon.com/docs/auth/production-checklist). ## Let us know We prioritize based on demand. If you need a specific framework or plugin, let us know on our [Discord](https://neon.com/discord). --- [Document source](https://neon.com/docs/auth/troubleshooting.md) --- > Summary: Troubleshooting for common Managed Better Auth errors in `@neon/auth` (Next.js and React SPA). Covers missing `NEON_AUTH_COOKIE_SECRET`, missing `force-dynamic` on server components, `NETWORK_DNS` / `NETWORK_TIMEOUT` upstream errors, `Origin` errors when scripts call the Auth API directly, and OAuth `redirect_uri_mismatch` from misconfigured callback URIs. Use this page when Managed Better Auth fails at startup, sessions do not persist, or OAuth logins loop back to the provider instead of the app. # Auth troubleshooting Common issues when implementing Managed Better Auth and how to fix them Last updated: 2026-11-05 This page covers common issues when integrating [Managed Better Auth](https://neon.com/docs/auth/overview) with `@neon/auth` in Next.js apps and React SPAs. ## Missing NEON_AUTH_COOKIE_SECRET If your Next.js app throws an error about a missing or invalid cookie secret at startup, the `NEON_AUTH_COOKIE_SECRET` environment variable is either unset or too short. The secret must be at least 32 characters for HMAC-SHA256. Generate one with: ```bash openssl rand -base64 32 ``` See the [Next.js Server SDK reference](https://neon.com/docs/auth/reference/nextjs-server) for the full list of required environment variables. ## Missing force-dynamic on server components If `next build` fails with a "Dynamic server usage" error on a page that calls `auth.getSession()`, the server component needs to opt out of static rendering: ```typescript export const dynamic = 'force-dynamic'; export default async function Page() { const { data: session } = await auth.getSession(); // ... } ``` This is required because `getSession()` reads cookies, which are only available at request time. See [getSession](https://neon.com/docs/auth/reference/nextjs-server#get-session) in the Next.js Server SDK reference. ## Managed Better Auth server logging in the terminal You may see structured **`warn`** or **`error`** lines in the Next.js server console when the auth proxy cannot reach Managed Better Auth or when session cookies fail validation. This is expected: the SDK defaults to **`logLevel: 'warn'`** (opt-out). To mute Managed Better Auth console output: ```typescript export const auth = createNeonAuth({ baseUrl: process.env.NEON_AUTH_BASE_URL!, cookies: { secret: process.env.NEON_AUTH_COOKIE_SECRET! }, logLevel: 'silent', }); ``` To investigate further, use **`logLevel: 'debug'`** or a custom **`logger`**. See [Server logging](https://neon.com/docs/auth/reference/nextjs-server#server-logging). ## Upstream NETWORK_* errors Server actions or API routes may return errors with **`code`** values such as **`NETWORK_DNS`**, **`NETWORK_REFUSED`**, or **`NETWORK_TIMEOUT`**. These mean your app could not reach the Auth server at **`NEON_AUTH_BASE_URL`** (typo, wrong branch URL, offline network, or TLS issue). 1. Confirm **`NEON_AUTH_BASE_URL`** in `.env.local` matches the Auth URL in the Neon Console (Project → Branch → Auth → Configuration). 2. Restart the dev server after changing env vars. 3. Enable **`logLevel: 'debug'`** and retry; logs include a safe **`detail`** field. See [Upstream fetch errors](https://neon.com/docs/auth/reference/nextjs-server#upstream-fetch-errors) for the full code list. ## Origin errors from scripts and server-side calls Managed Better Auth checks the `Origin` header on `POST` requests such as sign-up, sign-in, and sign-out. Browsers send it for you, and so does the `@neon/auth` Next.js handler. Seed scripts, tests, and server code that call `NEON_AUTH_BASE_URL` directly have to send it themselves. Without a trusted `Origin`, the request fails: | Response | Cause | | ------------------------------ | ------------------------------------------------------------- | | `403` `MISSING_OR_NULL_ORIGIN` | No `Origin` header (or `Origin: null`) on sign-in or sign-out | | `400` `MISSING_ORIGIN` | No `Origin` header on sign-up | | `403` `INVALID_ORIGIN` | The `Origin` isn't a trusted domain | Set `Origin` to a trusted domain: ```typescript const res = await fetch(`${process.env.NEON_AUTH_BASE_URL}/sign-in/email`, { method: 'POST', headers: { 'Content-Type': 'application/json', Origin: 'http://localhost:3000', }, body: JSON.stringify({ email: 'alex@example.com', password: 'AbC123dEf' }), }); ``` Any `localhost` origin is trusted while [localhost access](https://neon.com/docs/auth/production-checklist#localhost-access) is on, which it is by default. Add any other origin as a [trusted domain](https://neon.com/docs/auth/guides/configure-domains), for example with `neon neon-auth domain add https://myapp.com`. ## Cookies blocked in iframe or cross-site embeds Managed Better Auth cookies default to **`SameSite=Strict`**. If your app runs inside another site's **iframe**, or needs cookies on top-level cross-site navigations, sessions may not persist. Set an explicit SameSite mode when creating the auth instance: ```typescript export const auth = createNeonAuth({ baseUrl: process.env.NEON_AUTH_BASE_URL!, cookies: { secret: process.env.NEON_AUTH_COOKIE_SECRET!, sameSite: 'lax', // or 'none' for third-party iframe contexts (requires HTTPS) }, }); ``` See [Configuration reference](https://neon.com/docs/auth/reference/nextjs-server#configuration-reference) and the [Next.js quick start](https://neon.com/docs/auth/quick-start/nextjs-api-only). ## Using v0.1 API patterns If you are upgrading from v0.1, use `createNeonAuth()` + `auth.handler()` instead of the old standalone `authApiHandler()`. See the [migration guide](https://neon.com/docs/auth/migrate/from-auth-v0.1) for details. ## Using useSession() without adapter in React SPA In a React SPA, `createAuthClient(url)` without an adapter returns a vanilla client with no React hooks. Calling `useSession()` on this client will fail. Either pass `BetterAuthReactAdapter()`, or read the session with `useSession(authClient)` from `@better-auth-ui/react`, which takes any Managed Better Auth client. It reads the session through TanStack Query, so wrap your app in a `QueryClientProvider` (or pass a `queryClient` as the third argument). ```typescript import { createAuthClient } from '@neon/auth'; import { BetterAuthReactAdapter } from '@neon/auth/react/adapters'; const authClient = createAuthClient(url, { adapter: BetterAuthReactAdapter(), }); ``` The [TanStack Router quick start](https://neon.com/docs/auth/quick-start/tanstack-router) shows a complete setup with the React adapter. ## Wrong BetterAuthReactAdapter import The adapter must be imported from a subpath and called as a function: ```typescript // Wrong import { BetterAuthReactAdapter } from '@neon/auth'; // Correct import { BetterAuthReactAdapter } from '@neon/auth/react/adapters'; const client = createAuthClient(url, { adapter: BetterAuthReactAdapter() }); ``` ## Auth UI components are unstyled Better Auth UI's components are compiled by your app's Tailwind build. If they render without styles, check that your global CSS imports the shadcn/ui theme that `npx shadcn@latest init` adds (`tw-animate-css` and `shadcn/tailwind.css`, plus the theme variables), and that Tailwind scans the folder the components were copied to. See the [UI Components reference](https://neon.com/docs/auth/reference/ui-components) for complete setup instructions. ## Missing "use client" directive In Next.js, any component that uses `useSession()` or other React hooks must include `"use client"` at the top of the file. Without it, Next.js treats the file as a server component where React hooks are not available. ## Wrong createAuthClient signature The `createAuthClient` function has different signatures depending on the import path: ```typescript // React SPA — import from @neon/auth import { createAuthClient } from '@neon/auth'; createAuthClient(url); createAuthClient(url, { adapter: BetterAuthReactAdapter() }); // Next.js — import from @neon/auth/next (no arguments, uses proxy) import { createAuthClient } from '@neon/auth/next'; createAuthClient(); ``` See the [Next.js quick start](https://neon.com/docs/auth/quick-start/nextjs-api-only) and the [React quick start](https://neon.com/docs/auth/quick-start/react) for complete client setup examples. ## OAuth errors (`redirect_uri_mismatch`, blocked consent, redirect loops) **`redirect_uri_mismatch` from Google (or another provider)** The authorized redirect URI in the provider's dashboard must match Managed Better Auth's callback route exactly: **`{NEON_AUTH_BASE_URL}/callback/{provider}`** (for example `.../callback/google`). See [Production setup](https://neon.com/docs/auth/guides/setup-oauth#production-setup). Common mistakes: - Registering only your marketing site or only the `callbackURL` from `signIn.social()`, instead of **`{NEON_AUTH_BASE_URL}/callback/{provider}`**. - Using a branch's **`NEON_AUTH_BASE_URL`** in your app while Google still lists redirect URIs for a different branch's Auth base URL. **OAuth succeeds but the user never reaches your app** Managed Better Auth only redirects to [trusted domains](https://neon.com/docs/auth/guides/configure-domains). Add every origin you use in **`callbackURL`** (including `https://www.example.com` separately if you use www). **Google consent screen shows an unexpected hostname** That hostname comes from the OAuth redirect URI (your app vs Managed Better Auth). See [Google OAuth branding](https://neon.com/docs/auth/guides/setup-oauth#google-oauth-branding). **Google says the app is in Testing / users outside test accounts cannot sign in** Add testers in Google Cloud Console or publish the OAuth consent screen for production use. See [Google OAuth branding](https://neon.com/docs/auth/guides/setup-oauth#google-oauth-branding). --- [Document source](https://neon.com/docs/cli.md) --- > Summary: Neon CLI (neon) is the terminal tool for managing Neon projects, branches, databases, roles, connection strings, functions, buckets, and the Data API without using the web console. This page indexes every command with its subcommands and documents the global options, including --output (json, yaml, table), --api-key (NEON_API_KEY), and --context-file. Built for terminal workflows, CI/CD automation, scripts, and AI agents. # Neon CLI The Neon command-line interface: every command, with options and examples Last updated: 2026-11-02 One CLI for every Neon surface: manage Postgres, Functions, Storage, the Data API, and Managed Better Auth from the terminal, with branch-scoped workflows built in. ```bash filename="Install" npm i -g neon ``` ## Get started - [Install and connect](https://neon.com/docs/cli/install): Install the Neon CLI, authenticate, and connect your first Neon project in minutes. - [Quickstart](https://neon.com/docs/cli/quickstart): Create a project, manage branches, and run your first Neon CLI commands. ## Agent mode Use Neon CLI with Claude Code, Cursor, Codex, and other AI development tools. **Note:** Every command supports `--output json` for machine-readable results, and setting the `NEON_API_KEY` environment variable authenticates non-interactively. Agents bind a directory to a project with [`neon link`](https://neon.com/docs/cli/link)'s non-interactive flags, the same ones used for CI and scripts. ## Commands reference Browse every Neon CLI command, organized by category. The CLI is invoked as `neon`. `neonctl` is an alias for `neon`, so any command works with either name. ### api Call any Neon API route directly (authenticated passthrough). Usage: `neon api [path] [options]` ### api-keys (alias: `api-key`) Manage API keys. | Subcommand | Description | | --------------------------- | ---------------------------------------------------------------------- | | `neon api-keys create` | Create an API key. The key is shown once and cannot be retrieved again | | `neon api-keys list` | List API keys for your account, or for an organization | | `neon api-keys revoke ` | Revoke an API key. Anything using it stops working immediately | ### ask Ask a question about Neon. Usage: `neon ask [options]` ### bootstrap Scaffold a new project from a Neon starter template, then install agent tooling and link a Neon project. Usage: `neon bootstrap [directory] [options]` ### branches (alias: `branch`) Manage branches. | Subcommand | Description | | ----------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------ | | `neon branches add-compute ` | Add a compute to a branch | | `neon branches create` | Create a branch | | `neon branches delete ` | Delete a branch | | `neon branches get ` | Get a branch | | `neon branches list` | List branches | | `neon branches rename ` | Rename a branch | | `neon branches reset ` | Reset a branch | | `neon branches restore [@(timestamp\|lsn)>` | Restores a branch to a specific point in time \ can be: ^self, ^parent, or \ | | `neon branches schema-diff [base-branch] [compare-source[@(timestamp\|lsn)]]` | Compare the latest schemas of any two branches, or compare a branch to its own or another branch's history. | | `neon branches set-default ` | Set a branch as default | | `neon branches set-expiration ` | Set an expiration date for the branch | ### buckets (alias: `bucket`) Manage branch object-storage buckets and their objects. | Subcommand | Description | | ------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------- | | `neon buckets create ` | Create a bucket on a branch | | `neon buckets delete ` | Delete a bucket from a branch | | `neon buckets list` | List the buckets on a branch | | `neon buckets object delete ` | Delete an object, or every object under a prefix | | `neon buckets object get ` | Download an object from a bucket to a local file | | `neon buckets object list ` | List objects in a bucket. By default folders are collapsed (like "aws s3 ls"); pass --recursive for a flat listing of every key | | `neon buckets object put ` | Upload a local file to a bucket as an object | ### checkout Pin a branch in the local context (.neon) so subsequent commands target it. Usage: `neon checkout [id|name] [options]` ### claim (alias: `claimable`) Create and claim temporary Neon projects. | Subcommand | Description | | -------------------------------- | ---------------------------------------------------------------------------------------------------- | | `neon claim accept [project-id]` | Create a claim code and open the URL where a human signs in and takes the project | | `neon claim create` | Create a temporary Neon project without an account | | `neon claim delete [project-id]` | Permanently delete an unclaimed project, or drop a local record that can no longer reach the service | | `neon claim list` | List claimable projects saved on this machine | | `neon claim status [project-id]` | Show a claimable project's lifecycle and claim status | ### config Manage a branch with a neon.ts policy. | Subcommand | Description | | --------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `neon config add ai-gateway` | Enable the AI Gateway (aiGateway: true) | | `neon config add auth` | Enable Neon Auth (auth: true) | | `neon config add bucket ` | Declare an Object Storage bucket | | `neon config add data-api` | Enable the Data API (dataApi: true) and Neon Auth, which the default provider requires. For an external identity provider, set dataApi.authProvider to "external" instead | | `neon config add function ` | Declare a Neon Function and create its handler file | | `neon config add realtime` | Enable Realtime (preview\.realtime: true) | | `neon config apply` | Apply a neon.ts policy to the branch | | `neon config init` | Scaffold a neon.ts policy and install the Neon config packages | | `neon config plan` | Show what `config apply` would change (dry run) | | `neon config status` | Show the branch's live Neon state | ### connection-string (alias: `cs`) Get connection string. Usage: `neon connection-string [branch] [options]` ### credentials (alias: `credential`) Manage branch credentials. | Subcommand | Description | | ----------------------------------- | ------------------------------------------------------------------- | | `neon credentials create` | Issue a scoped credential on the branch | | `neon credentials list` | List credentials on the branch | | `neon credentials reveal ` | Show a credential's api\_token and s3\_secret\_access\_key | | `neon credentials revoke ` | Revoke a credential | | `neon credentials rotate ` | Replace a credential's secrets in place. The token id is unchanged. | ### data-api Manage the Neon Data API for a database. | Subcommand | Description | | ------------------------------ | ----------------------------------------------------------------------- | | `neon data-api create` | Provision the Neon Data API for a database | | `neon data-api delete` | Tear down the Neon Data API for a database | | `neon data-api get` | Show the Neon Data API status and settings | | `neon data-api refresh-schema` | Refresh the Data API schema cache without changing settings | | `neon data-api update` | Update Neon Data API settings (merges with current settings by default) | ### databases (alias: `database`, `db`) Manage databases. | Subcommand | Description | | ---------------------------------- | ----------------- | | `neon databases create` | Create a database | | `neon databases delete ` | Delete a database | | `neon databases list` | List databases | ### deploy Apply a neon.ts policy to a branch (alias for `config apply`). Usage: `neon deploy [options]` ### dev Run Neon Functions locally with a dev server. Usage: `neon dev [options]` ### diff Show a git-style schema diff between the current branch and another branch. Usage: `neon diff [compare-branch] [options]` ### docs Search neon.com docs, guides, and more. | Subcommand | Description | | -------------------------- | -------------------------------------------------------------------------------------------- | | `neon docs search ` | Search neon.com: docs, API reference, PostgreSQL tutorial, guides, FAQs, changelog, and blog | ### env Manage a branch's Neon env variables locally. | Subcommand | Description | | --------------- | ---------------------------------------------------------- | | `neon env pull` | Write the branch's Neon env variables to a local .env file | ### feedback Send feedback to Neon. Usage: `neon feedback [options]` ### functions (alias: `function`) Manage Neon Functions. | Subcommand | Description | | ------------------------------------------ | ---------------------------------------------------------- | | `neon functions delete ` | Delete a function on the branch | | `neon functions deploy ` | Deploy a function from a local directory | | `neon functions domains delete ` | Delete a custom domain from the branch | | `neon functions domains list` | List custom domains on the branch | | `neon functions domains register ` | Point a domain you already own at a function on the branch | | `neon functions get ` | Show a function's details | | `neon functions list` | List functions on the branch | | `neon functions new [template]` | Create a function from a Function Registry template | | `neon functions templates list` | List function templates | ### git Sync the checked-out Neon branch to your git branch (Preview). | Subcommand | Description | | -------------------- | ------------------------------------------------------------------------------------------------------ | | `neon git cleanup` | Prune git → Neon mappings whose local git branch is gone; optionally delete the orphaned Neon branches | | `neon git install` | Install a git post-checkout hook that syncs the Neon branch on `git checkout` | | `neon git status` | Show the git context, hook state, and current git → Neon mapping | | `neon git sync` | Check out the Neon branch mapped to the current git branch (run by the hook) | | `neon git uninstall` | Remove the git post-checkout hook installed by `git install` | ### init Set up coding agents and this directory for Neon. -y is Recommended. -y with Custom flags applies those answers without prompts. Usage: `neon init [options]` ### inspect (alias: `inspection`) Inspect a branch's Postgres health and configuration. | Subcommand | Description | | -------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------- | | `neon inspect db bloat` | Estimated table/index bloat (statistical estimate, no extension needed) | | `neon inspect db calls` | Most frequently called queries (needs pg\_stat\_statements) | | `neon inspect db index-sizes` | Size of each index, largest first (pg\_relation\_size) | | `neon inspect db lfc-hit-rate` | Local File Cache hit rate (compute-wide, needs neon extension) | | `neon inspect db locks` | Locks held with the acquiring query and its age (pg\_locks + pg\_stat\_activity) | | `neon inspect db long-running-queries` | Queries running longer than 5 minutes (pg\_stat\_activity) | | `neon inspect db outliers` | Queries taking the most cumulative execution time (needs pg\_stat\_statements) | | `neon inspect db replication-slots` | Replication slots (compute-wide): kind, status, client, restart/confirmed-flush LSNs, and lag (pg\_replication\_slots + pg\_stat\_replication) | | `neon inspect db seq-scans` | Number of sequential scans recorded against each table (pg\_stat\_user\_tables) | | `neon inspect db stalled-queries` | Active queries running longer than 30 seconds with parallel workers, waits, and blockers, oldest group first (compute-wide) | | `neon inspect db subscriptions` | Per-table logical replication progress on this subscriber (pg\_subscription\_rel) | | `neon inspect db table-sizes` | Size of each table (including TOAST), largest first (pg\_table\_size) | | `neon inspect db unused-indexes` | Non-unique indexes with few scans — candidates for removal (pg\_stat\_user\_indexes) | | `neon inspect db vacuum-stats` | Autovacuum status per table: last (auto)vacuum, dead tuples, threshold | | `neon inspect db working-set` | Estimated working set vs LFC size (compute-wide, needs neon extension) | ### ip-allow Manage IP Allow. | Subcommand | Description | | ------------------------------- | ----------------------------------------- | | `neon ip-allow add [ips...]` | Add IP addresses to the IP allowlist | | `neon ip-allow list` | List the IP allowlist | | `neon ip-allow remove [ips...]` | Remove IP addresses from the IP allowlist | | `neon ip-allow reset [ips...]` | Reset the IP allowlist | ### link Link the current directory to a Neon project. Usage: `neon link [options]` ### login (alias: `auth`) Sign in with a browser. See --help for API keys and profiles. Usage: `neon login [options]` ### logs Query branch logs with structured filters, LogQL, or the Loki API. | Subcommand | Description | | -------------------------------- | -------------------------------------------------------------- | | `neon logs field-values ` | List the distinct values observed for a log field | | `neon logs fields` | List the log fields whose values can be discovered on a branch | | `neon logs loki [query]` | Call the branch's Loki read API and return its JSON response | | `neon logs query` | Query log records with structured filters or LogQL | ### mcp Install the Neon MCP server into coding agents. Usage: `neon mcp [options]` ### me Show current user. Usage: `neon me [options]` ### neon-auth Manage Neon Auth. | Subcommand | Description | | ------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------- | | `neon neon-auth config email-password get` | Get email and password config | | `neon neon-auth config email-password update` | Update email and password config | | `neon neon-auth config email-provider get` | Get email provider config | | `neon neon-auth config email-provider test` | Send a test message through the saved custom SMTP provider | | `neon neon-auth config email-provider update` | Update email provider config | | `neon neon-auth config oauth-server get` | Get OAuth server config | | `neon neon-auth config oauth-server resource add ` | Add protected resources (reads the stored list and writes back the full list; concurrent changes by others can be overwritten) | | `neon neon-auth config oauth-server resource list` | List protected resources | | `neon neon-auth config oauth-server resource remove ` | Remove protected resources (reads the stored list and writes back the full list; concurrent changes by others can be overwritten) | | `neon neon-auth config oauth-server update` | Update OAuth server config | | `neon neon-auth config organization get` | Get organization plugin config | | `neon neon-auth config organization update` | Update organization plugin config | | `neon neon-auth config webhook get` | Get webhook config | | `neon neon-auth config webhook update` | Update webhook config | | `neon neon-auth disable` | Disable Neon Auth on a branch | | `neon neon-auth domain add ` | Add a trusted domain | | `neon neon-auth domain allow-localhost disable` | Restrict localhost connections | | `neon neon-auth domain allow-localhost enable` | Allow localhost connections | | `neon neon-auth domain allow-localhost get` | Get localhost connection setting | | `neon neon-auth domain delete ` | Delete a trusted domain | | `neon neon-auth domain list` | List trusted domains | | `neon neon-auth enable` | Enable Neon Auth on a branch | | `neon neon-auth oauth-client create` | Create an OAuth client | | `neon neon-auth oauth-client delete ` | Delete an OAuth client | | `neon neon-auth oauth-client get ` | Get an OAuth client | | `neon neon-auth oauth-client list` | List OAuth clients | | `neon neon-auth oauth-client rotate-secret ` | Rotate the secret of a confidential client; the old secret stops working immediately | | `neon neon-auth oauth-client update ` | Update an OAuth client (the type cannot be changed) | | `neon neon-auth oauth-provider add` | Add an OAuth provider | | `neon neon-auth oauth-provider delete` | Delete an OAuth provider | | `neon neon-auth oauth-provider list` | List OAuth providers | | `neon neon-auth oauth-provider update` | Update an OAuth provider | | `neon neon-auth plugins get ` | Get a specific plugin configuration | | `neon neon-auth plugins list` | List all plugin configurations | | `neon neon-auth status` | Get Neon Auth status for a branch | | `neon neon-auth user create` | Create an auth user | | `neon neon-auth user delete ` | Delete an auth user | | `neon neon-auth user set-role ` | Set roles for an auth user | ### open Open the linked project in the Neon Console. Usage: `neon open [options]` ### operations (alias: `operation`) Manage operations. | Subcommand | Description | | -------------------------- | ---------------- | | `neon operations get ` | Get an operation | | `neon operations list` | List operations | ### orgs (alias: `org`) Manage organizations. | Subcommand | Description | | -------------------------------------- | -------------------------------------------------------------------------------------------------- | | `neon orgs get [id]` | Show an organization | | `neon orgs invitations create` | Invite people by email. Each one is emailed, and anyone with a Neon account joins immediately | | `neon orgs invitations list` | List invitations | | `neon orgs list` | List organizations | | `neon orgs members get ` | Show a member | | `neon orgs members list` | List members and their organization role | | `neon orgs members remove ` | Remove a member from the organization. Admin only | | `neon orgs members update ` | Change a member's organization role. Admin only | | `neon orgs spending-limit delete` | Remove the monthly spending limit. Admin only | | `neon orgs spending-limit get` | Show the monthly spending limit | | `neon orgs spending-limit set ` | Set the monthly spending limit. Neon emails at 80% and 100% and keeps computes running. Admin only | ### plugins (alias: `plugin`) Install the Neon plugin into coding agents. Usage: `neon plugins [options]` ### postgres (alias: `pg`, `lakebase`) Manage Postgres computes, databases, and roles, and connect with psql or a connection string. | Subcommand | Description | | ------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------- | | `neon postgres computes delete ` | Delete a compute | | `neon postgres computes get ` | Get a compute | | `neon postgres computes list` | List computes. Lists the branch's computes when --branch is passed or .neon pins one, otherwise every compute in the project | | `neon postgres computes restart ` | Restart a compute | | `neon postgres computes start ` | Start a compute | | `neon postgres computes suspend ` | Suspend a compute | | `neon postgres computes update ` | Update a compute's size, scale-to-zero timeout, name, or connection access | | `neon postgres connection-string [branch]` | Get connection string | | `neon postgres databases create` | Create a database | | `neon postgres databases delete ` | Delete a database | | `neon postgres databases list` | List databases | | `neon postgres psql [branch]` | Connect to a database via psql | | `neon postgres roles create` | Create a role. By default it joins neon\_superuser (admin on every database); pass --access read\_only or read\_write for a scoped role | | `neon postgres roles delete ` | Delete a role | | `neon postgres roles get ` | Get a role | | `neon postgres roles list` | List roles | | `neon postgres roles reset-password ` | Reset a role's password and print the new one | ### profile (alias: `profiles`) Manage named sets of Neon credentials. | Subcommand | Description | | -------------------------------- | ------------------------------------------------------------------------------------- | | `neon profile create ` | Create a profile. It holds either a browser sign-in or an API key, never both | | `neon profile list` | List profiles, the account each holds, and where its credentials live | | `neon profile remove ` | Revoke a profile's credential where possible, and remove it | | `neon profile rotate-key ` | Mint a fresh API key for a profile, at the same scope, and revoke the one it replaces | ### projects (alias: `project`) Manage projects. | Subcommand | Description | | ---------------------------- | ----------------------------------------------------------- | | `neon projects create` | Create a project | | `neon projects delete ` | Delete a project | | `neon projects get ` | Get a project | | `neon projects list` | List projects | | `neon projects recover ` | Recovers a deleted project during the deletion grace period | | `neon projects update ` | Update a project | ### psql Connect to a database via psql. Usage: `neon psql [branch] [options]` ### realtime Manage Neon Realtime for a branch. | Subcommand | Description | | --------------------------------- | ------------------------------------------------ | | `neon realtime disable` | Disable Realtime on a branch | | `neon realtime enable` | Enable Realtime on a branch | | `neon realtime rotate-secret` | Replace a branch's Realtime shared secret | | `neon realtime subscribe ` | Subscribe to a live SQL query with Neon Realtime | ### roles (alias: `role`) Manage roles. | Subcommand | Description | | ---------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------- | | `neon roles create` | Create a role. By default it joins neon\_superuser (admin on every database); pass --access read\_only or read\_write for a scoped role | | `neon roles delete ` | Delete a role | | `neon roles get ` | Get a role | | `neon roles list` | List roles | | `neon roles reset-password ` | Reset a role's password and print the new one | ### set-context Deprecated: use `neon link`. Set the .neon context (raw write). Usage: `neon set-context [options]` ### skills (alias: `skill`) Install Neon agent skills into coding agents. | Subcommand | Description | | -------------------- | ------------------------------------------------------ | | `neon skills status` | Check whether installed Neon skills match their source | | `neon skills update` | Update installed skills to the latest versions | ### snapshots (alias: `snapshot`) Manage snapshots. | Subcommand | Description | | ---------------------------------- | ------------------------------------------------------------------- | | `neon snapshots create` | Create a snapshot from a branch | | `neon snapshots delete ` | Delete a snapshot by id or name | | `neon snapshots finalize ` | Finalize a previewed snapshot restore (swap the restored branch in) | | `neon snapshots get ` | Get a snapshot by id or name | | `neon snapshots list` | List snapshots in the project | | `neon snapshots restore ` | Restore a snapshot into a branch | | `neon snapshots schedule get` | Get a branch's automatic snapshot schedule | | `neon snapshots schedule set` | Set a branch's automatic snapshot schedule | | `neon snapshots update ` | Update a snapshot's name or expiration | ### status Show the branch's live Neon state (alias of `config status`). Usage: `neon status [options]` ### triggers (alias: `trigger`) Manage function triggers. | Subcommand | Description | | ---------------------------- | ---------------------------------------------------------------------------------------- | | `neon triggers create` | Create a trigger that invokes a function on a cron schedule or when an object is created | | `neon triggers delete ` | Delete a trigger | | `neon triggers disable ` | Disable a trigger without deleting it | | `neon triggers enable ` | Enable a trigger | | `neon triggers get ` | Show a trigger | | `neon triggers list` | List triggers on the branch | | `neon triggers update ` | Update a trigger | ### vpc Manage VPC endpoints and project VPC restrictions. | Subcommand | Description | | -------------------------------- | ---------------------------------------------------------------------------------------------- | | `neon vpc endpoint assign ` | Add or update a VPC endpoint for this organization. Note: Azure regions are not yet supported. | | `neon vpc endpoint list` | List configured VPC endpoints for this organization. | | `neon vpc endpoint remove ` | Remove a VPC endpoint from this organization. | | `neon vpc endpoint status ` | Get the status of a VPC endpoint for this organization. | | `neon vpc project list` | List VPC endpoint restrictions for this project. | | `neon vpc project remove ` | Remove a VPC endpoint restriction from this project. | | `neon vpc project restrict ` | Configure or update a VPC endpoint restriction for this project. | ## Global options Global options are optional and work with any Neon CLI command. | Option | Description | Type | Default | Required | | ----------------- | ----------------------------------------------------------------------------------- | ------- | --------------------------------------------------------------- | :------: | | `--analytics` | Manage analytics. Example: --no-analytics, --analytics false | boolean | `true` | No | | `--api-key` | Neon API key, authenticates without `neon login` | string | `""` | No | | `--color` | Colorize the output. Example: --no-color, --color false | boolean | `true` | No | | `--config-dir` | Path to config directory | string | \~/.config/neon (or $XDG\_CONFIG\_HOME/neon) | No | | `--context-file` | Context file with default org, project, and branch IDs, created by `neon link` | string | nearest .neon file, searching upward from the current directory | No | | `--help`, `-h` | Show help for a command or subcommand | boolean | — | No | | `--output`, `-o` | Set output format Possible values: `json`, `yaml`, `table` | string | `table` | No | | `--profile` | Named credentials to use, from profiles.json (default: NEON\_PROFILE, else DEFAULT) | string | — | No | | `--version`, `-v` | Show version number | boolean | — | No | More about global options: - **Output:** table output may omit fields. Use `--output json` or `--output yaml` to see all data. - **Authentication:** the CLI checks credentials in this order: the `--api-key` option, the `NEON_API_KEY` environment variable (`export NEON_API_KEY=`), the `credentials.json` file that `neon login` creates in the config directory (override its location with `--config-dir`), then interactive web authentication. To get a key, see [Create an API key](https://neon.com/docs/manage/api-keys#creating-api-keys). - **Context file:** sets a default organization, project, or branch so you don't repeat IDs in every command. Create one with [`neon link`](https://neon.com/docs/cli/link) (preferred) or [`set-context`](https://neon.com/docs/cli/set-context). - **Analytics:** Neon collects anonymous data about which commands and options are used, plus context such as the CLI version, whether it ran in CI or a terminal, and which coding agent ran it, never user-defined data such as project IDs or command payloads. Each installation gets a random ID, stored as `anonymous_id` in the config directory, and once you sign in, your events are linked to your account. The ID isn't created in CI or when you pass `--no-analytics`. If the CLI crashes on an internal bug, it also sends an error report with the error type and a sanitized stack trace, without your arguments, environment variables, or file contents. Opt out of both with `--no-analytics`, which also asks the docs search service not to record your `neon docs search` and `neon ask` queries. - **Help:** `--help` works at every level: `neon --help`, `neon branches --help`, `neon branches create --help`. ## GitHub repository The Neon CLI is open source. See the [neondatabase/neon-pkgs](https://github.com/neondatabase/neon-pkgs/tree/main/packages/cli) repository. --- [Document source](https://neon.com/docs/cli/api-keys.md) --- > Summary: The `neon api-keys` CLI command manages API keys for your account, an organization, or a single project. Use it to create a key for scripts and CI, list existing keys and when they were last used, and revoke a key you no longer trust. # Neon CLI command: api-keys Create, list, and revoke Neon API keys Last updated: 2026-10-09 The `api-keys` command creates, lists, and revokes the API keys that authenticate requests to the Neon API. Keys belong to your account unless you pass `--org-id` or `--project-id`. A key is shown once, at creation. There is no way to retrieve it later. For key types, revocation permissions, and rotation, see [Manage API keys](https://neon.com/docs/manage/api-keys). Subcommands: [create](https://neon.com/docs/cli/api-keys#create), [list](https://neon.com/docs/cli/api-keys#list), [revoke](https://neon.com/docs/cli/api-keys#revoke) ## neon api-keys list Lists key metadata, never the keys themselves. ```bash neon api-keys list [options] ``` | Option | Description | Type | Default | Required | | ---------- | ------------------------------------------------------ | ------ | ------- | :------: | | `--org-id` | List the organization's keys instead of your account's | string | — | No | List your account keys: ```bash neon api-keys list ``` ```text filename="Output" Account API keys ID Name Created At Last Used At Last Used From Addr 3225782 ci-deploy 2026-07-29T00:50:26Z 2026-07-29T18:06:55Z 192.0.2.10 ``` Organization keys are invisible to your account, so listing them needs `--org-id`: ```bash neon api-keys list --org-id org-example-12345678 ``` This covers both scopes, since a project-scoped key is owned by the project's organization. The `Project` column tells them apart: ```text filename="Output" API keys in org-example-12345678 ID Name Project Created At Last Used At Last Used From Addr 3243240 preview-bot green-breeze-12345678 2026-08-04T18:51:36Z 2026-08-05T18:51:36Z 192.0.2.10 3177950 org-key (all projects) 2026-07-08T01:28:49Z 2026-07-08T01:31:20Z 192.0.2.10 ``` `(all projects)` is a table label only. In JSON and YAML the field is `project_id`, and it is `null` for an organization-wide key: ```bash neon api-keys list --org-id org-example-12345678 -o json ``` ```json [ { "id": 3243240, "name": "preview-bot", "project_id": "green-breeze-12345678" }, { "id": 3177950, "name": "org-key", "project_id": null } ] ``` ## neon api-keys create Creates a key and prints it once. `--name` is required. By default the key reaches everything your account can, in every organization. Two mutually exclusive flags change that: - `--project-id` limits the key to one project. Use this for anything deployed, so a leaked key cannot reach your other projects. - `--org-id` transfers ownership to an organization. This is not a restriction: the key reaches every project in that organization, including ones created later. Both organization forms need organization admin permissions. Each form prints a notice describing what the key can reach. ```bash neon api-keys create [options] ``` | Option | Description | Type | Default | Required | | -------------- | ---------------------------------------------------------------------------------------------- | ------ | ------- | :------: | | `--name` | A name to identify the key later | string | — | Yes | | `--org-id` | Create a key for this organization instead of your account | string | — | No | | `--project-id` | Create a key that can access only this project. Its organization is looked up from the project | string | — | No | Create an account key: ```bash neon api-keys create --name ci-deploy ``` ```text filename="Output" API key ID 3225782 Name ci-deploy napi_examplekey1234567890abcdefghijklmnopqrstuvwxyz WARNING: Store this key now: it is not shown again. WARNING: This key reaches everything your account can, in every organization. Pass --org-id or --project-id to narrow it. ``` Create a key owned by an organization: ```bash neon api-keys create --name org-key --org-id org-example-12345678 ``` ```text filename="Output" API key ID 3177950 Name org-key napi_examplekey1234567890abcdefghijklmnopqrstuvwxyz WARNING: Store this key now: it is not shown again. WARNING: This key reaches every project in org-example-12345678, including ones created later. Pass --project-id instead to restrict it to one. ``` Create a key limited to one project. The output adds a `Project` column: ```bash neon api-keys create --name preview-bot --project-id green-breeze-12345678 ``` ```text filename="Output" API key ID 3243240 Name preview-bot Project green-breeze-12345678 napi_examplekey1234567890abcdefghijklmnopqrstuvwxyz WARNING: Store this key now: it is not shown again. Limited to green-breeze-12345678: it cannot create projects, mint API keys, or read any other project. It can still change and delete everything inside that project. ``` **Important:** A project-scoped key is owned by the project's organization, so it needs `--org-id` to list or revoke. The key is the last line of stdout, and the notices go to stderr, so you can capture it directly: ```bash echo "NEON_API_KEY=$(neon api-keys create --name local-dev -o json | jq -r .key)" >> .env ``` ## neon api-keys revoke Revokes a key immediately and permanently. Anything using it starts failing, so confirm the ID with `api-keys list` first. Takes the numeric key ID, not the name. Organization and project-scoped keys need organization admin permissions. See [who can revoke keys](https://neon.com/docs/manage/api-keys#who-can-revoke-keys). ```bash neon api-keys revoke [options] ``` | Option | Description | Type | Default | Required | | ---------- | ---------------------------------------------------- | ------ | ------- | :------: | | `--org-id` | Revoke an organization key instead of an account key | string | — | No | Revoke an account key: ```bash neon api-keys revoke 3225782 ``` ```text filename="Output" API key ID 3225782 Name ci-deploy Revoked true Last Used At 2026-07-29T18:06:55Z ``` `Last Used At` is empty for a key that was never used. Revoke an organization or project-scoped key: ```bash neon api-keys revoke 3243240 --org-id org-example-12345678 ``` Without `--org-id`, the same command fails: ```text filename="Output" ERROR: No account API key with id 3243240. If it belongs to an organization, pass --org-id. Organization keys are not visible to your account. ``` --- [Document source](https://neon.com/docs/cli/api.md) --- > Summary: The Neon CLI `api` command sends an authenticated request to any Neon API route and prints the response. Pass a path like `/projects`, set the method with `--method`, build a body from `--field` or `--data`, and add query parameters and headers. Run `neon api --list` to browse every endpoint. # Neon CLI command: api Call any Neon API route directly as an authenticated passthrough Last updated: 2026-09-18 The `api` command sends an authenticated request to any [Neon API](https://neon.com/docs/reference/api) route and prints the response. Pass an API path as the first argument. The method defaults to `GET`, or `POST` when you supply a body. By default the request uses your [`neon login`](https://neon.com/docs/cli/login) credentials. To use a specific key, pass `--api-key` or set `NEON_API_KEY`. The [key's permissions](https://neon.com/docs/manage/api-keys#types-of-api-keys) determine what the request can do. **Note:** `api` is a raw passthrough: it does not read your [context file](https://neon.com/docs/cli/link) or auto-fill parameters. Pass what each route needs explicitly. For example, `neon api /projects` returns `ERROR: org_id is required` unless you add `-Q org_id=` or authenticate with an organization API key. Get your organization ID from [`neon orgs list`](https://neon.com/docs/cli/orgs). ## Usage ```bash neon api [options] ``` ## Options | Option | Description | Type | Default | Required | | ------------------- | ------------------------------------------------------------------------------------------------------------------------------------------ | ------- | ------- | :------: | | `--data`, `-d` | Raw request body: a JSON string, @file, or - for stdin. Overrides --field. | string | — | No | | `--describe` | Print path, query, and body fields from the OpenAPI spec without calling the API. Body names are dotted for -F. | boolean | `false` | No | | `--field`, `-F` | Body field key=value (repeatable). Dot-notation nests objects (e.g. -F branch.name=dev); values are typed (numbers, booleans, null, JSON). | array | — | No | | `--header`, `-H` | Extra request header key:value (repeatable). | array | — | No | | `--include`, `-i` | Print the response status and headers before the body. | boolean | `false` | No | | `--list` | List available API endpoints from the OpenAPI spec. | boolean | `false` | No | | `--method`, `-X` | HTTP method (GET, POST, PUT, PATCH, DELETE). Defaults to GET, or POST when a body is provided. | string | — | No | | `--query`, `-Q` | Query parameter key=value (repeatable). | array | — | No | | `--raw-field`, `-f` | Body field key=value with the value kept as a raw string. | array | — | No | | `--refresh` | Refresh the cached OpenAPI spec (used with --list and --describe). | boolean | `false` | No | ## Examples ### GET request Pass required parameters with `--query` (`-Q`); add `--include` (`-i`) to print the status and headers before the body: ```bash neon api /projects -Q org_id=org-cool-darkness-12345678 -i ``` The response is the route's raw JSON. For the fields each route returns, see the [Neon API Reference](https://neon.com/docs/reference/api). ### Request body Set body fields with `--field` (`-F`) as `key=value`. Values are typed automatically (numbers, booleans, `null`, and JSON), and dot-notation nests objects. A body switches the default method to `POST`: ```bash neon api /projects/{project_id}/branches -F branch.name=dev ``` This sends `{ "branch": { "name": "dev" } }`. Use `--raw-field` (`-f`) to keep a value as a literal string. For a full JSON body, use `--data` (`-d`) with a string, `@file`, or `-` (stdin). ### Create a project `POST /projects` takes a `project` object. To create it under an organization, set `project.org_id` in the body (unlike `GET /projects`, which takes `org_id` as a query parameter): ```bash neon api /projects -X POST -F project.name=my-project -F project.org_id=org-cool-darkness-12345678 ``` For a larger body, put the JSON in a file and pass it with `-d @`: ```json filename="project.json" { "project": { "name": "my-project", "org_id": "org-cool-darkness-12345678" } } ``` ```bash neon api /projects -X POST -d @project.json ``` ### List endpoints `--list` prints every route from the Neon OpenAPI spec; `--refresh` refetches the cached spec: ```bash neon api --list ``` ### YAML output Responses print as JSON. Use the global `--output yaml` (`-o yaml`) for YAML: ```bash neon api /projects -Q org_id=org-cool-darkness-12345678 -o yaml ``` --- [Document source](https://neon.com/docs/cli/ask.md) --- > Summary: The Neon CLI `ask` command sends a question to the Neon assistant and prints the answer in your terminal. It answers from Neon's documentation and needs no login; use `--output json` for machine-readable output when scripting or calling it from an agent. # Neon CLI command: ask Ask the Neon assistant a question from the terminal Last updated: 2026-11-01 The `ask` command sends a question to the Neon assistant and prints the answer to your terminal: `neon ask --prompt ""`. The assistant answers from Neon's documentation, so keep questions scoped to Neon and Lakebase Postgres rather than general chat. No login is required, and it doesn't touch your projects or account. To find docs pages on a topic, use [`neon docs search`](https://neon.com/docs/cli/docs). To send feedback to the Neon team instead, use [`neon feedback`](https://neon.com/docs/cli/feedback). The answer is natural-language text, not structured data. By default it streams as markdown, use `--output json` to get the answer back as a single `text` field you can parse. ## Usage ```bash neon ask --prompt ``` Pass your question with `--prompt`. It's the only required option. ## Options | Option | Description | Type | Default | Required | | ---------- | ------------------- | ------ | ------- | :------: | | `--prompt` | The question to ask | string | — | Yes | `--output json` and `--output yaml` both return the full answer at once as a single `text` field, instead of streaming markdown. ## Examples Ask a question: ```bash neon ask --prompt "How do schema-only branches work?" ``` Get the answer as JSON so you can process it in a script: ```bash neon ask --prompt "What is a Neon project?" --output json ``` --- [Document source](https://neon.com/docs/cli/bootstrap.md) --- > Summary: Covers the usage of the `bootstrap` command in the Neon CLI to scaffold a new application from a Neon starter template, including the interactive template picker, the `--default` quick start, and post-scaffold setup steps (dependency install, git init, agent tooling, and project linking). # Neon CLI command: bootstrap Scaffold a new project from a Neon starter template Last updated: 2026-11-05 The `bootstrap` command scaffolds a new application from a Neon starter template. By default it runs interactively: it prompts you to pick a template, scaffolds it into the target directory, then offers the usual setup steps (install dependencies, initialize git, install agent tooling, and link the directory to a Neon project). To add a single function to an existing project from a template, use a [Function Registry template](https://neon.com/functions/templates) and [`neon functions new`](https://neon.com/docs/cli/functions#new) instead. ## Usage ```bash neon bootstrap [directory] [options] ``` The directory argument is optional. Use `.` to scaffold into the current directory, or leave it out and bootstrap prompts you for one. The target directory must be empty unless you pass `--force`. ## Options | Option | Description | Type | Default | Required | | ------------------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------- | ------- | :------: | | `--agent`, `-a` | Coding agent to install into (repeatable). Forwarded to plugins, or to skills and mcp. Skips agent selection. Values listed below | array | — | No | | `--agent-setup` | After scaffolding, install the Neon plugin or skills and MCP. Use --no-agent-setup to skip | boolean | `true` | No | | `--default`, `-y` | Quick start: scaffold the default template (or --template), then install, git, agent tooling (project folders, else the host CLI agent; if none, pass --agent or omit --default in a terminal), and link with defaults. If several organizations or projects exist, link prints IDs and exits | boolean | `false` | No | | `--deploy` | Run `neon deploy` once dependencies are installed and the project is linked, without asking. Fails if neon.ts reads an env var that is not set yet | boolean | `false` | No | | `--force` | Scaffold into the target directory even if it is not empty (colliding files are overwritten). | boolean | `false` | No | | `--git` | Initialize a git repository after scaffolding. In interactive mode this is offered as a prompt; use --no-git to skip without being asked. | boolean | `true` | No | | `--install` | Install dependencies after scaffolding. In interactive mode this is offered as a prompt; use --no-install to skip without being asked. | boolean | `true` | No | | `--link` | Link a Neon project after scaffolding. Templates with neon.ts link after install so env pull works; otherwise linking happens before install. In interactive mode this is offered as a prompt; use --no-link to skip without being asked. | boolean | `true` | No | | `--list-templates`, `--list`, `--ls` | List available templates and exit. --output json and --output yaml print a machine-readable catalog. | boolean | `false` | No | | `--template` | Template to use (skips the interactive picker). Run with --list-templates to see available templates. | string | — | No | Run with `--list-templates` to see the available templates (add `--output json` for a machine-readable catalog), and pass one with `--template` to skip the interactive picker. The post-scaffold steps all default to on. In interactive mode, bootstrap asks about each one; pass the negated flag to skip it without being asked: - `--install` / `--no-install`: install dependencies. - `--git` / `--no-git`: initialize a git repository. - `--agent-setup` / `--no-agent-setup`: install agent tooling, either the Neon plugin, or agent skills and the MCP server. Pass `--agent` (alias `-a`, repeatable) to name the agents and skip the picker, for example `neon bootstrap my-app --agent cursor`. - `--link` / `--no-link`: run [`neon link`](https://neon.com/docs/cli/link) in the scaffolded directory. Use `--default` (alias `-y`) for a quick start: it scaffolds the default template (or the one you pass with `--template`), then runs git init, agent tooling, dependency install, and `neon link --yes` without prompting. `link --yes` picks your only organization and project and writes a `.neon` context file. If you have several, the other steps still finish, then the command lists the IDs and exits with an error. Bootstrap doesn't accept `--org-id` or `--project-id`, so link from the new directory: ```bash neon link --yes --org-id --project-id ``` Outside an interactive terminal (no TTY, or in CI), bootstrap only scaffolds the template. It skips every post-scaffold step, even one you pass explicitly like `--install`, and its summary lists the commands to run next. Use `--default` to run the steps unattended. When the template has a [`neon.ts`](https://neon.com/docs/reference/neon-ts), bootstrap can also deploy it once dependencies are installed and the project is linked. It checks the environment variables your functions read against the env file that `neon link` pulled (`.env` if the directory has one, otherwise `.env.local`). If they're all set, bootstrap asks in an interactive terminal whether to deploy now and runs [`neon deploy --env `](https://neon.com/docs/cli/deploy) with that file. With `--default`, it skips the question and lists that command under `Next:`. If any are unset, `Next:` names them. Pass `--deploy` to install, link, and deploy without asking. It fails with `neon deploy`'s error if an environment variable is unset. `--deploy` can't be combined with `--no-install` or `--no-link`, and needs `--default` outside an interactive terminal: ```bash neon bootstrap my-app --template hono --default --deploy ``` ## Examples Create `./my-app` from an interactively chosen template: ```bash neon bootstrap my-app ``` When the steps finish, bootstrap prints a summary. This run linked a project and skipped agent tooling: ```text Project scaffolded. ------------------- Template REST API Directory my-app Dependencies installed with npm Git initialized Agents skipped Project linked Next: cd my-app See the README to run it. ``` Scaffold a specific template into the current directory: ```bash neon bootstrap . --template hono ``` Scaffold the [Realtime](https://neon.com/docs/realtime/overview) React starter, a todo app with live queries and optimistic updates. Its `neon.ts` declares Realtime, so run `neon deploy` in the new directory to enable it: ```bash neon bootstrap my-app --template realtime-react ``` Quick start: scaffold the default template and run setup without prompting: ```bash neon bootstrap my-app --default ``` List the template catalog as JSON, for scripting or driving `bootstrap` from an agent. Each entry's `id` is what you pass to `--template`: ```bash neon bootstrap --list-templates --output json ``` The command prints an array of template objects, each shaped like: ```json { "id": "hono", "title": "REST API", "description": "A Hono REST API on Neon Functions, backed by Lakebase Postgres via Drizzle.", "services": ["Postgres", "Functions"] } ``` --- [Document source](https://neon.com/docs/cli/branches.md) --- > Summary: The Neon CLI `branches` command provides subcommands (list, create, reset, restore, rename, schema-diff, set-default, set-expiration, add-compute, delete, get) to manage Neon project branches from the terminal. Use this reference when you need exact flags and syntax for branch operations: point-in-time restore via RFC 3339 timestamp or LSN, schema diff between any two branches or historical states, expiration timestamps, or adding read replica computes. # Neon CLI command: branches List, create, rename, and delete branches; set default; run schema diff Last updated: 2026-10-09 The `branches` command lists, creates, renames, deletes, and retrieves details about branches in your Neon project. It also sets the default branch, adds a compute or [read replica](https://neon.com/docs/introduction/read-replicas) to a branch, restores a branch to an earlier point in time, and runs a [schema diff](https://neon.com/docs/guides/schema-diff) between branches. For information about branches in Neon, see [Manage branches](https://neon.com/docs/manage/branches). If `--project-id` is omitted, the CLI resolves it from your [context file](https://neon.com/docs/cli/link), auto-selects when your account has only one project, and otherwise asks you to pass `--project-id`. **Tip: Switch the active branch** To pin a branch in your local `.neon` context file so subsequent commands target it, use [`neon checkout`](https://neon.com/docs/cli/checkout). Subcommands: [add-compute](https://neon.com/docs/cli/branches#add-compute), [create](https://neon.com/docs/cli/branches#create), [delete](https://neon.com/docs/cli/branches#delete), [get](https://neon.com/docs/cli/branches#get), [list](https://neon.com/docs/cli/branches#list), [rename](https://neon.com/docs/cli/branches#rename), [reset](https://neon.com/docs/cli/branches#reset), [restore](https://neon.com/docs/cli/branches#restore), [schema-diff](https://neon.com/docs/cli/branches#schema-diff), [set-default](https://neon.com/docs/cli/branches#set-default), [set-expiration](https://neon.com/docs/cli/branches#set-expiration) ## neon branches list Lists branches in a Neon project. ```bash neon branches list [options] ``` | Option | Description | Type | Default | Required | | -------------- | ----------- | ------ | ------- | :------: | | `--project-id` | Project ID | string | — | No | List branches with the default `table` output format: ```bash neon branches list --project-id solitary-leaf-288182 ``` ```text filename="Output" Name ID Current State Expires At Created At [default] production br-wispy-cloud-123456 ready never 2026-09-30T13:15:12Z [current] development br-cool-forest-123456 ready never 2026-09-30T14:45:50Z ``` Branch names include text labels that indicate status: `[default]` marks the project's default branch, `[protected]` marks a protected branch, `[anon]` marks an anonymized branch, and `[current]` marks the branch pinned in your local `.neon` context file. List branches with `--output json`, which returns more information than the `table` format: ```bash neon branches list --project-id solitary-leaf-288182 --output json ```
Show output ```json [ { "id": "br-wild-boat-123456", "project_id": "solitary-leaf-288182", "name": "production", "current_state": "ready", "logical_size": 29515776, "creation_source": "console", "default": true, "cpu_used_sec": 78, "compute_time_seconds": 78, "active_time_seconds": 312, "written_data_bytes": 107816, "data_transfer_bytes": 0, "created_at": "2026-07-09T17:01:34Z", "updated_at": "2026-07-09T17:15:13Z" }, { "id": "br-shy-cake-123456", "project_id": "solitary-leaf-288182", "parent_id": "br-wild-boat-123456", "parent_lsn": "0/1E88838", "name": "development", "current_state": "ready", "creation_source": "console", "default": false, "cpu_used_sec": 0, "compute_time_seconds": 0, "active_time_seconds": 0, "written_data_bytes": 0, "data_transfer_bytes": 0, "created_at": "2026-07-09T17:37:10Z", "updated_at": "2026-07-09T17:37:10Z" } ] ```
## neon branches create Creates a branch in a Neon project. ```bash neon branches create [options] ``` | Option | Description | Type | Default | Required | | ------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ------- | --------------- | :------: | | `--compute` | Create a branch with or without a compute. By default branch is created with a read-write compute. To create a branch without compute use --no-compute | boolean | `true` | No | | `--cu` | The number of Compute Units. Could be a fixed size (e.g. "2") or a range delimited by a dash (e.g. "0.5-3"). | string | project default | No | | `--expires-at` | Set an expiration date for the branch. Accepts a date string (e.g., 2024-12-31T23:59:59Z). | string | never expires | No | | `--name` | The branch name | string | branch id | No | | `--parent` | Parent branch name or id or timestamp or LSN. Defaults to the default branch | string | — | No | | `--protected` | Whether the branch is protected. Protected branches (and their computes) cannot be deleted, archived, or reset, and block deletion of the project. Can be gated by `protected_branches_only` in the IP allowlist. Paid plans only. | boolean | — | No | | `--psql` | Connect to a new branch via psql | boolean | `false` | No | | `--schema-only` | Create a schema-only branch. Requires exactly one read-write compute. | boolean | `false` | No | | `--secrets` | Include connection credentials in command output. Use --no-secrets to omit them | boolean | `true` | No | | `--suspend-timeout` | Duration of inactivity in seconds after which the compute endpoint is automatically suspended. The value `0` means use the global default. The value `-1` means never suspend. The default value is `300` seconds (5 minutes). The maximum value is `604800` seconds (1 week). | number | `0` | No | | `--type` | Type of compute to add | string | `read_write` | No | | `--project-id` | Project ID | string | — | No | The `--name` value must be unique within the project and can be up to 256 characters; see [Branch naming requirements](https://neon.com/docs/manage/branches#branch-naming-requirements). A `read_only` compute is a [read replica](https://neon.com/docs/introduction/read-replicas). **Note:** When creating a branch from a protected parent branch, role passwords on the child branch are changed. For more information about this Protected Branches feature, see [New passwords generated for Postgres roles on child branches](https://neon.com/docs/guides/protected-branches#new-passwords-generated-for-postgres-roles-on-child-branches). ```bash neon branches create ``` ```text filename="Output" Branch Name br-mute-sunset-123456 ID br-mute-sunset-123456 Current State ready Created At 2026-09-30T20:07:27Z Compute ID Created At ep-floral-violet-123456 2026-09-30T20:07:27Z Connection string Connection URI postgresql://[user]:[password]@[neon_hostname]/[dbname] ``` **Note:** If the parent branch has more than one role or database, the `branches create` command does not output a connection URI. As an alternative, you can use the `connection-string` command to retrieve the connection URI for a branch. This command includes options for specifying the role and database. See [the connection-string command](https://neon.com/docs/cli/connection-string). Omit the connection string from the output, keeping it out of terminal scrollback and CI logs: ```bash neon branches create --no-secrets ``` Needs Neon CLI 4.9.0+; older versions ignore `--no-secrets` and still print the connection string. Create a branch with `--output json`, which returns the full branch response data: ```bash neon branches create --output json ```
Show output ```json { "branch": { "id": "br-frosty-art-123456", "project_id": "polished-shape-60485499", "parent_id": "br-polished-fire-123456", "parent_lsn": "0/1E887C8", "name": "br-frosty-art-123456", "current_state": "init", "pending_state": "ready", "creation_source": "neon", "default": false, "cpu_used_sec": 0, "compute_time_seconds": 0, "active_time_seconds": 0, "written_data_bytes": 0, "data_transfer_bytes": 0, "created_at": "2026-08-03T20:12:24Z", "updated_at": "2026-08-03T20:12:24Z" }, "endpoints": [ { "host": "ep-cool-darkness-123456.us-east-2.aws.neon.tech", "id": "ep-cool-darkness-123456", "project_id": "polished-shape-60485499", "branch_id": "br-frosty-art-123456", "autoscaling_limit_min_cu": 1, "autoscaling_limit_max_cu": 1, "region_id": "aws-us-east-2", "type": "read_write", "current_state": "init", "pending_state": "active", "settings": {}, "pooler_enabled": false, "pooler_mode": "transaction", "disabled": false, "passwordless_access": true, "creation_source": "neon", "created_at": "2026-08-03T20:12:24Z", "updated_at": "2026-08-03T20:12:24Z", "proxy_host": "us-east-2.aws.neon.tech", "suspend_timeout_seconds": 0, "provisioner": "k8s-pod" } ], "connection_uris": [ { "connection_uri": "postgresql://alex:AbC123dEf@ep-cool-darkness-123456.us-east-2.aws.neon.tech/dbname?sslmode=require&channel_binding=require", "connection_parameters": { "database": "dbname", "password": "AbC123dEf", "role": "alex", "host": "ep-cool-darkness-123456.us-east-2.aws.neon.tech", "pooler_host": "ep-cool-darkness-123456-pooler.us-east-2.aws.neon.tech" } } ] } ```
Create a branch with a user-defined name: ```bash neon branches create --name feature/user-auth ``` Set the compute size when creating a branch: ```bash neon branches create --name mybranch --cu 2 ``` Set the compute's autoscaling range when creating a branch: ```bash neon branches create --name mybranch --cu 0.5-3 ``` Create a branch with a read replica compute: ```bash neon branches create --name my_read_replica_branch --type read_only ``` Create a branch from a parent branch other than your `main` branch: ```bash neon branches create --name feature/payment-api --parent development ``` Create an instant restore branch by specifying the `--parent` option with a timestamp: ```bash neon branches create --name data_recovery --parent 2023-07-11T10:00:00Z ``` The timestamp must be in RFC 3339 format (this [timestamp converter](https://it-tools.tech/date-converter) can help). For more about instant restore, see [Instant restore](https://neon.com/docs/guides/branch-restore). Create a branch and connect to it with `psql` immediately. Arguments after `--` are passed through to psql, so you can run an `.sql` file or a query on creation: ```bash neon branches create --psql neon branches create --psql -- -f dump.sql neon branches create --psql -- -c "SELECT version()" ``` Create a schema-only branch: ```bash neon branches create --schema-only ``` Create a [protected branch](https://neon.com/docs/guides/protected-branches): ```bash neon branches create --name production --protected ``` ## neon branches reset Resets a child branch to the latest data from its parent. The `` is the branch ID or branch name; either works. ```bash neon branches reset [options] ``` | Option | Description | Type | Default | Required | | ----------------------- | ------------------------------------------- | ------- | ------- | :------: | | `--parent` | Reset to a parent branch | boolean | `false` | No | | `--preserve-under-name` | Name under which to preserve the old branch | | — | No | | `--project-id` | Project ID | string | — | No | The `--parent` option is required; resetting from the parent branch is currently the only supported reset operation. To rewind a branch to an earlier point in time, see [restore](https://neon.com/docs/cli/branches#restore). ```bash neon branches reset development --parent ``` ```text filename="Output" Name development ID br-cool-forest-123456 Current State ready Created At 2026-09-30T14:45:50Z Last Reset At 2026-09-30T15:36:32Z ``` ## neon branches restore Restores a branch to a specified point in time in its own or another branch's history. The `` is the ID or name of the branch you want to restore, and `` is the source branch you want to restore from. Source options are: - `^self`: restores the selected branch to an earlier point in its own history. You must specify a timestamp or LSN (restoring to head is not supported). - `^parent`: restores the target branch to its parent. By default the target is restored to the latest (head) of its parent. Append `@timestamp` or `@lsn` to restore to an earlier point in the parent's history. - A source branch ID or name: restores the target branch to the selected source branch. It restores the latest (head) by default. Append `@timestamp` or `@lsn` to restore to an earlier point in the source branch's history. ```bash neon branches restore [@(timestamp|lsn)] ``` | Option | Description | Type | Default | Required | | ----------------------- | ------------------------------------------- | ------ | ------- | :------: | | `--preserve-under-name` | Name under which to preserve the old branch | | — | No | | `--project-id` | Project ID | string | — | No | The `--preserve-under-name` option is required when restoring to `^self`. Restore `main` to an earlier point in its own history, saving the previous state to a backup branch named `main_restore_backup_2026-09-29`: ```bash neon branches restore main ^self@2026-09-29T10:00:00.000Z --preserve-under-name main_restore_backup_2026-09-29 ``` ```text filename="Output" Restoring main to main at timestamp 2026-09-29T10:00:00.000Z Restored branch ID br-purple-dust-123456 Name main Last Reset At 2026-09-30T09:45:21Z Backup branch ID br-flat-forest-123456 Name main_restore_backup_2026-09-29 ``` Restore the target branch `feature/user-auth` to the head of the source branch `main`: ```bash neon branches restore feature/user-auth main ``` ```text filename="Output" Restoring feature/user-auth to the head of main Restored branch ID br-restless-frost-123456 Name feature/user-auth Last Reset At 2026-09-30T15:42:34Z ``` Restore `feature/user-auth` to an earlier point in time from its parent branch: ```bash neon branches restore feature/user-auth ^parent@2026-09-29T10:30:00.000Z ``` ```text filename="Output" Restoring feature/user-auth to main at timestamp 2026-09-29T10:30:00.000Z Restored branch ID br-restless-frost-123456 Name feature/user-auth Last Reset At 2026-09-30T15:55:04Z ``` ## neon branches rename Renames a branch. ```bash neon branches rename [options] ``` | Option | Description | Type | Default | Required | | -------------- | ----------- | ------ | ------- | :------: | | `--project-id` | Project ID | string | — | No | The new name follows the same rules as `--name` on [branches create](https://neon.com/docs/cli/branches#create); see [Branch naming requirements](https://neon.com/docs/manage/branches#branch-naming-requirements). ```bash neon branches rename mybranch teambranch ``` ```text filename="Output" Name teambranch ID br-rough-sound-123456 Current State ready Created At 2026-09-30T20:46:58Z ``` ## neon branches schema-diff Compares the latest schemas of any two branches, or compares against a specific point in a branch's own or another branch's history. For a git-style shortcut that defaults to comparing a branch against its parent, see [`neon diff`](https://neon.com/docs/cli/diff). The `[base-branch]` is the branch to compare against. It's optional; if omitted, the command uses the branch from your `set-context` file, or the project's default branch if no context is configured. The `[compare-source]` specifies the branch or state to compare against. Options are: - `^self`: compares the selected branch to an earlier point in its own history. You must specify a timestamp or LSN. - `^parent`: compares the selected branch to the head of its parent branch. You can append `@timestamp` or `@lsn` to compare to an earlier point in the parent's history. - A branch ID or name: compares the selected branch to the head of another specified branch. Append `@timestamp` or `@lsn` to compare to an earlier point in the specified branch's history. ```bash neon branches schema-diff [base-branch] [compare-source[@(timestamp|lsn)]] [options] ``` | Option | Description | Type | Default | Required | | -------------------- | ----------------------------------------------------------------- | ------ | ------- | :------: | | `--database`, `--db` | Name of the database for which the schema comparison is performed | string | — | No | | `--project-id` | Project ID | string | — | No | **Note:** Use the `--no-color` or `--color false` [global option](https://neon.com/docs/cli#global-options) to decolorize command output in CI/CD pipelines. Compare the schema of the `production` branch to the head of the `development` branch: ```bash neon branches schema-diff production development ``` The output indicates that in the table `public.playing_with_neon`, a new column `description character varying(255)` has been added in the `development` branch that is not present in the `production` branch. ```text filename="Output" --- Database: neondb (Branch: br-wandering-firefly-a50un462) +++ Database: neondb (Branch: br-fancy-sky-a5cydw8p) @@ -26,9 +26,10 @@ CREATE TABLE public.playing_with_neon ( id integer NOT NULL, name text NOT NULL, - value real + value real, + description character varying(255) ); ``` Compare the schema of `feature/user-auth` to an earlier point in its own history at LSN `0/123456`: ```bash neon branches schema-diff feature/user-auth ^self@0/123456 ``` Compare the schema of `feature/user-auth` to the head of its parent branch: ```bash neon branches schema-diff feature/user-auth ^parent ``` Compare the schema of the `production` branch to the state of `feature/payment-api` at timestamp `2024-06-01T00:00:00.000Z`: ```bash neon branches schema-diff production feature/payment-api@2024-06-01T00:00:00.000Z ``` ## neon branches set-default Sets a branch as the default branch in your Neon project. ```bash neon branches set-default [options] ``` | Option | Description | Type | Default | Required | | -------------- | ----------- | ------ | ------- | :------: | | `--project-id` | Project ID | string | — | No | ```bash neon branches set-default mybranch ``` ```text filename="Output" Name [default] mybranch ID br-odd-frog-123456 Current State ready Created At 2026-09-30T12:22:12Z ``` ## neon branches set-expiration Sets or updates the expiration date for a branch. When the expiration time is reached, the branch and its compute endpoints are permanently deleted. ```bash neon branches set-expiration [options] ``` | Option | Description | Type | Default | Required | | -------------- | --------------------------------------------------------------------------------------------------------------------- | ------ | ------- | :------: | | `--expires-at` | Set a expiration date for the branch. If omitted, expiration will be removed. Format \[RFC3339]: 2024-12-31T23:59:59Z | string | — | No | | `--project-id` | Project ID | string | — | No | Set an expiration date for a branch: ```bash neon branches set-expiration mybranch --expires-at 2025-08-15T18:00:00Z ``` Remove expiration from a branch (omit the parameter): ```bash neon branches set-expiration mybranch ``` ## neon branches add-compute Adds a compute to an existing branch in your Neon project. ```bash neon branches add-compute [options] ``` | Option | Description | Type | Default | Required | | -------------- | ------------------------------------------------------------------------------------------------------------ | ------ | ----------- | :------: | | `--cu` | The number of Compute Units. Could be a fixed size (e.g. "2") or a range delimited by a dash (e.g. "0.5-3"). | string | — | No | | `--name` | Optional name of the compute | string | — | No | | `--type` | Type of compute to add | string | `read_only` | No | | `--project-id` | Project ID | string | — | No | A `read_only` compute is a [read replica](https://neon.com/docs/introduction/read-replicas). A branch can have a single primary read-write compute and multiple read replica computes. Add a read replica compute to a branch: ```bash neon branches add-compute mybranch --type read_only ``` ```text filename="Output" ID ep-rough-lab-123456 Host ep-rough-lab-123456.us-east-2.aws.neon.tech ``` Set the compute size when adding a compute to a branch: ```bash neon branches add-compute main --cu 2 ``` Set the compute's autoscaling range when adding a compute to a branch: ```bash neon branches add-compute main --cu 0.5-3 ``` ## neon branches delete Deletes a branch in a Neon project. ```bash neon branches delete [options] ``` | Option | Description | Type | Default | Required | | -------------- | ----------- | ------ | ------- | :------: | | `--project-id` | Project ID | string | — | No | ```bash neon branches delete br-rough-sky-123456 ``` ```text filename="Output" Name my_child_branch ID br-rough-sky-123456 Current State ready Created At 2026-09-30T20:57:39Z ``` ## neon branches get Retrieves details about a branch. ```bash neon branches get [options] ``` | Option | Description | Type | Default | Required | | -------------- | ----------- | ------ | ------- | :------: | | `--project-id` | Project ID | string | — | No | Get a branch with the default `table` output format: ```bash neon branches get production ``` ```text filename="Output" Name [default] production ID br-wispy-cloud-123456 Current State ready Created At 2026-09-30T13:15:12Z Logical Size 30.6 MiB ``` Get a branch with the `--output` format option set to `json`: ```bash neon branches get production --output json ```
Show output ```json { "id": "br-lingering-bread-123456", "project_id": "noisy-rain-039137", "name": "production", "current_state": "ready", "logical_size": 29769728, "creation_source": "console", "default": false, "cpu_used_sec": 522, "compute_time_seconds": 522, "active_time_seconds": 2088, "written_data_bytes": 174433, "data_transfer_bytes": 20715, "created_at": "2026-06-28T10:17:28Z", "updated_at": "2026-07-11T12:22:59Z" } ```
--- [Document source](https://neon.com/docs/cli/buckets.md) --- > Summary: The Neon CLI `neon buckets` command manages branch object-storage buckets and their contents: create, list, and delete buckets, and use the `neon buckets object` subcommands to list, download, upload, and delete objects. Object listing supports prefixes, a --delimiter to collapse keys into folders, and cursor-based pagination; `buckets object delete --recursive` removes every object under a prefix. # Neon CLI command: buckets Manage branch object-storage buckets and their objects Last updated: 2026-09-17 The `buckets` command manages branch object-storage buckets and their objects. Buckets belong to a branch; the `object` subcommands work with the objects inside a bucket. Subcommands: [create](https://neon.com/docs/cli/buckets#create), [delete](https://neon.com/docs/cli/buckets#delete), [list](https://neon.com/docs/cli/buckets#list), [object](https://neon.com/docs/cli/buckets#object) ## neon buckets create Creates a bucket on a branch. ```bash neon bucket create [options] ``` | Option | Description | Type | Default | Required | | ---------------- | ---------------------------------------------------------------------- | ------ | --------- | :------: | | `--access-level` | The visibility of the bucket Possible values: `private`, `public_read` | string | `private` | No | | `--branch` | Branch ID or name | string | — | No | | `--project-id` | Project ID | string | — | No | Create a private bucket on a branch: ```bash neon buckets create my-bucket --access-level private ``` ## neon buckets list Lists the buckets on a branch. ```bash neon bucket list [options] ``` | Option | Description | Type | Default | Required | | -------------- | ----------------- | ------ | ------- | :------: | | `--branch` | Branch ID or name | string | — | No | | `--project-id` | Project ID | string | — | No | List the buckets on a branch with `json` output: ```bash neon buckets list --output json ``` ## neon buckets delete Deletes a bucket from a branch. ```bash neon bucket delete [options] ``` | Option | Description | Type | Default | Required | | -------------- | ----------------- | ------ | ------- | :------: | | `--branch` | Branch ID or name | string | — | No | | `--project-id` | Project ID | string | — | No | ```bash neon buckets delete my-bucket ``` ## Bucket objects Lists, downloads, uploads, or deletes objects in a bucket. Subcommands: [delete](https://neon.com/docs/cli/buckets#object-delete), [get](https://neon.com/docs/cli/buckets#object-get), [list](https://neon.com/docs/cli/buckets#object-list), [put](https://neon.com/docs/cli/buckets#object-put) ### neon buckets object list Lists objects in a bucket. ```bash neon bucket object list [/] [options] ``` | Option | Description | Type | Default | Required | | -------------- | ---------------------------------------------------------------------------------------------------------------------------------------- | ------- | ------- | :------: | | `--branch` | Branch ID or name | string | — | No | | `--cursor` | Pagination cursor returned as next\_cursor by a previous call | string | — | No | | `--delimiter` | Collapse keys sharing this prefix separator into folders. Defaults to "/" (folder view); ignored when --recursive is set | string | — | No | | `--limit` | Maximum number of items (objects + folders) to return | number | — | No | | `--project-id` | Project ID | string | — | No | | `--recursive` | List every key flat, descending into nested folders (no delimiter). Mutually exclusive with --delimiter. Mirrors "aws s3 ls --recursive" | boolean | `false` | No | List the objects under a prefix, collapsing keys into folders: ```bash neon buckets object list my-bucket/images --delimiter / ``` ### neon buckets object get Downloads an object from a bucket to a local file. ```bash neon bucket object get / [options] ``` | Option | Description | Type | Default | Required | | -------------- | ------------------------------------------------------------------------------------------------- | ------ | ------- | :------: | | `--branch` | Branch ID or name | string | — | No | | `--file` | Path to write the downloaded object to (defaults to the object filename in the current directory) | string | — | No | | `--project-id` | Project ID | string | — | No | ```bash neon buckets object get my-bucket/images/logo.png --file ./logo.png ``` ### neon buckets object put Uploads a local file to a bucket as an object. ```bash neon bucket object put / [options] ``` | Option | Description | Type | Default | Required | | ---------------- | ------------------------------------------------------- | ------ | ------- | :------: | | `--branch` | Branch ID or name | string | — | No | | `--content-type` | Content-Type to store the object with (e.g. text/plain) | string | — | No | | `--file` | Path to the local file to upload | string | — | Yes | | `--project-id` | Project ID | string | — | No | Upload a file, optionally setting the Content-Type to store it with: ```bash neon buckets object put my-bucket/images/logo.png --file ./logo.png neon buckets object put my-bucket/notes/readme.txt --file ./readme.txt --content-type text/plain ``` ### neon buckets object delete Deletes an object, or every object under a prefix. ```bash neon bucket object delete / [options] ``` | Option | Description | Type | Default | Required | | -------------- | ------------------------------------------------------------------------ | ------- | ------- | :------: | | `--branch` | Branch ID or name | string | — | No | | `--project-id` | Project ID | string | — | No | | `--recursive` | Delete every object under the given prefix. The prefix must end with "/" | boolean | `false` | No | With `--recursive`, the target is treated as a prefix, which must end with `/`. Delete a single object, or every object under a prefix: ```bash neon buckets object delete my-bucket/images/logo.png neon buckets object delete my-bucket/images/ --recursive ``` --- [Document source](https://neon.com/docs/cli/checkout.md) --- > Summary: Covers the usage of the `checkout` command in the Neon CLI to switch the active branch in your local context, so subsequent commands target that branch without specifying `--branch` on every command. # Neon CLI command: checkout Pin a branch in your local .neon context file Last updated: 2026-10-09 The `checkout` command pins a branch in the local context so subsequent commands target it. It's a focused helper over [`set-context`](https://neon.com/docs/cli/set-context) for the common "switch the branch I'm working on" case. `checkout` resolves the branch (by name or ID) against the project, then heals the `.neon` file: it always (re)writes `projectId`, `branch`, and `orgId` (when the project has one), so a `.neon` that was missing fields or drifted ends up complete and consistent. ## Usage ```bash neon checkout [id|name] [options] ``` The branch argument is optional. Run `neon checkout` with no branch in an interactive terminal to fetch the project's branches and pick one from a list. In a non-interactive context (CI or no TTY), you must pass a branch explicitly. ## Options | Option | Description | Type | Default | Required | | -------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------- | ------- | :------: | | `--create` | Create the named branch if it does not exist, then check it out | boolean | `false` | No | | `--env` | Path to a .env file to load into the environment before evaluating neon.ts so Function env values resolve from it. Existing env vars are not overridden. Function env values that read process.env must be set in this file or the environment. Used when this checkout creates a branch from neon.ts; ignored for an existing branch. | string | — | No | | `--env-pull` | Pull the branch's Neon env vars (DATABASE\_URL, ...) into a local .env after checkout. On by default; use --no-env-pull to skip, for example when injecting env at runtime with `neon-env run` (from `@neon/env`) or `neon dev`. | boolean | `true` | No | | `--project-id` | Project ID | string | — | No | By default, `checkout` pulls environment variables into a `.env` file after checking out the branch; use `--no-env-pull` to skip this. Creating a branch from a [`neon.ts`](https://neon.com/docs/reference/neon-ts) policy evaluates that policy, resolving any `process.env` values it references (such as a function's secrets) from your environment. Pass `--env ` to load those values from `` first, so they resolve during the checkout. Checking out an existing branch doesn't re-evaluate the policy, so `--env` is ignored there. ## Branch ID vs name Branch ID vs name is detected automatically (a `br-…` value is treated as an ID): - **ID:** Matched strictly by ID. A non-existent ID is a hard "not found" error (IDs are server-assigned, so `checkout` never creates one). - **Name:** Matched by name. If the name doesn't exist, pass `--create` to create it (equivalent to `neon branches create --name `: branched from the project's default branch with a read-write compute), then check it out. Without `--create`, an interactive terminal offers to create it, while a non-interactive context (CI or no TTY) exits with a "not found" error that tells you to pass `--create`. `--create` needs a branch name, so `neon checkout --create` on its own is an error. `--create` requires neon 4.15.0 or later. ## Project resolution The project is resolved through the standard Neon CLI chain, each entry winning over the next: 1. `--project-id ` flag 2. `projectId` from the closest `.neon` file (found by walking up from the current directory) 3. If still unresolved and the API key maps to exactly one project, that project is auto-detected (same behavior as `branches` and `connection-string`) If none of those resolve a project, `checkout` prints an error explaining the chain above. In an interactive terminal it then offers to run [`neon link`](https://neon.com/docs/cli/link) in the current folder so you can pick (or create) a project on the spot. In non-interactive contexts, it exits with a non-zero code instead of prompting. ## Examples Pin a branch by name. Projects created with the CLI or API get a default branch named `main`; Console-created projects use `production`. Run `neon branches list` if you're unsure: ```bash neon checkout main --project-id polished-snowflake-12345678 ``` ```text filename="Output" Checked out branch br-steep-math-aiu3vve7 on project polished-snowflake-12345678 (org org-example-12345678). Updated /path/to/cwd/.neon. Pulled 5 Neon variables into .env.local Postgres DATABASE_URL, DATABASE_URL_UNPOOLED Branch NEON_BRANCH, NEON_BRANCH_ID Functions NEON_FUNCTION_HOST_SUFFIX ``` The updated `.neon` file: ```json { "projectId": "polished-snowflake-12345678", "orgId": "org-example-12345678", "branch": "main" } ``` Pick a branch interactively (requires a linked project or `--project-id`): ```bash neon checkout ``` Pin a branch by ID: ```bash neon checkout br-cool-snow-12345678 --project-id polished-snowflake-12345678 ``` Create a branch by name if it doesn't exist yet, then pin it: ```bash neon checkout dev --create --project-id polished-snowflake-12345678 ``` After checking out a branch, commands such as [`connection-string`](https://neon.com/docs/cli/connection-string) and [`psql`](https://neon.com/docs/cli/psql) use the pinned branch by default. To run this checkout automatically whenever you switch git branches, see [`neon git`](https://neon.com/docs/cli/git) (Preview), which installs a git hook that checks out the mapped Neon branch on `git checkout`. --- [Document source](https://neon.com/docs/cli/claim.md) --- > Summary: The Neon CLI `claim` command (`neon claimable` is an alias) creates a temporary Neon project before anyone signs in. The CLI stores an identity assertion, writes credentials to `.env`, and later opens a claim URL so a human can take the project. See [Claimable Neon](/docs/reference/claimable-neon). # Neon CLI command: claim Create and claim a temporary Neon project without an account Last updated: 2026-11-05 The `claim` command creates a temporary Neon project when there is no Neon account yet. `neon claimable` is an alias. The CLI stores an identity assertion on the machine, writes provisioned variables to `.env` (or `.env.local`), and later opens a claim URL so a human can take the project into their organization. If `neon claim` is not a command, or `neon claim --help` does not list `create`, install the latest CLI (`npm i -g neon@latest`) or use the HTTP flow in [Claimable Neon](https://neon.com/docs/reference/claimable-neon). Do not pass `--api-key` or `--profile`. Those are refused. `neon login` and `neon init` need a Neon account; use this command instead when there is none. Start in the browser at [neon.com/claimable-neon](https://neon.com/claimable-neon), or give an agent [`auth.md`](https://neon.com/auth.md). Subcommands: [accept](https://neon.com/docs/cli/claim#accept), [create](https://neon.com/docs/cli/claim#create), [delete](https://neon.com/docs/cli/claim#delete), [list](https://neon.com/docs/cli/claim#list), [status](https://neon.com/docs/cli/claim#status) ## neon claim create Creates a temporary project and saves its identity assertion. Postgres is always requested. Pass `--service` for Data API, Managed Better Auth, or other services. If a [`neon.ts`](https://neon.com/docs/reference/neon-ts) file is present, declared services are requested automatically. [Realtime](https://neon.com/docs/cli/realtime) isn't available until the project is claimed, so `--service` doesn't accept it and a `neon.ts` Realtime declaration isn't requested. ```bash neon claim create [options] ``` | Option | Description | Type | Default | Required | | ------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------- | ------- | :------: | | `--config` | Path to neon.ts for registration and the bundled env pull. Defaults to the neon.ts in the project directory (next to .neon, or cwd without one) | string | — | No | | `--env-pull` | Write the same Neon env vars `env pull` would | boolean | `true` | No | | `--file` | Target dotenv file. Defaults to an existing .env, otherwise .env.local | string | — | No | | `--project-name` | Name for the new project. The project keeps it when claimed | string | — | No | | `--region-id` | Region ID for the new project (e.g. aws-eu-central-1). Defaults to aws-us-east-2 | string | — | No | | `--service`, `-s`, `--services` | Services to request for the claimable project: postgres, auth, data-api, functions, object-storage, ai-gateway. Repeat the flag or comma-separate. Postgres is always included. Services unavailable before claim are recorded and reported. | array | — | No | ```bash neon claim create --env-pull ``` ```bash neon claim create \ --service data-api \ --service auth \ --env-pull ``` `claim create` uses `aws-us-east-2` unless you pass `--region-id` with another AWS [region](https://neon.com/docs/introduction/regions) that accepts new projects. The output includes the project's `region_id`. ```bash neon claim create --region-id aws-eu-central-1 ``` The project gets a generated name unless you pass `--project-name`. It keeps the name when you claim it: ```bash neon claim create --project-name my-app ``` `--env-pull` is on by default. It writes provisioned vars to an existing `.env`, otherwise `.env.local`, and gitignores that file. If `.env` or `.env.local` already has a `DATABASE_URL` (or other Neon-managed keys), pass `--file ` or `--no-env-pull`. After create, regular Neon CLI commands use the saved assertion. Explicit Neon account credentials take precedence when you pass them. ## neon claim status Shows a claimable project's lifecycle and claim status. Pass a project ID from `neon claim list`, or omit it to use the project linked in the current directory. ```bash neon claim status [project-id] [options] ``` ```bash neon claim status ``` ## neon claim accept Creates a claim code and opens the URL where a human signs in and takes the project. `--open` is on by default. `--no-open` prints the URL. ```bash neon claim accept [project-id] [options] ``` | Option | Description | Type | Default | Required | | -------- | -------------------------------------- | ------- | ------- | :------: | | `--open` | Open the verification URL in a browser | boolean | `true` | No | ```bash neon claim accept --no-open ``` Opening the URL does not freeze access. Continuing to Neon from that URL starts the transfer and rotates `DATABASE_URL` before the console org picker. ## neon claim list Lists claimable projects saved on this machine. ```bash neon claim list [options] ``` ```bash neon claim list ``` ## neon claim delete Permanently deletes an unclaimed project, or drops a local record that can no longer reach the service. Pass a project ID from `neon claim list`, or omit it to use the linked project. Pass `--yes` to skip the confirmation prompt. ```bash neon claim delete [project-id] [options] ``` | Option | Description | Type | Default | Required | | ------------- | ---------------------------- | ------- | ------- | :------: | | `--yes`, `-y` | Skip the confirmation prompt | boolean | `false` | No | ```bash neon claim delete --yes ``` --- [Document source](https://neon.com/docs/cli/completion.md) --- > Summary: The `neon completion` command generates a yargs-based shell tab-completion script for `neon` that surfaces available commands and options when you press Tab. Use this page when you want to enable autocomplete for the Neon CLI in your terminal, so you can stop typing full command names from memory. Installation targets include `.bashrc`, `.bash_profile`, `.profile`, and `.zshrc` on Linux and macOS. # Neon CLI command: completion Generate shell completion scripts for neon commands and options Last updated: 2026-07-01 The `completion` command generates a shell completion script for `neon`. Once installed, the script presents the possible commands and options when you press the **tab** key after typing or partially typing a command or option. ## Usage ```bash neon completion ``` **Important:** Generate the completion script in your own terminal, as the script may differ depending on your operating environment.
Show output ```text filename="Output" ###-begin-neon-completions-### # # yargs command completion script # # Installation: neon completion >> ~/.bashrc # or neon completion >> ~/.bash_profile on OSX. # _neon_yargs_completions() { local cur_word args type_list cur_word="${COMP_WORDS[COMP_CWORD]}" args=("${COMP_WORDS[@]}") # ask yargs to generate completions. type_list=$(neon --get-yargs-completions "${args[@]}") COMPREPLY=( $(compgen -W "${type_list}" -- ${cur_word}) ) # if no match was found, fall back to filename completion if [ ${#COMPREPLY[@]} -eq 0 ]; then COMPREPLY=() fi return 0 } complete -o bashdefault -o default -F _neon_yargs_completions neon ###-end-neon-completions-### ```
## Examples Add the completion script to your shell configuration file in your home directory. The file differs by platform: Ubuntu typically uses `.bashrc`, while macOS uses `.bash_profile` or `.zshrc`. The `source` command applies the change to the current shell session. Add the completion script to `.bashrc`: ```bash neon completion >> ~/.bashrc source ~/.bashrc ``` Add the completion script to `.bash_profile`: ```bash neon completion >> ~/.bash_profile source ~/.bash_profile ``` Add the completion script to `.profile`: ```bash neon completion >> ~/.profile source ~/.profile ``` Add the completion script to `.zshrc`: ```bash neon completion >> ~/.zshrc source ~/.zshrc ``` --- [Document source](https://neon.com/docs/cli/config.md) --- > Summary: The Neon CLI `neon config` command manages a branch declaratively with a neon.ts policy file. Use `neon config init` to scaffold a starter neon.ts and install the config packages, `neon config add` to declare a service, function, or bucket in an existing neon.ts, `neon config status` to show the branch's live Neon state (`neon status --current-branch` prints the pinned branch offline for shell prompts), `neon config plan` for a dry run of what an apply would change, and `neon config apply` (or its top-level alias `neon deploy`) to apply the policy to the branch. Supports --config to point at a neon.ts file, --env to load environment variables before evaluating it, and --allow-protected, --update-existing, or -y to answer the apply confirmation prompts in non-interactive use. # Neon CLI command: config Manage a branch with a neon.ts policy: init, add, status, plan, and apply Last updated: 2026-10-31 The `config` command manages a branch declaratively with a `neon.ts` policy file: scaffold a starter config, inspect the branch's live state, preview what an apply would change, and apply the policy. For the `neon.ts` file format, see the [neon.ts reference](https://neon.com/docs/reference/neon-ts). Subcommands: [add](https://neon.com/docs/cli/config#add), [apply](https://neon.com/docs/cli/config#apply), [init](https://neon.com/docs/cli/config#init), [plan](https://neon.com/docs/cli/config#plan), [status](https://neon.com/docs/cli/config#status) The top-level [`neon deploy`](https://neon.com/docs/cli/deploy) command is an alias for `config apply`, and [`neon status`](https://neon.com/docs/cli/status) is an alias for `config status`. ## neon config init Scaffolds a starter `neon.ts` policy file in the current project and installs the `@neon/config` and `@neon/env` packages, so you can start managing a branch declaratively. The generated file uses the standard named `defineConfig` import from `@neon/config/v1` and exports the result as the module default, for example: ```ts filename="neon.ts" import { defineConfig } from "@neon/config/v1"; export default defineConfig({ // Declare your Neon services here auth: false, // Branch policy: per-branch tuning branch: (branch) => { if (branch.isDefault) { // Default branch: no overrides, uses project defaults return {}; } if (!branch.exists) { // New non-default branches: auto-expire // Run `neon checkout ` to create a new branch with these settings return { ttl: "7d" }; } // Existing branch: no changes return {}; }, }); ``` If a `neon.ts`, `neon.mts`, `neon.js`, or `neon.mjs` file already exists, `config init` is idempotent: it leaves that file untouched instead of overwriting hand-written policy. By default, `config init` runs locally and does not call the Neon API. With `--from-branch`, it reads the branch's live state through the Neon API, so it needs your Neon credentials and a project. It picks your package manager (npm, pnpm, yarn, or bun) from the project's lockfile, or from how the command was invoked if there's no lockfile. Before installing, it makes sure `node_modules/` is listed in your `.gitignore`, appending it if it's missing. Pass `--no-install` to skip installation and just print the command to run. ```bash neon config init [options] ``` | Option | Description | Type | Default | Required | | ------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------- | ------- | :------: | | `--from-branch` | Seed neon.ts from a branch's live Neon state instead of asking. Uses the branch pinned in .neon, or --branch \, or the project's default branch. Needs credentials and a project. | boolean | — | No | | `--install` | Install @neon/config and @neon/env if they're missing. On by default; use --no-install to just print the command. | boolean | `true` | No | | `--services`, `-s`, `--service` | Services the scaffolded neon.ts declares: postgres, auth, data-api, functions, object-storage, ai-gateway, realtime. Repeat the flag or comma-separate. postgres alone writes the starter policy; every branch has Postgres. Omitted: pick interactively on a terminal, starter policy in CI or without a TTY. | array | — | No | | `--branch` | Branch ID or name | string | — | No | | `--project-id` | Project ID | string | — | No | ```bash neon config init ``` Pass `--services` to declare services in the file it scaffolds, for example `neon config init --services auth,functions,realtime`. This applies only when creating a new `neon.ts`; to add services to a file that already exists, use [`config add`](https://neon.com/docs/cli/config#add). In a linked project, declaring the Data API makes `config init` check the branch's Data API and pick `dataApi: true` or the external form, [as `init` does](https://neon.com/docs/cli/init). If the check fails, it declares `dataApi: true` with `auth: true` and prints a warning. For non-interactive setup, run it with package installation disabled, then install the printed dependencies yourself (or add them to your lockfile in a separate step): ```bash neon config init --no-install npm install @neon/config @neon/env ``` Use `config init` when you want a trusted starter artifact and package list. Hand-write `neon.ts` instead when you need a different filename/module format or want to avoid modifying files in the current directory. **Tip:** After running an interactive [`neon link`](https://neon.com/docs/cli/link), the CLI prompts you to run `config init` as its final step, unless the project already has a `neon.ts` file. ## neon config add Declares a service, function, or bucket in your `neon.ts`, creating the file if there isn't one. Where [`config init`](https://neon.com/docs/cli/config#init) scaffolds a starter policy and leaves an existing file alone, `config add` edits an existing policy for you, including creating and registering a handler for a function. To declare services while first scaffolding the file, use [`config init --services`](https://neon.com/docs/cli/config#init) instead. ```bash neon config add [options] ``` Subcommands: [ai-gateway](https://neon.com/docs/cli/config#add-ai-gateway), [auth](https://neon.com/docs/cli/config#add-auth), [bucket](https://neon.com/docs/cli/config#add-bucket), [data-api](https://neon.com/docs/cli/config#add-data-api), [function](https://neon.com/docs/cli/config#add-function), [realtime](https://neon.com/docs/cli/config#add-realtime) `config add` runs entirely locally: it edits files, and never authenticates or resolves a project. Provisioning stays a separate [`neon config apply`](https://neon.com/docs/cli/config#apply) step. It looks for your config in the project directory: the directory holding the nearest `.neon` file (found by searching up from the current directory), or the current directory when there's no `.neon`. A `neon.ts` in a parent directory no longer applies. When it finds none, it creates `neon.ts` there and installs the `@neon/config` and `@neon/env` packages; pass `--no-install` to print the install command instead. Editing an existing file never installs packages. Pass `--config ` to target a specific file; a path that doesn't exist is an error. It edits the file in place, keeping your comments and formatting. It refuses edits it can't make safely, such as a graduated service still declared under the `preview` block, where it's a deprecated alias, and prints the lines to add by hand instead. Re-adding an already-enabled service exits `0` with "nothing to change"; a duplicate function slug or bucket name exits `1`; a bare `neon config add` exits `1` and lists what you can add. ### neon config add auth Enables Managed Better Auth by setting `auth: true`. ```bash neon config add auth [options] ``` | Option | Description | Type | Default | Required | | -------------- | ---------------------------------------------------------------------------------------------------------------------- | ------- | ------- | :------: | | `--config` | Path to the neon.ts to edit (defaults to the neon.ts next to .neon, or in cwd without one; created there when missing) | string | — | No | | `--install` | Install @neon/config and @neon/env when creating neon.ts. On by default; use --no-install to just print the command. | boolean | `true` | No | | `--branch` | Branch ID or name | string | — | No | | `--project-id` | Project ID | string | — | No | ```bash neon config add auth ``` ### neon config add data-api Enables the Data API by setting `dataApi: true`, and enables Managed Better Auth, which the default provider requires (it flips `auth: false` to `true`). An existing external auth provider is left unchanged. ```bash neon config add data-api [options] ``` | Option | Description | Type | Default | Required | | -------------- | ---------------------------------------------------------------------------------------------------------------------- | ------- | ------- | :------: | | `--config` | Path to the neon.ts to edit (defaults to the neon.ts next to .neon, or in cwd without one; created there when missing) | string | — | No | | `--install` | Install @neon/config and @neon/env when creating neon.ts. On by default; use --no-install to just print the command. | boolean | `true` | No | | `--branch` | Branch ID or name | string | — | No | | `--project-id` | Project ID | string | — | No | ```bash neon config add data-api ``` ### neon config add ai-gateway Enables the AI Gateway by setting `aiGateway: true`. ```bash neon config add ai-gateway [options] ``` | Option | Description | Type | Default | Required | | -------------- | ---------------------------------------------------------------------------------------------------------------------- | ------- | ------- | :------: | | `--config` | Path to the neon.ts to edit (defaults to the neon.ts next to .neon, or in cwd without one; created there when missing) | string | — | No | | `--install` | Install @neon/config and @neon/env when creating neon.ts. On by default; use --no-install to just print the command. | boolean | `true` | No | | `--branch` | Branch ID or name | string | — | No | | `--project-id` | Project ID | string | — | No | ```bash neon config add ai-gateway ``` ### neon config add realtime Enables [Neon Realtime](https://neon.com/docs/realtime/overview) by setting `preview.realtime: true`. Pass `--allowed-origin` (repeatable) to set the browser origins allowed to connect instead, which writes `preview.realtime: { allowedOrigins: [...] }`. Each origin must be `*` or an `http` or `https` origin with no path, query, or fragment, and the command checks them before editing the file. See [`neon realtime enable`](https://neon.com/docs/cli/realtime#enable) for the full rules. ```bash neon config add realtime [options] ``` | Option | Description | Type | Default | Required | | ------------------ | ------------------------------------------------------------- | ------ | ------- | :------: | | `--allowed-origin` | Allowed browser origin (repeatable). "\*" allows every origin | array | — | No | | `--branch` | Branch ID or name | string | — | No | | `--project-id` | Project ID | string | — | No | With an existing `neon.ts`, setting an allowed origin updates it in place: ```bash neon config add realtime --allowed-origin https://app.example.com ``` ```text Updated neon.ts: set preview.realtime to { allowedOrigins: ["https://app.example.com"] }. Next: `neon config plan` to preview, `neon config apply` to provision. ``` ### neon config add function Declares a [Neon Function](https://neon.com/docs/cli/functions) and creates its handler file. The handler defaults to `functions/.ts` (`.js` for a JavaScript config). A slug is 1 to 20 lowercase letters and digits, with no hyphens. Pass `--name` to set a display name (it defaults to the slug), or `--source` to register an existing handler relative to `neon.ts` without overwriting it. To start from a [Function Registry template](https://neon.com/functions/templates) instead of the starter handler, use [`neon functions new`](https://neon.com/docs/cli/functions#new). ```bash neon config add function [options] ``` | Option | Description | Type | Default | Required | | -------------- | -------------------------------------------------------------------------------------------------------------------- | ------ | ------- | :------: | | `--name` | Display name. Defaults to the slug | string | — | No | | `--source` | Handler file, relative to neon.ts. Defaults to functions/\.ts. Created when missing, left alone when it exists | string | — | No | | `--branch` | Branch ID or name | string | — | No | | `--project-id` | Project ID | string | — | No | Adding a function to a directory with no `neon.ts` creates both the config and the handler: ```bash neon config add function sendemail ``` ```text Created functions/sendemail.ts. Created neon.ts: added functions.sendemail. Created package.json. Installing @neon/config, @neon/env with npm… Next: `neon dev` to run it locally, `neon config apply` to deploy. ``` ### neon config add bucket Declares a [Neon Object Storage](https://neon.com/docs/cli/buckets) bucket. Pass `--access public_read` to allow anonymous reads; the default is `private`. ```bash neon config add bucket [options] ``` | Option | Description | Type | Default | Required | | -------------- | ----------------------------------------------------------------------------------------------------------------------------- | ------ | --------- | :------: | | `--access` | Anonymous access: private requires credentials, public\_read allows anonymous reads Possible values: `private`, `public_read` | string | `private` | No | | `--branch` | Branch ID or name | string | — | No | | `--project-id` | Project ID | string | — | No | ```bash neon config add bucket assets --access public_read ``` ## neon config status Shows the branch's live Neon state. ```bash neon config status [options] ``` | Option | Description | Type | Default | Required | | ------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------- | ------- | ------- | :------: | | `--config-json` | Print only the branch's live config as neon.ts-shaped JSON (services + branch tuning + preview), to stdout. Useful for scripting or copying into a neon.ts. | boolean | `false` | No | | `--current-branch` | Print only the linked branch name from the local .neon file (no network). Exits non-zero when no branch is pinned. | boolean | `false` | No | | `--branch` | Branch ID or name | string | — | No | | `--project-id` | Project ID | string | — | No | ```bash neon config status ``` The top-level `neon status` command is an alias for `config status` and accepts the same options. ### Print the current branch offline Pass `--current-branch` to print _only_ the branch pinned in the local `.neon` file. This variant makes no network request and requires no login or analytics, so it is cheap enough to drive a shell prompt. It prints the branch name to stdout and exits `0`. When no branch is pinned, it prints nothing to stdout, writes a `neon checkout ` hint to stderr, and exits with a non-zero status, so a prompt can guard on the command directly. ```bash neon status --current-branch ``` For example, add your current Neon branch to a [starship](https://starship.rs) prompt. Append this `[custom.neon]` module to `~/.config/starship.toml`. The `command` prints the pinned branch, and `when` hides the segment (exits non-zero) whenever you are not in a Neon project: ```toml # ~/.config/starship.toml [custom.neon] description = "Current Neon branch" command = "neon status --current-branch" # prints the branch pinned in .neon (no network) when = "neon status --current-branch" # exits non-zero when no branch -> segment is hidden symbol = "🌿 " style = "bold green" format = "[$symbol$output]($style) " ``` **Tip: Faster outside Neon projects** The `when` above runs the CLI on every prompt everywhere. To skip it unless a `.neon` file exists somewhere up the tree, replace `when` with a pure-shell walk-up and add `shell = ["sh"]` so it runs under `sh` even if your interactive shell is fish or PowerShell: ```toml shell = ["sh"] when = ''' d="$PWD" while [ "$d" != "$HOME" ] && [ "$d" != / ]; do if [ -e "$d/.neon" ]; then neon status --current-branch >/dev/null 2>&1 exit $? fi d=$(dirname "$d") done exit 1 ''' ``` For a full copy-paste (and agent-ready) walkthrough, including prerequisites and troubleshooting, see this [Starship + Neon branch setup gist](https://gist.github.com/thisistonydang/0b6c03ec9aa9b619ffecd48f58fd40c7). ## neon config plan Shows what `config apply` would change, as a dry run. Nothing is modified. ```bash neon config plan [options] ``` | Option | Description | Type | Default | Required | | -------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------ | ------- | :------: | | `--config` | Path to a neon.ts policy (defaults to the neon.ts next to .neon, or in cwd without one) | string | — | No | | `--env` | Path to a .env file to load into the environment before evaluating neon.ts so Function env values resolve from it. Existing env vars are not overridden. Function env values that read process.env must be set in this file or the environment. | string | — | No | | `--branch` | Branch ID or name | string | — | No | | `--project-id` | Project ID | string | — | No | ```bash neon config plan --config ./neon.ts --env .env.local ``` ## neon config apply Applies a `neon.ts` policy to the branch. ```bash neon config apply [options] ``` | Option | Description | Type | Default | Required | | ------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------- | ------- | :------: | | `--allow-protected` | Apply to a branch marked protected on Neon without asking | boolean | `false` | No | | `--config` | Path to a neon.ts policy (defaults to the neon.ts next to .neon, or in cwd without one) | string | — | No | | `--env` | Path to a .env file to load into the environment before evaluating neon.ts so Function env values resolve from it. Existing env vars are not overridden. Function env values that read process.env must be set in this file or the environment. | string | — | No | | `--env-pull` | Pull the branch's Neon env vars (DATABASE\_URL, …) into a local .env after a successful apply. On by default; use --no-env-pull to skip (e.g. when injecting env at runtime with `neon-env run` / `neon dev`). | boolean | `true` | No | | `--update-existing` | Override branch settings that differ from neon.ts without asking | boolean | `false` | No | | `--yes`, `-y` | Answer yes to every confirmation: --update-existing and --allow-protected | boolean | `false` | No | | `--branch` | Branch ID or name | string | — | No | | `--project-id` | Project ID | string | — | No | In a terminal, `apply` asks before it overrides branch settings that differ from `neon.ts` or applies to a branch marked protected on Neon. Declining applies nothing. Without a terminal, there's no prompt. This covers CI, runs with no TTY, and `-o json` or `-o yaml` output. In those cases, `apply` stops before changing anything and names the flag to re-run with. For scripts, CI, and agents, pass `--update-existing` to allow the overrides, `--allow-protected` to allow a protected branch, or `-y` for both: ```bash neon config apply --branch feature/auth -y ``` --- [Document source](https://neon.com/docs/cli/connection-string.md) --- > Summary: The Neon connection string command (`neon connection-string`) outputs a PostgreSQL connection URL for a specified branch, role, and database, including the role password. Use it to get connection strings for psql, Prisma (--prisma), connection pooling (--pooled), read-only replicas (--endpoint-type read_only), or time-travel queries targeting a specific timestamp or LSN. # Neon CLI command: connection-string Get Postgres connection strings for branches and databases Last updated: 2026-11-05 The `connection-string` command gets a Postgres connection string for any database on any branch in your Neon project. The connection string includes the password for the specified role. It's also available as [`neon postgres connection-string`](https://neon.com/docs/cli/postgres#connection-string). For information about connecting to Neon, see [Connect from any application](https://neon.com/docs/connect/connect-from-any-app). If `--project-id` is omitted, the CLI resolves it from your [context file](https://neon.com/docs/cli/link), auto-selects when your account has only one project, and otherwise asks you to pass `--project-id`. `--database-name` is needed only when the branch has more than one database. Without `--role-name`, the command uses the branch's only role, or `neondb_owner` when there are several. The roles that the [Data API](https://neon.com/docs/data-api/get-started) and [Managed Better Auth](https://neon.com/docs/auth/overview) add (`authenticator`, `anonymous`, and `authenticated`) don't count, so you don't need `--role-name` on those branches either. This is the same role [`neon env pull`](https://neon.com/docs/cli/env) writes into `DATABASE_URL`. If the command still can't pick a role, it asks you to pass `--role-name`. **Tip: Connect with psql** To open a `psql` session directly, use the dedicated [`neon psql`](https://neon.com/docs/cli/psql) command. You can also pass `--psql` to `connection-string` to achieve the same result. ## Usage ```bash neon connection-string [branch] [options] ``` The `[branch]` is the branch name or ID. If omitted, the default branch is used. To connect to a specific point in the branch's history, use the point-in-time format `branch@timestamp` or `branch@lsn`. If no timestamp or LSN is appended, the current state (HEAD) is used. ## Options | Option | Description | Type | Default | Required | | ----------------- | ------------------------------------------------------------------------------------------------- | ------- | --------- | :------: | | `--database-name` | Database name | string | — | No | | `--endpoint-type` | Endpoint type | string | — | No | | `--extended` | Show extended information | boolean | — | No | | `--pooled` | Use pooled connection | boolean | `false` | No | | `--prisma` | Use connection string for Prisma setup | boolean | `false` | No | | `--project-id` | Project ID | string | — | No | | `--psql` | Connect to a database via psql using connection string | boolean | `false` | No | | `--role-name` | Role name. Defaults to neondb\_owner, else the only role besides the Data API and Neon Auth roles | string | — | No | | `--ssl` | SSL mode Possible values: `require`, `verify-ca`, `verify-full`, `omit` | string | `require` | No | The `--endpoint-type` value can be `read_write` (the default) or `read_only`. The `--psql` option doesn't require a psql installation: if `psql` isn't on your `$PATH`, the CLI uses a built-in TypeScript implementation. To save your project context to a file and avoid repeating `--project-id`, see [Using a named context file](https://neon.com/docs/cli/set-context#using-a-named-context-file). ## Examples Get a connection string for a branch: ```bash neon connection-string mybranch ``` ```text filename="Output" postgresql://alex:AbC123dEf@ep-cool-darkness-123456.us-east-2.aws.neon.tech/dbname?sslmode=require&channel_binding=require ``` - Get a pooled connection string. The `--pooled` option adds a `-pooler` suffix to the host name, which enables connection pooling for clients that use this connection string. ```bash neon connection-string --pooled ``` ```text postgresql://alex:AbC123dEf@ep-cool-darkness-123456-pooler.us-east-2.aws.neon.tech/dbname?sslmode=require&channel_binding=require ``` - Get a connection string for use with Prisma. The `--prisma` option adds `connect_timeout=30` to the connection string so that connections from Prisma Client don't time out. ```bash neon connection-string --prisma ``` ```text postgresql://alex:AbC123dEf@ep-cool-darkness-123456.us-east-2.aws.neon.tech/dbname?sslmode=require&channel_binding=require&connect_timeout=30 ``` - Get a connection string to a specific point in a branch's history by appending `@timestamp` or `@lsn`. Availability depends on your configured [history window](https://neon.com/docs/introduction/history-window). For additional examples, see [How to use Time Travel](https://neon.com/docs/guides/time-travel-assist#how-to-use-time-travel). ```bash neon connection-string @2024-04-21T00:00:00Z ``` Get a connection string and connect with `psql`: ```bash neon connection-string --psql ``` Get a connection string, connect with `psql`, and run an `.sql` file: ```bash neon connection-string --psql -- -f dump.sql ``` Get a connection string, connect with `psql`, and run a query: ```bash neon connection-string --psql -- -c "SELECT version()" ``` --- [Document source](https://neon.com/docs/cli/credentials.md) --- > Summary: The Neon CLI `neon credentials` command manages branch-scoped credentials: issue a credential with storage, AI gateway, or function-invoke scopes, list the credentials on a branch, reveal a credential's secrets, rotate its secrets in place, and revoke it. # Neon CLI command: credentials Issue, list, reveal, rotate, and revoke scoped credentials on a branch Last updated: 2026-10-21 The `credentials` command manages scoped credentials on a branch. A credential grants an application or agent direct access to a branch's surfaces without an account API key. Each credential carries one or more scopes and, when issued, a pair of secrets: an `api_token` and an `s3_secret_access_key`. The available scopes are: - `storage:read` and `storage:write` for [Neon Object Storage](https://neon.com/docs/storage/overview) - `ai_gateway:invoke` for the [Neon AI Gateway](https://neon.com/docs/ai-gateway/overview) - `functions:invoke` for invoking [Neon Functions](https://neon.com/docs/compute/functions/overview) Credentials are branch-scoped. Pass `--project-id` and `--branch` to target a branch, or let the CLI resolve them from your [context file](https://neon.com/docs/cli/link). A credential's `token_id` has the form `nak_live_` and is stable across a rotation. **Important: Store secrets when they're issued** The `api_token` and `s3_secret_access_key` are returned only when you create or rotate a credential, or when you explicitly run `neon credentials reveal`. Store them securely as soon as they're issued. Subcommands: [create](https://neon.com/docs/cli/credentials#create), [list](https://neon.com/docs/cli/credentials#list), [reveal](https://neon.com/docs/cli/credentials#reveal), [revoke](https://neon.com/docs/cli/credentials#revoke), [rotate](https://neon.com/docs/cli/credentials#rotate) ## neon credentials list Lists the credentials on the branch. Secrets are never included; use [`neon credentials reveal`](https://neon.com/docs/cli/credentials#reveal) to see them. ```bash neon credentials list [options] ``` | Option | Description | Type | Default | Required | | -------------- | ----------------- | ------ | ------- | :------: | | `--branch` | Branch ID or name | string | — | No | | `--project-id` | Project ID | string | — | No | ```bash neon credentials list --project-id solitary-heart-93902637 --branch main ``` ```text filename="Output" Token ID Name Principal Type Scopes Created At nak_live_aaaa1111bbbb2222cccc3333dddd4444 Default AI gateway credential user ai_gateway:invoke 2026-09-10T20:02:49Z nak_live_eeee5555ffff6666aaaa7777bbbb8888 Default object storage credential user storage:read, storage:write 2026-09-10T20:02:50Z ``` ## neon credentials create Issues a new credential. `--scope` is required and repeatable; pass one for each capability you want to grant. `--name` is an optional label. ```bash neon credentials create [options] ``` | Option | Description | Type | Default | Required | | -------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------ | ------- | :------: | | `--name` | Label for the credential | string | — | No | | `--scope` | Capability to grant. Repeatable. Values: storage:read, storage:write, ai\_gateway:invoke, functions:invoke Possible values: `storage:read`, `storage:write`, `ai_gateway:invoke`, `functions:invoke` | array | — | Yes | | `--branch` | Branch ID or name | string | — | No | | `--project-id` | Project ID | string | — | No | ```bash neon credentials create --name uploads --scope storage:read --scope storage:write --project-id solitary-heart-93902637 --branch main ``` ```text filename="Output" Token ID nak_live_0123456789abcdef0123456789abcdef Name uploads Scopes storage:read, storage:write api_token: s3_secret_access_key: WARNING: Store these secrets now: they are not shown again unless you run neon credentials reveal. ``` With `--output json`, the secrets stay on the object so scripts can read them:
Show output ```json { "token_id": "nak_live_0123456789abcdef0123456789abcdef", "token_id_short": "0123456789ab", "name": "uploads", "api_token": "", "s3_secret_access_key": "", "scopes": ["storage:read", "storage:write"], "branch_id": "br-morning-frost-a1b2c3d4", "created_at": "2026-09-10T20:02:49Z" } ```
## neon credentials reveal Shows a credential's `api_token` and `s3_secret_access_key` again, looked up by `token_id`. ```bash neon credentials reveal [options] ``` | Option | Description | Type | Default | Required | | -------------- | ----------------- | ------ | ------- | :------: | | `--branch` | Branch ID or name | string | — | No | | `--project-id` | Project ID | string | — | No | ```bash neon credentials reveal nak_live_0123456789abcdef0123456789abcdef --project-id solitary-heart-93902637 --branch main ``` ```text filename="Output" Token ID nak_live_0123456789abcdef0123456789abcdef api_token: s3_secret_access_key: WARNING: These are live secrets. Treat them like a password. ``` ## neon credentials rotate Replaces a credential's secrets in place. The `token_id` is unchanged, so anything that references the credential by ID keeps working once you update the stored secrets. ```bash neon credentials rotate [options] ``` | Option | Description | Type | Default | Required | | -------------- | ----------------- | ------ | ------- | :------: | | `--branch` | Branch ID or name | string | — | No | | `--project-id` | Project ID | string | — | No | ```bash neon credentials rotate nak_live_0123456789abcdef0123456789abcdef --project-id solitary-heart-93902637 --branch main ``` ```text filename="Output" Token ID nak_live_0123456789abcdef0123456789abcdef Name uploads Scopes storage:read, storage:write api_token: s3_secret_access_key: WARNING: Store the new secrets now: a retry mints another pair and does not recover a lost response. A replica may briefly accept the previous secret. ``` ## neon credentials revoke Revokes a credential. Its secrets stop working and the `token_id` can no longer be revealed or rotated. ```bash neon credentials revoke [options] ``` | Option | Description | Type | Default | Required | | -------------- | ----------------- | ------ | ------- | :------: | | `--branch` | Branch ID or name | string | — | No | | `--project-id` | Project ID | string | — | No | ```bash neon credentials revoke nak_live_0123456789abcdef0123456789abcdef --project-id solitary-heart-93902637 --branch main ``` ```text filename="Output" Credential nak_live_0123456789abcdef0123456789abcdef revoked ``` --- [Document source](https://neon.com/docs/cli/data-api.md) --- > Summary: Covers the usage of the `data-api` command in the Neon CLI to create, inspect, update, refresh, and delete the Neon Data API for a database. # Neon CLI command: data-api Provision and manage the Neon Data API from the CLI Last updated: 2026-09-18 The `data-api` command provisions and manages the [Neon Data API](https://neon.com/docs/data-api/overview) for a database. For Console-based management, see [Manage Data API](https://neon.com/docs/data-api/manage). Subcommands: [create](https://neon.com/docs/cli/data-api#create), [delete](https://neon.com/docs/cli/data-api#delete), [get](https://neon.com/docs/cli/data-api#get), [refresh-schema](https://neon.com/docs/cli/data-api#refresh-schema), [update](https://neon.com/docs/cli/data-api#update) If `--project-id`, `--branch`, or `--database` are omitted, the CLI resolves them from your [context file](https://neon.com/docs/cli/link), auto-selects when there is only one option, and otherwise asks you to pass the flag. ## Settings flags The `create` and `update` subcommands share a set of settings flags that configure how the Data API serves your database: | Flag | Description | Type | | ------------------------------- | ----------------------------------------------------------- | ------- | | `--db-aggregates-enabled` | Enable aggregate functions in queries | boolean | | `--db-anon-role` | Database role used for anonymous (unauthenticated) requests | string | | `--db-extra-search-path` | Extra schemas appended to the search path | string | | `--db-max-rows` | Maximum number of rows returned by a single request | number | | `--db-schemas` | Comma-separated list of schemas exposed via the Data API | string | | `--jwt-role-claim-key` | JWT claim path used to extract the role | string | | `--jwt-cache-max-lifetime` | Maximum JWT cache lifetime in seconds | number | | `--openapi-mode` | OpenAPI mode. Choices: `ignore-privileges`, `disabled` | string | | `--server-cors-allowed-origins` | CORS allowed origins | string | | `--server-timing-enabled` | Enable Server-Timing response headers | boolean | ## neon data-api create Provisions the Neon Data API for a database. ```bash neon data-api create [options] ``` | Option | Description | Type | Default | Required | | ------------------------------- | --------------------------------------------------------------------------- | ------- | ------- | :------: | | `--add-default-grants` | Grant all permissions on tables in the public schema to authenticated users | boolean | — | No | | `--auth-provider` | Authentication provider Possible values: `neon_auth`, `external` | string | — | No | | `--db-aggregates-enabled` | Enable aggregate functions in queries | boolean | — | No | | `--db-anon-role` | Database role used for anonymous (unauthenticated) requests | string | — | No | | `--db-extra-search-path` | Extra schemas appended to the search path | string | — | No | | `--db-max-rows` | Maximum number of rows returned by a single request | number | — | No | | `--db-schemas` | Comma-separated list of schemas exposed via the Data API | string | — | No | | `--jwks-url` | URL that lists the JWKS (used with external auth) | string | — | No | | `--jwt-audience` | Expected JWT audience claim | string | — | No | | `--jwt-cache-max-lifetime` | Maximum JWT cache lifetime in seconds | number | — | No | | `--jwt-role-claim-key` | JWT claim path used to extract the role | string | — | No | | `--openapi-mode` | OpenAPI mode Possible values: `ignore-privileges`, `disabled` | string | — | No | | `--provider-name` | Name of the auth provider (e.g. Clerk, Stytch, Auth0) | string | — | No | | `--server-cors-allowed-origins` | CORS allowed origins | string | — | No | | `--server-timing-enabled` | Enable Server-Timing response headers | boolean | — | No | | `--skip-auth-schema` | Skip creating the auth schema and RLS functions | boolean | — | No | | `--branch` | Branch ID or name | string | — | No | | `--database` | Database name | string | — | No | | `--project-id` | Project ID | string | — | No | `create` also accepts [settings flags](https://neon.com/docs/cli/data-api#settings-flags) to configure the Data API at provision time. Provision the Data API with Managed Better Auth: ```bash neon data-api create --database neondb --auth-provider neon_auth ``` ## neon data-api get Shows the Neon Data API status and settings. ```bash neon data-api get [options] ``` | Option | Description | Type | Default | Required | | -------------- | ----------------- | ------ | ------- | :------: | | `--branch` | Branch ID or name | string | — | No | | `--database` | Database name | string | — | No | | `--project-id` | Project ID | string | — | No | ```bash neon data-api get --database neondb ``` ## neon data-api update Updates Neon Data API settings. By default, the flags you provide are merged with the current settings. Pass `--replace` to overwrite all settings with only the flags you provide. ```bash neon data-api update [options] ``` | Option | Description | Type | Default | Required | | ------------------------------- | ------------------------------------------------------------------------------------------ | ------- | ------- | :------: | | `--db-aggregates-enabled` | Enable aggregate functions in queries | boolean | — | No | | `--db-anon-role` | Database role used for anonymous (unauthenticated) requests | string | — | No | | `--db-extra-search-path` | Extra schemas appended to the search path | string | — | No | | `--db-max-rows` | Maximum number of rows returned by a single request | number | — | No | | `--db-schemas` | Comma-separated list of schemas exposed via the Data API | string | — | No | | `--jwt-cache-max-lifetime` | Maximum JWT cache lifetime in seconds | number | — | No | | `--jwt-role-claim-key` | JWT claim path used to extract the role | string | — | No | | `--openapi-mode` | OpenAPI mode Possible values: `ignore-privileges`, `disabled` | string | — | No | | `--replace` | Replace settings with only the flags provided. Omitted settings revert to server defaults. | boolean | `false` | No | | `--server-cors-allowed-origins` | CORS allowed origins | string | — | No | | `--server-timing-enabled` | Enable Server-Timing response headers | boolean | — | No | | `--branch` | Branch ID or name | string | — | No | | `--database` | Database name | string | — | No | | `--project-id` | Project ID | string | — | No | `update` requires at least one [settings flag](https://neon.com/docs/cli/data-api#settings-flags). To refresh the schema cache without changing settings, use [`refresh-schema`](https://neon.com/docs/cli/data-api#refresh-schema) instead. ```bash neon data-api update --database neondb --db-max-rows 1000 ``` ## neon data-api refresh-schema Refreshes the Data API schema cache without changing settings. ```bash neon data-api refresh-schema [options] ``` | Option | Description | Type | Default | Required | | -------------- | ----------------- | ------ | ------- | :------: | | `--branch` | Branch ID or name | string | — | No | | `--database` | Database name | string | — | No | | `--project-id` | Project ID | string | — | No | ```bash neon data-api refresh-schema --database neondb ``` ## neon data-api delete Deletes the Neon Data API for a database. ```bash neon data-api delete [options] ``` | Option | Description | Type | Default | Required | | -------------- | ----------------- | ------ | ------- | :------: | | `--branch` | Branch ID or name | string | — | No | | `--database` | Database name | string | — | No | | `--project-id` | Project ID | string | — | No | ```bash neon data-api delete --database neondb ``` --- [Document source](https://neon.com/docs/cli/databases.md) --- > Summary: The Neon CLI `databases` command lists, creates, and deletes Postgres databases within a Neon project branch directly from the terminal. Use `neon databases create --name --owner-name ` to provision a database on a named branch, or omit `--branch` to target the project's default branch. Each subcommand accepts `--project-id` (required only for accounts with multiple projects) and `--context-file` for reusable context. # Neon CLI command: databases List, create, and delete databases in a Neon project Last updated: 2026-11-05 The `databases` command lists, creates, and deletes databases in a Neon project from the terminal. It's also available as [`neon postgres databases`](https://neon.com/docs/cli/postgres#databases). For information about databases in Neon, see [Manage databases](https://neon.com/docs/manage/databases). If `--project-id` is omitted, the CLI resolves it from your [context file](https://neon.com/docs/cli/link), auto-selects when your account has only one project, and otherwise asks you to pass `--project-id`. Subcommands: [create](https://neon.com/docs/cli/databases#create), [delete](https://neon.com/docs/cli/databases#delete), [list](https://neon.com/docs/cli/databases#list) ## neon databases list Lists databases. If you don't specify a branch ID or name with `--branch`, the command targets the project's default branch. This applies to all `databases` subcommands. ```bash neon databases list [options] ``` | Option | Description | Type | Default | Required | | -------------- | ----------------- | ------ | ------- | :------: | | `--branch` | Branch ID or name | string | — | No | | `--project-id` | Project ID | string | — | No | ```bash neon databases list ``` ```text filename="Output" Databases on main Name Owner Name Created At neondb neondb_owner 2026-06-19T18:27:19Z ``` The table is titled with the branch the databases belong to. Pass `--branch ` to list another branch's databases. ## neon databases create Creates a database. If you don't specify `--owner-name`, the current user becomes the database owner. ```bash neon databases create [options] ``` | Option | Description | Type | Default | Required | | -------------- | ----------------- | ------ | ------- | :------: | | `--name` | Database name | string | — | Yes | | `--owner-name` | Owner name | string | — | No | | `--branch` | Branch ID or name | string | — | No | | `--project-id` | Project ID | string | — | No | ```bash neon databases create --name mynewdb --owner-name alex ``` ```text filename="Output" Database created on main Name mynewdb Owner Name alex Created At 2026-06-19T23:45:45Z ``` ## neon databases delete Deletes a database. The `` is the database name. ```bash neon databases delete [options] ``` | Option | Description | Type | Default | Required | | -------------- | ----------------- | ------ | ------- | :------: | | `--branch` | Branch ID or name | string | — | No | | `--project-id` | Project ID | string | — | No | ```bash neon databases delete mydb ``` ```text filename="Output" Database deleted from main Name mydb Owner Name neondb_owner Created At 2026-06-19T23:45:45Z ``` --- [Document source](https://neon.com/docs/cli/deploy.md) --- > Summary: The Neon CLI `neon deploy` command applies a neon.ts policy to a branch. It is a top-level alias of `neon config apply` with the same options, so you can reconcile a branch without the `config` prefix. # Neon CLI command: deploy Apply a neon.ts policy to a branch Last updated: 2026-10-15 The `deploy` command applies a `neon.ts` policy to a branch. It is a top-level alias of [`neon config apply`](https://neon.com/docs/cli/config#apply), with the same options. ```bash neon deploy [options] ``` | Option | Description | Type | Default | Required | | ------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------- | ------- | :------: | | `--allow-protected` | Apply to a branch marked protected on Neon without asking | boolean | `false` | No | | `--branch` | Branch ID or name | string | — | No | | `--config` | Path to a neon.ts policy (defaults to the neon.ts next to .neon, or in cwd without one) | string | — | No | | `--env` | Path to a .env file to load into the environment before evaluating neon.ts so Function env values resolve from it. Existing env vars are not overridden. Function env values that read process.env must be set in this file or the environment. | string | — | No | | `--env-pull` | Pull the branch's Neon env vars (DATABASE\_URL, …) into a local .env after a successful apply. On by default; use --no-env-pull to skip (e.g. when injecting env at runtime with `neon-env run` / `neon dev`). | boolean | `true` | No | | `--project-id` | Project ID | string | — | No | | `--update-existing` | Override branch settings that differ from neon.ts without asking | boolean | `false` | No | | `--yes`, `-y` | Answer yes to every confirmation: --update-existing and --allow-protected | boolean | `false` | No | In a terminal, `deploy` asks before it overrides branch settings that differ from `neon.ts` or applies to a branch marked protected on Neon. Declining applies nothing. If `neon.ts` declares [Realtime](https://neon.com/docs/cli/realtime) under `preview.realtime`, `neon deploy` enables it on the branch, and the default env pull waits until it's ready and writes `NEON_REALTIME_URL` and `NEON_REALTIME_SECRET`. Without a terminal, there's no prompt. This covers CI, runs with no TTY, and `-o json` or `-o yaml` output. In those cases, `deploy` stops before changing anything and names the flag to re-run with. For scripts, CI, and agents, pass `--update-existing` to allow the overrides, `--allow-protected` to allow a protected branch, or `-y` for both: ```bash neon deploy --branch feature/auth -y ``` --- [Document source](https://neon.com/docs/cli/dev.md) --- > Summary: The Neon CLI `neon dev` command runs Neon Functions locally with a dev server and hot reload. Pass --source to serve a single function entry module (optionally with --port for an explicit port), or omit --source to serve every function declared in neon.ts, each on its own dev server. # Neon CLI command: dev Run Neon Functions locally with a dev server Last updated: 2026-10-15 The `dev` command runs [Neon Functions](https://neon.com/docs/compute/functions/overview) locally with a dev server and hot reload. Serve one function from its entry module, or every function declared in your `neon.ts` policy. ## Usage ```bash neon dev [--source ] [options] ``` ## Options | Option | Description | Type | Default | Required | | ---------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------ | ------- | :------: | | `--env` | Path to a .env file to load into the environment before evaluating neon.ts so Function env values resolve from it. Existing env vars are not overridden. Function env values that read process.env must be set in this file or the environment. | string | — | No | | `--port` | Port to listen on (single-function mode only, with --source). Fails if taken. Without it (and without a PORT env var) a free port is chosen automatically. | number | — | No | | `--source` | Path to a single function entry module. Omit to serve every function declared in neon.ts. | string | — | No | ## Examples Serve one function on a free port with hot reload: ```bash neon dev --source ./functions/hello.ts ``` Serve every function declared in `neon.ts` (one dev server each): ```bash neon dev ``` Serve one function on an explicit port (fails if the port is taken): ```bash neon dev --source ./functions/hello.ts --port 3000 ``` ## Environment variables Before evaluating `neon.ts`, `neon dev` loads your project's `.env` and then `.env.local` into the environment. Values in `.env.local` override `.env`, and a variable already set in your shell wins over both. This lets function `env` values that read `process.env` resolve locally the same way they do for [`neon deploy --env`](https://neon.com/docs/cli/deploy). Pass `--env` to load only one file instead, resolved from the current directory: ```bash neon dev --env .env.staging ``` Local functions inherit every loaded variable, including ones `neon.ts` doesn't declare. A deployed function only gets the variables `neon.ts` declares plus the ones Neon injects, so check that anything your code needs is declared before you deploy. The dev server's startup banner lists which env files it loaded and how many variables each one set. `neon dev` never writes to these files. To reuse the branch credential behind the AI Gateway and Object Storage, it reads the file [`neon env pull`](https://neon.com/docs/cli/env) writes. Without that file, it resolves the credential again on every start, so run `neon env pull` once if you restart often. ## WebSockets `neon dev` serves WebSocket upgrades locally, so you can test real-time functions before you deploy. Connect a client to the dev server's `ws://localhost:` URL. See [WebSockets and SSE](https://neon.com/docs/compute/functions/websockets) for the function-side code. --- [Document source](https://neon.com/docs/cli/diff.md) --- > Summary: The Neon CLI `diff` command prints a git-style schema diff between two branches: the branch under review (the `+++` side) and the branch you compare against (the `---` side). Use this reference for the exact positional argument and flags: set the branch under review with `--branch`, the branch to compare against with the `compare-branch` positional, limit output to one database with `--database`, and target a project with `--project-id`. # Neon CLI command: diff Show a git-style schema diff between two branches Last updated: 2026-10-09 The `diff` command shows a git-style schema diff between two branches, in the same unified diff format `git diff` produces. The branch under review is the `+++` side; the branch you compare against is the `---` side. Omit the `compare-branch` argument to diff against the reviewed branch's parent, which answers "what did I change since branching?". See [Schema diff](https://neon.com/docs/guides/schema-diff) for more on comparing schemas in Neon. The `+++` branch comes from `--branch`, or the branch pinned in your [`.neon` context file](https://neon.com/docs/cli/link), or the project's default branch, in that order. `diff` covers every database on that branch unless you pass `--database`. Use `--output json` or `--output yaml` for a machine-readable diff, one entry per database. `neon diff` is a shortcut for comparing branch schemas. To compare against a historical point in time (by timestamp or LSN), use the [`neon branches schema-diff`](https://neon.com/docs/cli/branches#schema-diff) subcommand. ## Usage ```bash neon diff [compare-branch] [options] ``` ## Options | Option | Description | Type | Default | Required | | -------------------- | -------------------------------------------------------------------------------------------------- | ------ | ------- | :------: | | `--branch`, `-b` | The branch to review (the '+++' side). Defaults to the branch pinned in the local context (.neon). | string | — | No | | `--database`, `--db` | Limit the diff to a single database. Defaults to every database on the current branch. | string | — | No | | `--project-id` | Project ID | string | — | No | ## Examples Diff the branch pinned in your `.neon` context against its parent. This works only when the pinned branch has a parent; against the project's default branch it errors, since there's nothing above it to compare: ```bash neon diff ``` Diff the reviewed branch's schema against the `main` branch: ```bash neon diff main ``` ## Example output Say your `feature/checkout` branch adds a `discount_code` column to the `orders` table and a new `coupons` table on top of `main`. Diff it against `main` with `--branch`, which reviews an explicit branch regardless of your `.neon` context: ```bash neon diff main --branch feature/checkout ``` ```diff filename="Output" → Comparing schema main → feature/checkout diff --neon database neondb --- main (br-solitary-block-atxzqx8a) +++ feature/checkout (br-wandering-bar-atq2lw6c) @@ -22,6 +22,19 @@ SET default_table_access_method = heap; -- +-- Name: coupons; Type: TABLE; Schema: public; Owner: neondb_owner +-- + +CREATE TABLE public.coupons ( + code text NOT NULL, + percent_off integer NOT NULL, + expires_at timestamp with time zone +); + + +ALTER TABLE public.coupons OWNER TO neondb_owner; + +-- -- Name: orders; Type: TABLE; Schema: public; Owner: neondb_owner -- @@ -29,7 +42,8 @@ id integer NOT NULL, customer_id integer NOT NULL, total numeric(10,2) NOT NULL, - created_at timestamp with time zone DEFAULT now() + created_at timestamp with time zone DEFAULT now(), + discount_code text ); ``` Each branch's schema is dumped as `pg_dump --schema-only` SQL and the two dumps are compared, so the diff includes generated lines you didn't write directly, such as `-- Name: ...` comments and `ALTER TABLE ... OWNER TO` statements. Lines prefixed with `+` exist only on the branch under review; `-` lines exist only on the compare branch. If the schemas match, `diff` reports no differences instead. --- [Document source](https://neon.com/docs/cli/docs.md) --- > Summary: The Neon CLI `docs` command searches neon.com from your terminal: the docs, API reference, PostgreSQL tutorial, guides, FAQs, changelog, and blog. It needs no login; use `--category` to narrow results and `--output json` for machine-readable output when scripting or calling it from an agent. # Neon CLI command: docs Search the Neon docs, guides, and more from the terminal Last updated: 2026-10-22 The `docs` command searches neon.com and prints matching pages in your terminal. It covers the docs, API reference, PostgreSQL tutorial, guides, FAQs, changelog, and blog. No login is required, and it doesn't touch your projects or account. To get a written answer instead of a list of pages, use [`neon ask`](https://neon.com/docs/cli/ask). Subcommands: [search](https://neon.com/docs/cli/docs#search) ## neon docs search Searches neon.com and lists the matching pages. ```bash neon docs search [options] ``` | Option | Description | Type | Default | Required | | ------------ | -------------------------------------------------------------------------------------------------------------------------------------- | ------ | ------- | :------: | | `--category` | Only return pages in these categories (repeatable) Possible values: `docs`, `api`, `postgresql`, `guides`, `faqs`, `blog`, `changelog` | array | — | No | | `--limit` | Maximum number of results (1-40) | number | `10` | No | By default, each result shows the page title and matching section, with the URL on the next line. Long title lines are cut to fit your terminal; URLs never are. `--output json` and `--output yaml` also include each result's `category`, `breadcrumb`, and a short `excerpt` of the matching text. To search more than one category, repeat `--category`. Search for a topic: ```bash neon docs search "reset a branch" ``` Search only the API reference and the docs, and return the top three results: ```bash neon docs search "create branch" --category api --category docs --limit 3 ``` ```text Manage branches ' Branching with the Neon API ' Create a branch with the API https://neon.com/docs/manage/branches Neon CLI command: branches ' neon branches create https://neon.com/docs/cli/branches Neon CLI quickstart ' Common operations ' Create a branch https://neon.com/docs/cli/quickstart ``` Get results as JSON so you can process them in a script: ```bash neon docs search "reset a branch" --limit 2 --output json ```
Show output ```json [ { "title": "Manage branches", "url": "https://neon.com/docs/manage/branches", "category": "docs", "breadcrumb": ["Docs", "Manage & operate", "Projects & resources"], "heading": "Manage branches > Reset a branch from parent", "excerpt": "You can use Neon's Reset from parent feature to instantly update a branch with the latest schema and data from its parent. This feature can be an integral part of your CI/CD automation. You can use the Neon Console, CLI, or API. For details, see Reset from parent." }, { "title": "Branching with the Neon CLI", "url": "https://neon.com/docs/guides/branching-neon-cli", "category": "docs", "breadcrumb": ["Docs", "Postgres", "Branching", "Automate & workflows"], "heading": "Branching with the Neon CLI > Resetting a branch from its parent", "excerpt": "Depending on your development workflow, you might need to periodically reset a branch to match the latest state of its parent. This is useful, for example, when resetting a development branch back to the production branch before starting work on a new feature. Use the followin..." } ] ```
--- [Document source](https://neon.com/docs/cli/env.md) --- > Summary: The Neon CLI `neon env pull` command writes a branch's Neon environment variables to a local .env file. By default it targets an existing .env file, otherwise .env.local, and only Neon-managed variables are rewritten; other lines in the file are preserved. Use --file to target a specific file, --branch to pull from a specific branch, and --service to pull only selected services. # Neon CLI command: env Manage a branch's Neon environment variables locally Last updated: 2026-10-15 The `env` command manages a branch's Neon environment variables locally. [`neon link`](https://neon.com/docs/cli/link) and [`neon checkout`](https://neon.com/docs/cli/checkout) pull env variables automatically by default. Subcommands: [pull](https://neon.com/docs/cli/env#pull) ## neon env pull Writes the branch's Neon environment variables to a local `.env` file. `neon env pull` works with or without a [`neon.ts`](https://neon.com/docs/reference/neon-ts) configuration file. Without one, it writes everything the branch has: the core variables (`DATABASE_URL`, `DATABASE_URL_UNPOOLED`, `NEON_BRANCH`, `NEON_BRANCH_ID`), credentials for each service provisioned on the branch, and the default AI Gateway credential. With a `neon.ts`, it writes the core variables plus credentials for each service you declare (Managed Better Auth, Data API, AI Gateway, Object Storage, [Realtime](https://neon.com/docs/cli/realtime)). It also writes `NEON_FUNCTION_HOST_SUFFIX`. Neon injects it and `NEON_BRANCH_ID` into every deployed [Neon Function](https://neon.com/docs/compute/functions/overview). Together they make up any function's URL on the branch: `https://-`. To build that URL in code, use [`functionBaseUrl("")`](https://neon.com/docs/compute/functions/environment-variables#call-another-function) from `@neon/env`. A pull without `--service` writes the suffix whether or not your `neon.ts` declares functions, and the function doesn't have to be deployed yet. `--service functions` writes only `NEON_BRANCH`, `NEON_BRANCH_ID`, and `NEON_FUNCTION_HOST_SUFFIX`. Neon CLI 9.0.0 replaced the per-function `NEON_FUNCTION__BASE_URL` variables that earlier releases wrote. A pull without `--service`, or with `--service functions`, removes those old lines, and `--env NEON_FUNCTION__BASE_URL` fails with an error that points you to `functionBaseUrl`. To update code that read those variables, see [Call another function](https://neon.com/docs/compute/functions/environment-variables#call-another-function). Unset function env vars don't block a pull. If a declared function reads a `process.env.*` value that isn't set, `neon env pull` (and the pull that [`neon link`](https://neon.com/docs/cli/link) and [`neon checkout`](https://neon.com/docs/cli/checkout) run) skips that value and writes everything else instead of failing. The commands that actually build or run your functions still require every declared value: `neon deploy`, `neon dev`, and `neon-env run`. ```bash neon env pull [options] ``` | Option | Description | Type | Default | Required | | ------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------ | ------- | :------: | | `--config` | Path to a neon.ts policy (defaults to the neon.ts next to .neon, or in cwd without one) | string | — | No | | `--env`, `-e` | | array | — | No | | `--file` | Target .env file to write, relative to cwd. Defaults to an existing .env, otherwise .env.local, in the project directory (next to .neon, or cwd without one). Only Neon variables are updated; other lines are preserved. | string | — | No | | `--service`, `-s`, `--services` | Pull only these services' variables: postgres, auth, data-api, functions, object-storage, ai-gateway, realtime. Repeat the flag or comma-separate. Overrides neon.ts, and prunes only within the services you name. Combines with --env as a union. | array | — | No | | `--branch` | Branch ID or name | string | — | No | | `--project-id` | Project ID | string | — | No | Write the linked branch's Neon variables into `.env.local` (or `.env` if present): ```bash neon env pull ``` Pull a specific branch into a specific file: ```bash neon env pull --branch preview --file .env.preview ``` Pull only the variables for the services you name, ignoring `neon.ts`. Repeat `--service` or comma-separate the values (`postgres`, `auth`, `data-api`, `functions`, `object-storage`, `ai-gateway`, `realtime`): ```bash neon env pull --service ai-gateway --service postgres ``` For [Realtime](https://neon.com/docs/realtime/overview), the pull writes `NEON_REALTIME_URL` and `NEON_REALTIME_SECRET`. With `--service realtime`, if Realtime is still provisioning on the branch (for example, right after [`neon realtime enable`](https://neon.com/docs/cli/realtime#enable)) or [rotating its secret](https://neon.com/docs/cli/realtime#rotate-secret), the pull waits until it's ready. `--service realtime` on its own doesn't write `DATABASE_URL`, so name `postgres` too when you need both: ```bash neon env pull --service postgres --service realtime ``` Use a specific `neon.ts` policy instead of the one in the project directory (next to the nearest `.neon`, or the current directory when there's no `.neon`): ```bash neon env pull --config ./config/neon.ts ``` --- [Document source](https://neon.com/docs/cli/feedback.md) --- > Summary: The Neon CLI `feedback` command sends a short message to the Neon team without leaving your terminal. Pass your note with `--message`. It needs no login and doesn't touch your projects or account. Don't include passwords, API keys, connection strings, or other personal information. # Neon CLI command: feedback Send feedback about the Neon CLI and docs to the Neon team Last updated: 2026-10-10 The `feedback` command sends a short message to the Neon team from the terminal: `neon feedback --message ""`. Use it to report a confusing command, a docs gap, or anything else about the CLI you'd like the team to see. To ask the Neon assistant a question instead, use [`neon ask`](https://neon.com/docs/cli/ask). No login is required, and the command doesn't read or change your projects or account. Don't put passwords, API keys, connection strings, or other personal information in the message. The `feedback` command requires Neon CLI version 8.0.2 or later. Run `neon --version` to check your version, and [upgrade the CLI](https://neon.com/docs/cli/install#upgrade) if needed. For other ways to reach the Neon team, see [Send feedback](https://neon.com/docs/introduction/feedback). ## Usage ```bash neon feedback --message ``` Pass your note with `--message`. It's the only required option. ## Options | Option | Description | Type | Default | Required | | ----------- | ------------------------------------------------------------------------------- | ------ | ------- | :------: | | `--message` | The feedback to send. Do not include passwords, API keys, or connection strings | string | — | Yes | ## Examples ```bash neon feedback --message "The branch docs were unclear about default branch names" ``` ```text filename="Output" Feedback received. Thank you! ``` --- [Document source](https://neon.com/docs/cli/functions.md) --- > Summary: The Neon CLI `neon functions` command manages Neon Functions on a branch: create functions from Function Registry templates, deploy, list, get, and delete functions, and register and manage their custom domains with the `domains` subcommands. # Neon CLI command: functions Create, deploy, list, inspect, and delete Neon Functions, and manage their custom domains Last updated: 2026-10-26 The `functions` command manages [Neon Functions](https://neon.com/docs/compute/functions/overview) on a branch. This is the command reference; for the full deployment workflow, see [Deploy functions](https://neon.com/docs/compute/functions/deploy). To run functions locally, see [`neon dev`](https://neon.com/docs/cli/dev). To add a function from a template, see [Use function templates](https://neon.com/docs/compute/functions/templates). Subcommands: [delete](https://neon.com/docs/cli/functions#delete), [deploy](https://neon.com/docs/cli/functions#deploy), [domains](https://neon.com/docs/cli/functions#domains), [get](https://neon.com/docs/cli/functions#get), [list](https://neon.com/docs/cli/functions#list), [new](https://neon.com/docs/cli/functions#new), [templates](https://neon.com/docs/cli/functions#templates) ## neon functions new Creates a function from a [Function Registry template](https://neon.com/functions/templates). It writes the template's files to `functions//` and declares the function in `neon.ts`, creating the file if needed. It doesn't need a project or a signed-in session. Requires the Neon CLI 8.11.0 or later. ```bash neon functions new [template] [options] ``` | Option | Description | Type | Default | Required | | -------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------- | ------- | :------: | | `--add-to-config` | Declare the function in neon.ts, creating it when missing. On by default; use --no-add-to-config to skip. | boolean | — | No | | `--all-operations` | Include every operation. Conflicts with --operation. | boolean | — | No | | `--config` | Path to the neon.ts to edit (defaults to the neon.ts next to .neon, or in cwd without one; created there when missing) | string | — | No | | `--dir` | Destination directory (defaults to functions/\ next to neon.ts) | string | — | No | | `--force` | Overwrite differing files and keep an existing neon.ts declaration | boolean | — | No | | `--install` | Install the template's dependencies, plus @neon/config and @neon/env when neon.ts is created. A TTY asks when omitted, --yes installs, and anything else leaves the install command in Next. | boolean | — | No | | `--operation` | Operation to include (repeatable). Without it, a TTY asks and anything else uses the recommended operations. | array | — | No | | `--slug` | Function slug, also used as the directory name. A separate template keeps its own slugs and uses this only for the directory. Defaults to the template ID | string | — | No | | `--yes`, `-y`, `--default` | Skip prompts: use the recommended operations and install dependencies | boolean | — | No | | `--branch` | Branch ID or name | string | — | No | | `--project-id` | Project ID | string | — | No | By default, the slug is the template ID with everything except lowercase letters and digits removed, so `neon functions new context-dev` writes to `functions/contextdev/`. A `router` template becomes one function, with a generated `index.ts` that routes each URL path to an operation. A `separate` template declares one function per operation under slugs the template sets, so `--slug` only renames the directory. If the template needs environment variables, the command declares them in `neon.ts` and adds their names, without values, to `.env.example`. Set the values in `.env.local`, which `neon dev` loads automatically, and deploy with `neon deploy --env .env.local`. The `Next:` list may print `neon config apply` instead, which does the same thing as `neon deploy`. Create a function from the `basic` template: ```bash neon functions new basic --no-install ``` ```text filename="Output" Fetching template "basic" from the Function Registry… Function created. ----------------- Template Basic function (Neon) Function basic Directory functions/basic Config neon.ts created: added functions.basic Dependencies not installed Next: npm install @neon/config @neon/env neon dev neon config apply ``` Use your own slug and skip `neon.ts`: ```bash neon functions new basic --slug hello --no-add-to-config ``` ```text filename="Output" Fetching template "basic" from the Function Registry… Function created. ----------------- Template Basic function (Neon) Function hello Directory functions/hello Config not added Next: neon dev --source functions/hello/index.ts neon functions deploy hello --src functions/hello/index.ts ``` Templates live in [`registry/`](https://github.com/neondatabase/examples/tree/main/registry) in `neondatabase/examples`. Set `NEON_FUNCTION_REGISTRY_DIR` to a local copy of that directory to install templates you're developing. See [Test a template locally](https://neon.com/docs/compute/functions/registry#test-your-template-locally). ## neon functions templates Browse the templates at [neon.com/functions/templates](https://neon.com/functions/templates). For the end-to-end workflow, see [Use function templates](https://neon.com/docs/compute/functions/templates). The live catalog is [registry.json](https://neon.com/functions/registry/registry.json). To contribute your own, see [Contribute a function template](https://neon.com/docs/compute/functions/registry). Subcommands: [list](https://neon.com/docs/cli/functions#templates-list) ### neon functions templates list Lists the templates you can pass to [`neon functions new`](https://neon.com/docs/cli/functions#new). ```bash neon functions templates list [options] ``` | Option | Description | Type | Default | Required | | -------------- | ----------------- | ------ | ------- | :------: | | `--branch` | Branch ID or name | string | — | No | | `--project-id` | Project ID | string | — | No | ```bash neon functions templates list ``` ```text filename="Output" ID Title Provider Description basic Basic function Neon A minimal Neon Function with a JSON response. context-dev Context.dev web data Context.dev Search the web and news, read pages, answer questions, and retrieve brand data with Context.dev. ``` ## neon functions deploy Deploys a function from a local directory or entry file. The `` is the permanent function identifier: 1 to 20 lowercase letters and digits (`^[a-z0-9]{1,20}$`). ```bash neon functions deploy [options] ``` | Option | Description | Type | Default | Required | | -------------- | ---------------------------------------------------------------------------------------------------------------------------------------- | ------- | ------- | :------: | | `--bundle` | Bundle --src with esbuild. Use --no-bundle to zip a prebuilt directory (root must contain index.mjs or index.js) or a file of that name. | boolean | `true` | No | | `--env` | Environment variable as KEY=VALUE (repeatable) | array | — | No | | `--runtime` | Function runtime Possible values: `nodejs24` | string | — | No | | `--src` | Function source: a directory containing index.ts, index.js, or index.mjs (first file match is the entry), or a path to the entry file | string | — | No | | `--wait` | Wait for the deployment to finish building | boolean | `true` | No | | `--branch` | Branch ID or name | string | — | No | | `--project-id` | Project ID | string | — | No | By default, `deploy` waits until the deployment finishes building (`--wait=true`), which is the predictable path for scripts and CI. Use `--no-wait` to return immediately after triggering the deployment. By default, `deploy` bundles your `--src` with esbuild before uploading. Pass `--no-bundle` to skip bundling and deploy a prebuilt source instead: the directory root (or the file you point at) must be named or contain `index.mjs` or `index.js`. This is useful when you run your own build step and want to ship the output as-is. Deploy a function from an entry file: ```bash neon functions deploy hello --src functions/hello.ts ``` ```text filename="Output" Function deployment triggered for function hello. Function hello URL https://br-cool-darkness-123456-hello.compute.c-1.us-east-2.aws.neon.tech/ Deployment ID 1 Status completed Runtime nodejs24 Memory 2048 MiB Created At 2026-06-12T00:14:58.044690Z ``` Deploy with environment variables and wait for the build: ```bash neon functions deploy hello --src functions/hello.ts --env LOG_LEVEL=info --wait ``` ## neon functions list Lists the functions on the branch. ```bash neon functions list [options] ``` | Option | Description | Type | Default | Required | | -------------- | ----------------- | ------ | ------- | :------: | | `--branch` | Branch ID or name | string | — | No | | `--project-id` | Project ID | string | — | No | ```bash neon functions list ``` ```text filename="Output" Slug Name Status URL Created At hello hello completed https://br-cool-darkness-123456-hello.compute.c-1.us-east-2.aws.neon.tech/ 2026-06-12T00:14:57.942988Z ``` List with full deployment details for scripts and agents: ```bash neon functions list --output json ```
Show output ```json [ { "id": "hello", "slug": "hello", "name": "hello", "invocation_url": "https://br-cool-darkness-123456-hello.compute.c-1.us-east-2.aws.neon.tech/", "current_deployment": { "id": 1, "status": "completed", "memory_mib": 2048, "runtime": "nodejs24", "created_at": "2026-06-12T00:14:58.044690Z" }, "active_deployment": { "id": 1, "status": "completed", "memory_mib": 2048, "runtime": "nodejs24", "created_at": "2026-06-12T00:14:58.044690Z" }, "created_at": "2026-06-12T00:14:57.942988Z" } ] ```
## neon functions get Shows a function's details. ```bash neon functions get [options] ``` | Option | Description | Type | Default | Required | | ---------------------------- | ------------------------------------------------------------ | ------- | ------- | :------: | | `--list-env-variables`, `-E` | List the environment variable names of the active deployment | boolean | `false` | No | | `--branch` | Branch ID or name | string | — | No | | `--project-id` | Project ID | string | — | No | ```bash neon functions get hello ``` ```text filename="Output" Function Slug hello Name hello URL https://br-cool-darkness-123456-hello.compute.c-1.us-east-2.aws.neon.tech/ Created At 2026-06-12T00:14:57.942988Z Deployment (current, active) Deployment ID 1 Status completed Runtime nodejs24 Memory 2048 MiB Created At 2026-06-12T00:14:58.044690Z ``` ## neon functions delete Deletes a function on the branch. ```bash neon functions delete [options] ``` | Option | Description | Type | Default | Required | | -------------- | ----------------- | ------ | ------- | :------: | | `--branch` | Branch ID or name | string | — | No | | `--project-id` | Project ID | string | — | No | ```bash neon functions delete hello ``` ```text filename="Output" Function hello deleted from branch br-cool-darkness-123456 ``` ## neon functions domains Manage custom domains for functions on the branch. Subcommands: [delete](https://neon.com/docs/cli/functions#domains-delete), [list](https://neon.com/docs/cli/functions#domains-list), [register](https://neon.com/docs/cli/functions#domains-register) ### neon functions domains list Lists the custom domains registered on the branch. ```bash neon functions domains list [options] ``` | Option | Description | Type | Default | Required | | -------------- | ----------------- | ------ | ------- | :------: | | `--branch` | Branch ID or name | string | — | No | | `--project-id` | Project ID | string | — | No | ```bash neon functions domains list ``` The default table shows the domain, target function, and CNAME target. To inspect DNS and routing status, use JSON output: ```bash neon functions domains list --output json ``` ```json filename="Output" [ { "domain": "docs.example.com", "entity_type": "function", "entity_id": "hello", "cname_target": "fn-custom-domains.us-east-2.aws.neon.tech", "status": "active", "dns_status": "ok", "binding_status": "present", "status_reason": "" } ] ``` An `active` status confirms that DNS, CAA authorization, and routing are ready. Verify the domain with an HTTPS request because certificate issuance isn't included in this status. ### neon functions domains register Points a domain you already own at a function on the branch. Both `--slug` and the domain are required. The command prints a CNAME target; create a CNAME record for the domain at your DNS provider pointing at that target. See [Custom domains](https://neon.com/docs/compute/functions/custom-domains) for DNS, CAA, and TLS details. ```bash neon functions domains register [options] ``` | Option | Description | Type | Default | Required | | -------------- | ----------------------------------------- | ------ | ------- | :------: | | `--slug` | Function slug this domain should point at | string | — | Yes | | `--branch` | Branch ID or name | string | — | No | | `--project-id` | Project ID | string | — | No | ```bash neon functions domains register docs.example.com --slug hello ``` ### neon functions domains delete Deletes a custom domain from the branch. ```bash neon functions domains delete [options] ``` | Option | Description | Type | Default | Required | | -------------- | ----------------- | ------ | ------- | :------: | | `--branch` | Branch ID or name | string | — | No | | `--project-id` | Project ID | string | — | No | ```bash neon functions domains delete docs.example.com ``` Routing changes are eventually consistent, so the custom URL can continue reaching the function briefly after deletion. Deleting a function doesn't delete its custom-domain registration; delete the domain separately. --- [Document source](https://neon.com/docs/cli/git.md) --- > Summary: The Neon CLI `git` command connects git branch switches to Neon checkout. It installs a git post-checkout hook so that switching git branches checks out the mapped Neon branch, with subcommands to install and remove the hook (install, uninstall), run the sync by hand (sync), inspect the current state (status), and prune stale branch mappings (cleanup). # Neon CLI command: git Keep your Neon branch in sync with the git branch you have checked out Last updated: 2026-10-07 The `git` command connects your git workflow to Neon branching. After you install its git hook, switching git branches with `git checkout` also checks out the Neon branch mapped to that git branch, so your application code and its database branch stay in sync. Under the hood it delegates to [`neon checkout`](https://neon.com/docs/cli/checkout) and records the git-to-Neon mapping in your local [context file](https://neon.com/docs/cli/link). **Coming soon: Preview** The `neon git` command group is in preview. The commands and their behavior may change. Before you install the hook, link a Neon project at your repository root with [`neon link`](https://neon.com/docs/cli/link) or [`neon checkout`](https://neon.com/docs/cli/checkout). The hook reads the `.neon` context file at the repository root, so the project link has to live there. Subcommands: [cleanup](https://neon.com/docs/cli/git#cleanup), [install](https://neon.com/docs/cli/git#install), [status](https://neon.com/docs/cli/git#status), [sync](https://neon.com/docs/cli/git#sync), [uninstall](https://neon.com/docs/cli/git#uninstall) ## neon git install Installs a managed `post-checkout` git hook that runs `neon git sync` whenever you switch branches with `git checkout`. The hook honors your configured git hooks directory and won't overwrite an existing unmanaged `post-checkout` hook. The command requires a project already linked at the repository root's own `.neon` file. If none is linked, install stops and tells you to run `neon link` or `neon checkout ` there first. ```bash neon git install [options] ``` ```bash neon git install ``` ```text filename="Output" Git → Neon sync installed. `git checkout ` will now check out the mapped Neon branch. Hook: /path/to/your/app/.git/hooks/post-checkout ``` ## neon git status Shows your current git branch, whether the hook is installed, whether sync-on-checkout is enabled, the Neon branch mapped to the current git branch, and all recorded mappings. Use `--output json` or `--output yaml` for scripting. ```bash neon git status [options] ``` ```bash neon git status ``` ```text filename="Output" GitBranch main HookInstalled false FollowOnCheckout false MappedNeonBranch (unmapped — will derive on next sync) Mappings (none) ``` ## neon git sync Checks out the Neon branch mapped to the current git branch. This is the command the installed hook runs on every `git checkout`, and you can also run it by hand. If no mapping exists yet, sync derives a Neon branch name from the current git branch and checks it out, then saves the resulting mapping so later checkouts of that git branch stay stable. The Neon branch has to exist already: sync doesn't create it, so a git branch with no matching Neon branch reports `Branch not found. Pass --create to create it.` unless a `checkout.before` hook maps it to an existing branch. A detached HEAD has no git branch, so sync skips it. Pass `--pull` to run `git pull --ff-only` before syncing, so committed files such as migrations match the branch before any `checkout.after` hook runs. A pull failure warns and sync continues. Pass `--no-env-pull` to skip pulling the branch's Neon environment variables into a local `.env` after sync. ```bash neon git sync [options] ``` | Option | Description | Type | Default | Required | | ------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------- | ------- | :------: | | `--env-pull` | Pull the branch's Neon env vars into a local .env after sync. On by default. | boolean | `true` | No | | `--pull` | Run `git pull --ff-only` before syncing so local files (incl. migration files) match the branch before any checkout.after migration runs. Without the flag, prompts when run manually in a TTY and skips in the hook / CI. | boolean | — | No | | `--quiet` | Suppress sync's own routine status lines (git pull result, detached HEAD notice). Warnings and the delegated checkout's own output are unaffected. Used by the installed git hook. | boolean | `false` | No | ```bash neon git sync --no-pull ``` ```text filename="Output" Checked out branch br-billing-a1b2c3d4 on project polished-snowflake-12345678 (org org-example-12345678). Updated /path/to/your/app/.neon. Pulled 5 Neon variables into .env.local Postgres DATABASE_URL, DATABASE_URL_UNPOOLED Branch NEON_BRANCH, NEON_BRANCH_ID Functions NEON_FUNCTION_HOST_SUFFIX ``` ## neon git cleanup Removes git-to-Neon mappings whose local git branch no longer exists. By default it only prunes the mappings. Add `--prune-neon-branches` to also delete the orphaned Neon branches, which never touches the default or a protected branch. Deleting Neon branches prompts for confirmation unless you pass `--yes`. ```bash neon git cleanup [options] ``` | Option | Description | Type | Default | Required | | ----------------------- | --------------------------------------------------------------------------------- | ------- | ------- | :------: | | `--prune-neon-branches` | Also delete the orphaned Neon branches (never the default or a protected branch). | boolean | `false` | No | | `--yes` | Skip the confirmation prompt before deleting Neon branches. | boolean | `false` | No | Prune stale mappings only: ```bash neon git cleanup ``` ```text filename="Output" Pruned 1 stale mapping(s) from .neon: feature/billing → feature/billing These Neon branch(es) are no longer mapped and were not deleted: feature/billing. Delete them with `neon branches delete `, or run `neon git cleanup --prune-neon-branches` next time before a mapping-only cleanup. ``` Prune stale mappings and delete their Neon branches without a prompt: ```bash neon git cleanup --prune-neon-branches --yes ``` ## neon git uninstall Removes the managed `post-checkout` hook installed by `neon git install` and turns off sync-on-checkout. If the `post-checkout` hook isn't the one Neon manages, uninstall leaves it in place and only clears the sync flag. ```bash neon git uninstall [options] ``` ```bash neon git uninstall ``` ```text filename="Output" Removed the neon git post-checkout hook. Git → Neon sync is off. ``` --- [Document source](https://neon.com/docs/cli/init.md) --- > Summary: The `neon init` command sets up the current directory to use Neon with your AI coding assistant. It installs agent tooling (either a plugin, or skills and the MCP server), links a Neon project, and optionally writes a neon.ts config. It runs interactively by default; pass -y for the recommended setup with no prompts, or add flags such as --skill, MCP options, or --claimable for the custom setup. # Neon CLI command: init Set up the current directory for Neon with agent tooling, a linked project, and an optional neon.ts config Last updated: 2026-11-05 The `init` command sets up the current directory to use Neon with your AI coding assistant. It's a thin wrapper that runs Neon's other setup commands for you: it installs agent tooling, [links a Neon project](https://neon.com/docs/cli/link), and can write a [`neon.ts` config](https://neon.com/docs/cli/config). It sets up the current directory in place. `init` is interactive, so run it from a terminal. It asks how coding agents should get Neon, prompts you to pick a project to link, and asks whether to write `neon.ts`. If you don't have the CLI installed, run it with `npx`: ```bash npx neon@latest init ``` For agents, CI, or scripts that can't answer prompts, see [Run it non-interactively](https://neon.com/docs/cli/init#run-it-non-interactively). **Note: Behavior changed in Neon CLI 6.0** Before 6.0, `init` could scaffold a starter template in an empty directory, and it accepted `--template` and `--skip-template`. From 6.0, `init` only sets up the current directory in place, those template flags are gone, and `-y` runs a recommended setup. To scaffold a starter project, use [`neon bootstrap`](https://neon.com/docs/cli/bootstrap) instead. ## Usage ```bash neon init [options] ``` ## Recommended and custom setup `init` has two setup modes: - **Recommended setup** installs tooling for your detected coding agents, links a Neon project when the CLI is authenticated (or the session is interactive), and writes a default `neon.ts`. Run it with no prompts using `-y`. When no agents are detected, it writes the default skills in the current directory. - **Custom setup** applies the specific answers you pass as flags and falls back to the recommended defaults for anything you don't. Passing `--skill`, an MCP flag (`--mcp-auth`, `--mcp-config-location`, or `--mcp-project-scoped`), `--no-agent-setup`, or `--claimable` selects it. `-y` alone runs the recommended setup without prompts and never opens a browser. `-y` with any of those flags runs the custom setup with your answers, still without prompts. ## What it does ### Choose how coding agents get Neon In a terminal, `init` asks how your coding agents should get Neon: - **Plugin (recommended)** installs the `neon-postgres` plugin, which bundles agent skills and the MCP server. - **Skills and MCP separately** installs [agent skills](https://neon.com/docs/cli/skills), then the [Neon MCP server](https://neon.com/docs/cli/mcp). - **Skip agent setup** continues without a plugin, skills, or MCP. You can also make this choice with flags, which skips the prompt: - `--agent` (without skill or MCP flags) installs the plugin for the named agents, plus skills and MCP for any agent the plugin can't cover. - `--skill` selects skills (not the plugin) and skips the skills picker. Combined with an MCP flag, it also configures MCP. - An MCP flag (`--mcp-auth`, `--mcp-config-location`, or `--mcp-project-scoped`) selects skills and MCP. - `--no-agent-setup` skips agent setup entirely. The plugin and the skills-plus-MCP option are mutually exclusive; `init` sets up one family per run. Installing skills needs Node.js 22.20 or newer. Recommended setup installs agent tooling globally for your detected agents, so it's available across projects. Custom setup can set up the current directory instead: pass `--mcp-config-location project` to write the MCP configuration locally. To control the scope yourself, run [`neon skills`](https://neon.com/docs/cli/skills) or [`neon plugins`](https://neon.com/docs/cli/plugins) directly. ### Link a project and write neon.ts After agent setup, `init` runs [`neon link`](https://neon.com/docs/cli/link) (unless the directory is already linked). Linking writes a `.neon` file with your org, project, and branch. `init` then pulls the branch's environment variables (including `DATABASE_URL`) into `.env` if one exists, otherwise `.env.local`. Pass `--no-link` to set up agent tooling and `neon.ts` without linking a project; you can link later with `neon link`. It can also write a [`neon.ts` config](https://neon.com/docs/cli/config) you can edit and apply with [`neon deploy`](https://neon.com/docs/cli/deploy). In a terminal, `init` asks whether to create it. Pass `--config` to create it without asking, `--no-config` to skip it, or `--services` to create it with specific services declared (which implies `--config`). Pass `--package-manager` (`npm`, `pnpm`, `yarn`, or `bun`) to choose which package manager installs the `neon.ts` dependencies. When `init` creates a new `neon.ts`, it pulls environment variables once, after the file is written. If `neon.ts` declares only services that need no deploy (the AI Gateway or Functions), the pull includes all of them. If it declares Managed Better Auth, the Data API, Object Storage, or Realtime, `init` pulls Postgres (plus the AI Gateway and the scaffolded function's URL when declared), and [`neon deploy`](https://neon.com/docs/cli/deploy) provisions the rest and pulls their variables. With `--claimable`, `init` skips the pull when `neon.ts` declares services beyond Postgres. When `init` writes a new `neon.ts` for a linked project, it lists next steps under `Next`. Preview the changes with [`neon config plan`](https://neon.com/docs/cli/config#plan), then apply them with [`neon deploy`](https://neon.com/docs/cli/deploy). It also suggests [`neon checkout dev --create`](https://neon.com/docs/cli/checkout) to work on a development branch once you've deployed. These steps appear even for the default Postgres-only `neon.ts`. For a claimable project, `init` lists `neon claim accept` instead, followed by the plan and deploy steps when `neon.ts` declares services beyond Postgres. If you skip `neon.ts` (for example, with `--no-config`) and the directory doesn't have one, `init` suggests [`neon config init`](https://neon.com/docs/cli/config#init) to create it later. `--services realtime` declares [Realtime](https://neon.com/docs/realtime/overview) in `neon.ts`. `init` doesn't enable it on the branch: [`neon deploy`](https://neon.com/docs/cli/deploy) does, or you can run [`neon realtime enable`](https://neon.com/docs/cli/realtime#enable). The interactive service picker doesn't list Realtime, so pass `--services realtime` to declare it. When `neon.ts` declares the [Data API](https://neon.com/docs/data-api/get-started), `init` checks the linked branch's Data API first. If it uses an external identity provider, `init` declares the [external form](https://neon.com/docs/reference/neon-ts#dataapi) (`authProvider: "external"`) instead of `dataApi: true`, so `neon deploy` doesn't enable Managed Better Auth. If `init` can't read the branch, for example without credentials, it declares `dataApi: true` with `auth: true`. It never starts a login to check. ## Options | Option | Description | Type | Default | Required | | ------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------- | ------- | :------: | | `--agent`, `-a` | Coding agent to install into (repeatable). Skips agent selection. Values listed below | array | — | No | | `--agent-setup` | Install Neon into coding agents. Use --no-agent-setup to skip. Plugin vs skills is inferred from --skill and MCP flags | boolean | `true` | No | | `--branch`, `--branch-id` | Forwarded to link: branch name or ID to pin | string | — | No | | `--claimable` | Create a claimable project that expires in 72 hours unless claimed. Selects Custom | boolean | `false` | No | | `--config` | Create neon.ts after linking. Use --no-config to skip. Omitted in Custom: you will be asked | boolean | — | No | | `--link` | Link a Neon project during setup. Use --no-link to skip without being asked | boolean | `true` | No | | `--mcp-auth` | MCP authentication. Selects skills and MCP setup. oauth is neon mcp --oauth Possible values: `oauth`, `api-key` | string | — | No | | `--mcp-config-location` | Where to configure the Neon MCP server: global (user config, same as neon mcp) or project (this directory, same as neon mcp --project). Selects skills and MCP setup Possible values: `global`, `project` | string | — | No | | `--mcp-project-scoped` | Limit MCP tools to the linked project, same as neon mcp --project-id. Selects skills and MCP setup | boolean | `false` | No | | `--org-id` | Forwarded to link: organization ID to link to | string | — | No | | `--package-manager` | Package manager for neon.ts dependencies. -y uses this without asking. Custom asks only when none is detected Possible values: `npm`, `pnpm`, `yarn`, `bun` | string | — | No | | `--project-id` | Forwarded to link: existing project ID to link to | string | — | No | | `--project-name` | Name for a new project, forwarded to link or to the claimable project | string | — | No | | `--region-id` | Region for a new project, forwarded to link or to the claimable project | string | — | No | | `--services`, `-s`, `--service` | Services to declare in neon.ts: postgres, auth, data-api, functions, object-storage, ai-gateway, realtime. Repeat the flag or comma-separate. postgres alone writes the starter policy; every branch has Postgres. Implies creating neon.ts. Cannot be combined with --no-config. | array | — | No | | `--skill` | Neon skill to install (repeatable). Selects skills setup (not the plugin) and skips the skills picker. With MCP flags, also configures MCP. Values listed below | array | — | No | | `--yes`, `-y` | Skip prompts. Alone: Recommended (detected agents, link when authenticated, default neon.ts). With --skill, MCP flags, --no-agent-setup, or --claimable: Custom using those flags | boolean | `false` | No | Pass `-y` (alias `--yes`) to run each step with its defaults instead of prompting. On its own, `-y` runs the recommended setup: it detects agents from your global agent configuration, the project folders, and the host CLI agent you're running inside, then installs the plugin globally for each detected agent that supports it, and skills and MCP for the rest. Run `neon init --help` to see which agents fall into each family. If it detects no agent, it writes the default skills in the current directory. `-y` links your only organization and project, or prints the IDs and exits when you have several (pass `--org-id`/`--project-id` to choose), and it never opens a browser. Pass `--agent` (alias `-a`) to name the coding agents to set up, which skips both detection and the picker. It's repeatable (`neon init --agent cursor --agent claude-code`) and works with `-y`. Without skill or MCP flags, it installs the plugin, plus skills and MCP for any agent the plugin can't cover. Run `neon init --help` to see which agents each family supports. Passing `--agent` with no value returns an error. Pass `--claimable` to create a [claimable project](https://neon.com/docs/reference/claimable-neon) that expires in 72 hours unless it's claimed. This selects the custom setup. The project goes in `aws-us-east-2` unless you add `--region-id`. `--claimable` can't be combined with `--no-link`, `--org-id`, `--project-id`, `--project-name`, or `--branch`. ## Run it non-interactively Combine `-y` with any of those flags to set up without prompts, for example in CI or from an agent. Without a TTY, pass `-y` or enough flags to answer every question: ```bash neon init -y --agent cursor ``` By default, `init` links to the project the directory is already linked to, and when it isn't linked yet, [`neon link`](https://neon.com/docs/cli/link) picks one interactively. To target a project without prompts, `init` forwards project-selection flags to `link`: pass `--project-id` (with `--org-id`) to link an existing project, or `--org-id`, `--project-name`, and `--region-id` to create and link a new one. Pass `--branch` to pin a branch. ```bash # Existing project, fully non-interactive neon init -y --agent cursor --project-id --org-id # Create a new project and link it neon init -y --agent cursor --org-id --project-name my-app --region-id aws-us-east-2 # Custom setup: install the neon skill and configure MCP with OAuth in this directory neon init -y --skill neon --mcp-auth oauth --mcp-config-location project ``` Authenticate without a browser by setting `NEON_API_KEY` or passing `--api-key`. Agents can find the IDs with `neon orgs list --output json` and `neon projects list --org-id --output json`. To control `neon.ts` in the same run, add `--config`, `--no-config`, or `--services`. When `-y` can't authenticate, it finishes every step it can and lists what's left under `Next`. With no credential at all, it skips the environment pull. If you also pass `--org-id`, `--project-id`, and `--branch`, it writes `.neon` without contacting Neon (like [`neon link --no-checks`](https://neon.com/docs/cli/link)), and Neon checks those IDs on the first command that reaches it. With fewer IDs, it skips linking and prints the `neon login` and `neon link` commands to run. A project-scoped or organization API key can link and pull, but it can't mint the API key the Neon MCP server uses. In that case, `init` configures MCP with OAuth instead. If you asked for `--mcp-auth api-key`, it skips MCP, finishes the other steps, and exits with an error that names the retry command. ## What gets created The files created depend on the flags you pass. Each one is written by the command `init` runs, so see that command's page for details. | Artifact | Written by | Scope | | ----------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------- | | `.neon` (org, project, and branch context) | [`neon link`](https://neon.com/docs/cli/link) | Project | | `.env` or `.env.local` (`DATABASE_URL` and Neon vars) | [`neon link`](https://neon.com/docs/cli/link) | Project | | `neon.ts` (config-as-code policy) | [`neon config init`](https://neon.com/docs/cli/config) | Project | | Agent skills, MCP config, or plugin | [`neon skills`](https://neon.com/docs/cli/skills) / [`neon mcp`](https://neon.com/docs/cli/mcp) / [`neon plugins`](https://neon.com/docs/cli/plugins) | User or project, per agent | ## Examples Run `init` from your project root: ```bash npx neon@latest init ``` Choose your agent setup, then pick a project to link. Linking writes the context. If you create a `neon.ts`, `init` writes it and then pulls your environment variables: ```text Linked .neon Project my-app (polished-snowflake-12345678) Branch main Org org-example-12345678 Creating neon.ts... Installing Neon dependencies with npm... Pulling Neon environment variables... Pulled 5 Neon variables into .env.local from branch main (br-restless-wildflower-a1b2c3d4) Postgres DATABASE_URL, DATABASE_URL_UNPOOLED Branch NEON_BRANCH, NEON_BRANCH_ID Functions NEON_FUNCTION_HOST_SUFFIX ``` After setup, restart your editor and ask your assistant to "Get started with Neon." The installed [Neon MCP server](https://neon.com/docs/ai/neon-mcp-server) points your assistant to the right docs, so it can connect to your database and use Neon features as you build. Install the Neon plugin for a specific agent and create a [claimable project](https://neon.com/docs/reference/claimable-neon). Naming an agent with `--agent` selects the custom setup, which installs the plugin at the project level: ```bash neon init -y --claimable --agent cursor ```
Show output ```text Installing the Neon plugin... Installing the Neon plugin for Cursor (1/1)... Plugins Scope Plugin Agent Status user neon-postgres cursor installed Installed the Neon plugin (user). Creating a claimable project... Project ID sweet-breeze-12345678 Branch ID br-restless-wildflower-a1b2c3d4 Region ID aws-us-east-2 State unclaimed Project Expires At 2026-09-29T01:51:07.360Z Granted Capabilities postgres Creating neon.ts... Installing Neon dependencies with npm... Pulling Neon environment variables... Pulled 5 Neon variables into .env.local from branch main (br-restless-wildflower-a1b2c3d4) Postgres DATABASE_URL, DATABASE_URL_UNPOOLED Branch NEON_BRANCH, NEON_BRANCH_ID Functions NEON_FUNCTION_HOST_SUFFIX Neon setup complete. -------------------- Agents Neon plugin: cursor Project claimable Config neon.ts created Next: This project expires at 2026-09-29T01:51:07.360Z. To keep it, open the claim flow and sign in to Neon: neon claim accept ```
## Manual setup To configure a specific agent without running `init`, or to register only the Neon MCP Server, see [Set up your AI agent](https://neon.com/docs/ai/agent-setup). To install only agent skills, use [`neon skills`](https://neon.com/docs/cli/skills); to install only the MCP server, use [`neon mcp`](https://neon.com/docs/cli/mcp). --- [Document source](https://neon.com/docs/cli/inspect.md) --- > Summary: The Neon CLI `neon inspect` command runs read-only diagnostic queries against a branch's Postgres, reporting on table and index sizes, unused indexes, locks, long-running and expensive queries, cache hit rates, autovacuum status, bloat, and replication. Use it to troubleshoot performance and understand what a database is doing without leaving the terminal. # Neon CLI command: inspect Run diagnostic queries against a branch's Postgres to check its health and configuration Last updated: 2026-10-09 The `inspect` command runs a set of read-only diagnostic queries against a branch's Postgres and prints the results. Each query targets a common operational question, such as which tables are largest, which indexes go unused, what is holding locks, or how the cache is performing. Nothing is modified, so the command is safe to run against any branch. Subcommands: [db](https://neon.com/docs/cli/inspect#db) ## neon inspect db Run a single diagnostic query against a branch's Postgres. Pick the query with a subcommand, for example `neon inspect db table-sizes`. ```bash neon inspect db [options] ``` | Option | Description | Type | Default | Required | | ----------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------ | ------- | :------: | | `--branch` | Branch ID or name | string | — | No | | `--database-name` | Database to inspect. Omit to cover every database the API lists for the branch. Ranking and row limits stay per database. One failing database fails the whole run. Compute-wide checks run once against the first listed database. Ignored with --db-url. | string | — | No | | `--db-url` | Inspect any Postgres via a connection string, bypassing the Neon API (project/branch resolution is skipped) | string | — | No | | `--project-id` | Project ID | string | — | No | | `--role-name` | Role name. Defaults to neondb\_owner, else the only role besides the Data API and Neon Auth roles | string | — | No | By default the command resolves the project, branch, database, and role from your [context](https://neon.com/docs/cli/link) and connects through the Neon API. Pass `--db-url` to inspect any Postgres directly from a connection string, which bypasses API resolution and lets you point `inspect` at a database outside Neon without being logged in to Neon. Without `--role-name`, `inspect` connects as the same role as [`neon connection-string`](https://neon.com/docs/cli/connection-string): the branch's only role, or `neondb_owner` on branches with several roles. If there's no `neondb_owner`, it uses the only role left after skipping the Data API and Managed Better Auth roles (`authenticator`, `anonymous`, and `authenticated`). When you omit `--database-name`, `inspect` covers every database on the branch and adds a `database` column so you can tell the rows apart. Pass `--database-name` to inspect a single database, which also scopes `locks` and `long-running-queries` to that database so lock and relation names resolve correctly. Database-scoped checks such as `table-sizes`, `locks`, and `outliers` run against each database, while compute-wide checks (`lfc-hit-rate`, `working-set`, and `replication-slots`) run once. If any database fails, the whole run fails, so pass `--database-name` to narrow to one when that happens. `--db-url` always inspects the single database in the connection string and never adds the `database` column. Some queries read from Postgres statistics extensions. `outliers` and `calls` need [`pg_stat_statements`](https://neon.com/docs/extensions/pg_stat_statements), and `lfc-hit-rate` and `working-set` need the [`neon`](https://neon.com/docs/extensions/neon) extension. If a required extension is not installed, the command reports it instead of returning rows. **Note:** On large fixed-size computes (18 CU and above), Neon disables the file cache and serves the [compute cache](https://neon.com/docs/extensions/neon#what-is-the-compute-cache) from Postgres `shared_buffers`, so `lfc-hit-rate` and `working-set` return empty or misleading results on those computes. Use the [Compute cache hit rate](https://neon.com/docs/introduction/monitoring-page#compute-cache-hit-rate) graph or run `SHOW shared_buffers` instead. From an AI assistant, the same checks are available through the Neon MCP server's `inspect_database` tool. See [Database diagnostics](https://neon.com/docs/ai/neon-mcp-server#database-diagnostics). Subcommands: [bloat](https://neon.com/docs/cli/inspect#db-bloat), [calls](https://neon.com/docs/cli/inspect#db-calls), [index-sizes](https://neon.com/docs/cli/inspect#db-index-sizes), [lfc-hit-rate](https://neon.com/docs/cli/inspect#db-lfc-hit-rate), [locks](https://neon.com/docs/cli/inspect#db-locks), [long-running-queries](https://neon.com/docs/cli/inspect#db-long-running-queries), [outliers](https://neon.com/docs/cli/inspect#db-outliers), [replication-slots](https://neon.com/docs/cli/inspect#db-replication-slots), [seq-scans](https://neon.com/docs/cli/inspect#db-seq-scans), [stalled-queries](https://neon.com/docs/cli/inspect#db-stalled-queries), [subscriptions](https://neon.com/docs/cli/inspect#db-subscriptions), [table-sizes](https://neon.com/docs/cli/inspect#db-table-sizes), [unused-indexes](https://neon.com/docs/cli/inspect#db-unused-indexes), [vacuum-stats](https://neon.com/docs/cli/inspect#db-vacuum-stats), [working-set](https://neon.com/docs/cli/inspect#db-working-set) ### neon inspect db table-sizes Size of each table, including TOAST, largest first. ```bash neon inspect db table-sizes ``` ```text Schema Name Size public events 16 MB public orders 4752 kB public customers 1616 kB ``` ### neon inspect db index-sizes Size of each index, largest first. ```bash neon inspect db index-sizes ``` ### neon inspect db unused-indexes Non-unique, non-primary-key indexes with fewer than 50 scans, largest first. These are candidates for removal. Check the `Index Scans` column: an index that has never been scanned (`0`) while taking up space is a strong candidate to drop. ```bash neon inspect db unused-indexes ``` ```text Table Index Index Size Index Scans public.events events_created_at_idx 1368 kB 0 public.orders orders_customer_id_idx 1024 kB 2 public.customers customers_email_idx 808 kB 0 public.orders orders_status_idx 560 kB 20 ``` ### neon inspect db seq-scans Number of sequential scans recorded against each table, highest first. A high count on a large table often points to a missing index. ```bash neon inspect db seq-scans ``` ### neon inspect db long-running-queries Queries that have been running longer than five minutes. Run it to catch a runaway statement. When nothing qualifies, it says so instead of printing an empty table: ```bash neon inspect db long-running-queries ``` ```text No long-running queries in any database. ``` ### neon inspect db stalled-queries Active queries running longer than 30 seconds, with their parallel workers, what each one is waiting on, and any queries blocking them. It runs compute-wide. When nothing qualifies, it says so instead of printing an empty table: ```bash neon inspect db stalled-queries ``` ```text No active queries running longer than 30 seconds. ``` ### neon inspect db locks Locks currently held, with the query that acquired each one and its age. When writes are blocked, run this to find what is holding the lock. ```bash neon inspect db locks ``` ```text No locks held in any database. ``` ### neon inspect db stalled-queries Active queries that have been running for at least 30 seconds, reported with their waits, blockers, parallel workers, query IDs, and query text. Where `long-running-queries` catches statements past a five-minute mark, this surfaces stalls sooner and shows what each backend is waiting on. Parallel workers are grouped with their leader process, and the `Blocking Pids` column shows which backends are holding others up. Run it during an incident to see what is running right now and what is blocking it. ```bash neon inspect db stalled-queries ``` ### neon inspect db outliers The top 25 queries by cumulative execution time (`Total Exec Time`), with each query's share of the total (`Prop Exec Time`) and how often it ran (`Ncalls`). This ranks by total time spent, so a cheap query that runs constantly can outrank an expensive one that runs rarely. Needs the [`pg_stat_statements`](https://neon.com/docs/extensions/pg_stat_statements) extension. ```bash neon inspect db outliers ```
Show output ```text Total Exec Time Prop Exec Time Ncalls Query 00:00:00.875831 57.0% 250 SELECT * FROM orders WHERE customer_id = $1 00:00:00.439406 28.6% 400 SELECT * FROM customers WHERE email = $1 00:00:00.220669 14.4% 15 SELECT status, count(*), sum(total_cents) FROM orders GROUP BY status ```
### neon inspect db calls The top 25 queries by call count (`Ncalls`). Where `outliers` ranks by total time, this ranks by how often a query runs, so it highlights hot paths worth caching or batching even when each individual call is cheap. Needs the [`pg_stat_statements`](https://neon.com/docs/extensions/pg_stat_statements) extension. ```bash neon inspect db calls ```
Show output ```text Ncalls Total Exec Time Prop Exec Time Query 400 00:00:00.439406 59.8% SELECT * FROM customers WHERE email = $1 250 00:00:00.875831 37.4% SELECT * FROM orders WHERE customer_id = $1 15 00:00:00.220669 2.2% SELECT status, count(*), sum(total_cents) FROM orders GROUP BY status ```
### neon inspect db lfc-hit-rate Compute cache hit rate, the share of reads served from your compute's cache instead of storage. A low or falling ratio means your working set no longer fits in the cache. Read it after the compute has handled some traffic, not on a freshly resumed one. Needs the [`neon`](https://neon.com/docs/extensions/neon) extension. ```bash neon inspect db lfc-hit-rate ``` ### neon inspect db working-set Estimated working set size over several time windows, compared with the compute cache size. When `Exceeds LFC` is `no`, your recent data fits in cache. A `yes` means the working set has outgrown the cache, and a larger compute may help. Needs the [`neon`](https://neon.com/docs/extensions/neon) extension. ```bash neon inspect db working-set ``` ```text Window Working Set LFC Size Exceeds LFC 1m 48 MB 607 MB no 5m 48 MB 607 MB no 15m 48 MB 607 MB no 1h 48 MB 607 MB no ``` ### neon inspect db vacuum-stats Autovacuum status per table: last (auto)vacuum time, dead tuples, and the autovacuum threshold, ordered by dead tuples. Rising dead tuples with no recent autovacuum points at autovacuum falling behind. ```bash neon inspect db vacuum-stats ``` **Note: Vacuum stats reset on auto-suspend** Postgres resets these counters whenever the compute restarts, including after a scale-to-zero auto-suspend. On a freshly resumed compute they start near empty, so read them after the database has handled some real traffic. ### neon inspect db bloat The top 25 tables by estimated wasted bytes. It needs no extension. The number is a statistical estimate, so use it to decide where to look, not as an exact measurement. ```bash neon inspect db bloat ``` ### neon inspect db replication-slots Replication slots with their kind, status, client, restart and confirmed-flush LSNs, and lag. Check the lag and status columns to see how far each replica or subscriber is behind the primary. ```bash neon inspect db replication-slots ``` ### neon inspect db subscriptions Per-table logical replication progress on this subscriber. Run it on a database with a subscription to see which tables are still copying and which have caught up. On other databases it reports that no subscriptions were found. ```bash neon inspect db subscriptions ``` --- [Document source](https://neon.com/docs/cli/install.md) --- > Summary: Install the Neon CLI (neon) with npm i -g neon@latest, or on macOS, Windows, or Linux via Homebrew, bun, or a standalone binary, with no-install options via npx or bunx. After installing, connect by running `neon login` for browser-based authentication, or set the NEON_API_KEY environment variable or pass --api-key per command. Vercel-Managed Integration users must use an API key because web auth requires a Neon-registered account. # Neon CLI: Install and connect Install the Neon CLI and connect with web auth or API key Last updated: 2026-10-27 ## Install Install the Neon CLI globally with [npm](https://www.npmjs.com/package/neon): ```shell npm i -g neon@latest ``` Requires [Node.js 20.19.0](https://nodejs.org/en/download/) or higher. The CLI is invoked as `neon`, and `neonctl` is an alias for `neon`.
Other install options Homebrew, bun, and standalone binaries are also available. The Homebrew formula is named `neonctl`, so install commands use that name even though you run the CLI as `neon`. **macOS** **Install with [Homebrew](https://formulae.brew.sh/formula/neonctl)** ```bash brew install neonctl ``` **Install with bun** ```bash bun install -g neon ``` **macOS binary** Download the binary. No installation required. ```bash curl -sL https://github.com/neondatabase/neon-pkgs/releases/latest/download/neon-macos-x64 -o neon ``` Run the CLI from the download directory: ```bash neon [options] ``` **Windows** **Install with bun** ```bash bun install -g neon ``` **Windows binary** Download the binary. No installation required. ```bash curl -sL -O https://github.com/neondatabase/neon-pkgs/releases/latest/download/neon-win-x64.exe ``` Run the CLI from the download directory: ```bash neon-win-x64.exe [options] ``` **Linux** **Install with bun** ```bash bun install -g neon ``` **Linux binary** Download the x64 or ARM64 binary, depending on your processor type. No installation required. x64: ```bash curl -sL https://github.com/neondatabase/neon-pkgs/releases/latest/download/neon-linux-x64 -o neon ``` ARM64: ```bash curl -sL https://github.com/neondatabase/neon-pkgs/releases/latest/download/neon-linux-arm64 -o neon ``` Run the CLI from the download directory: ```bash neon [options] ``` You can also run the Neon CLI without installing it using **npx** or the `bun` equivalent, **bunx**: ```shell # npx npx neon # bunx bunx neon ```
### Upgrade Upgrade using the method that matches how you installed the CLI. To check for the latest version, see the [Neon CLI **Releases** page](https://github.com/neondatabase/neon-pkgs/releases). To check your installed version, run: ```bash neon --version ``` **Note: Node.js 20.19.0 is required to upgrade** The current CLI requires Node.js 20.19.0 or higher. On an older version (such as Node.js 18), npm only warns about the engine mismatch when you install or upgrade, and then every `neon` command exits with `neon requires Node.js 20.19 or newer` and the version it found. If you're on an older version, [upgrade Node.js](https://nodejs.org/en/download/) before you upgrade the CLI. **npm** ```shell npm update -g neon ``` **Homebrew** ```bash brew upgrade neonctl ``` **Binary** To upgrade a [binary](https://github.com/neondatabase/neon-pkgs/releases) version, download the `latest` binary as described in the install instructions above, and replace your old binary with the new one. In CI/CD tools like GitHub Actions, you can safely pin the Neon CLI to `latest`, as we prioritize stability for CI/CD processes. **npm (recommended)** In your GitHub Actions workflow, use the `latest` tag with `npm`: ```yaml - name: Install Neon CLI run: npm install -g neon@latest ``` **Binary** If you're downloading a binary, reference the latest release from the [Releases page](https://github.com/neondatabase/neon-pkgs/releases) using `curl` or `wget` in your workflow: ```yaml - name: Install Neon CLI run: | curl -L https://github.com/neondatabase/neon-pkgs/releases/latest/download/neon-linux-x64 -o /usr/local/bin/neon chmod +x /usr/local/bin/neon ``` ## Connect The Neon CLI supports connecting via web authentication or API key. ### Web authentication Run the following command to connect to Neon via web authentication: ```bash neon login ``` The [neon login](https://neon.com/docs/cli/login) command launches a browser window where you can authorize the Neon CLI to access your Neon account. If you haven't authenticated previously, running any Neon CLI command launches the web authentication process automatically unless you've specified an API key. **Note:** If you use Neon through the [Vercel-Managed Integration](https://neon.com/docs/guides/vercel-managed-integration), you must authenticate connections from the CLI client using a Neon API key (see below). The `neon login` command requires an account registered through Neon rather than Vercel. ### API key To authenticate with a Neon API key, specify the `--api-key` option when running a Neon CLI command: ```bash neon projects list --api-key ``` To avoid including `--api-key` with each command, export your API key to the `NEON_API_KEY` environment variable. ```bash export NEON_API_KEY= ``` For information about obtaining a Neon API key, see [Creating API keys](https://neon.com/docs/manage/api-keys#creating-api-keys). ## Configure autocompletion The Neon CLI supports autocompletion. See [Neon CLI commands: completion](https://neon.com/docs/cli/completion) to set it up. --- [Document source](https://neon.com/docs/cli/ip-allow.md) --- > Summary: The Neon CLI `ip-allow` command controls project-level IP allowlists with subcommands `list`, `add`, `remove`, and `reset`, supporting individual IP addresses, IP ranges, and CIDR notation. Use this page when you need to restrict database access to specific IPs from the command line, rather than through the Neon console. The `add` subcommand accepts a `--protected-only` flag to scope the allowlist to protected branches only. # Neon CLI command: ip-allow Manage the IP allowlist: list, add, remove, and reset allowed IPs Last updated: 2026-09-18 The `ip-allow` command lists, adds, removes, and resets the IP allowlist for your Neon project. An allowlist can contain individual IP addresses, IP ranges, or [CIDR notation](https://neon.com/docs/reference/glossary#cidr-notation). For information about Neon's IP Allow feature, see [Configure IP Allow](https://neon.com/docs/manage/projects#configure-ip-allow). Subcommands: [add](https://neon.com/docs/cli/ip-allow#add), [list](https://neon.com/docs/cli/ip-allow#list), [remove](https://neon.com/docs/cli/ip-allow#remove), [reset](https://neon.com/docs/cli/ip-allow#reset) The `--project-id` option is required only if your Neon account has more than one project and no project is set in your [context file](https://neon.com/docs/cli/link). ## neon ip-allow list Lists the addresses in the IP allowlist. ```bash neon ip-allow list [options] ``` | Option | Description | Type | Default | Required | | -------------- | ----------- | ------ | ------- | :------: | | `--project-id` | Project ID | string | — | No | List the IP allowlist: ```bash neon ip-allow list --project-id cold-grass-40154007 ``` List the IP allowlist with the `--output` format set to `json`: ```bash neon ip-allow list --project-id cold-grass-40154007 --output json ``` ## neon ip-allow add Adds IP addresses to the IP allowlist for your Neon project. ```bash neon ip-allow add [ips...] ``` | Option | Description | Type | Default | Required | | ------------------ | ------------------------------------------------------------- | ------- | ------- | :------: | | `--protected-only` | If true, the list will be applied only to protected branches. | boolean | — | No | | `--project-id` | Project ID | string | — | No | Use `--protected-only` to apply the allowlist to [protected branches](https://neon.com/docs/guides/protected-branches) only. Use `--protected-only false` to remove this setting. ```bash neon ip-allow add 192.0.2.3 --project-id cold-grass-40154007 ``` ## neon ip-allow remove Removes IP addresses from the IP allowlist for your project. ```bash neon ip-allow remove [ips...] ``` | Option | Description | Type | Default | Required | | -------------- | ----------- | ------ | ------- | :------: | | `--project-id` | Project ID | string | — | No | ```bash neon ip-allow remove 192.0.2.3 --project-id cold-grass-40154007 ``` ## neon ip-allow reset Resets the allowlist to the IP addresses you specify. If you specify no addresses, the currently defined IP addresses are removed. ```bash neon ip-allow reset [ips...] ``` | Option | Description | Type | Default | Required | | -------------- | ----------- | ------ | ------- | :------: | | `--project-id` | Project ID | string | — | No | ```bash neon ip-allow reset 192.0.2.1 --project-id cold-grass-40154007 ``` --- [Document source](https://neon.com/docs/cli/link.md) --- > Summary: Covers the usage of the `link` command in the Neon CLI to bind the current directory to a Neon project, including interactive and non-interactive workflows for CI, scripts, and AI agents. # Neon CLI command: link Link a directory to a Neon project and write a `.neon` context file Last updated: 2026-10-09 The `link` command binds the current directory to a Neon project and writes a `.neon` context file. Once linked, commands you run here (or in any subdirectory) know which organization, project, and branch to use, so you don't repeat `--org-id` and `--project-id` every time. `link` always pins a branch as part of that context. Pass `--branch` to choose one, or use [`checkout`](https://neon.com/docs/cli/checkout) to switch it later. **Note: Behavior changed in Neon CLI 5.0.0** Before 5.0.0, `link` wrote `orgId` and `projectId` but pinned a branch only when you passed `--branch`, so a `.neon` file could be incomplete. From 5.0.0, `link` always pins a branch, and `--no-checks` also requires `--branch`. In non-interactive scripts, pass `--branch` (or `-y` for the default branch). **Tip: Prefer link over set-context** For most workflows, use `neon link` instead of manually running `neon set-context --project-id ...`. The `link` command guides you through organization and project selection and ensures the context file is complete. ## Usage ```bash neon link [options] ``` ## Options | Option | Description | Type | Default | Required | | ------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------- | ------- | :------: | | `--branch`, `--branch-id` | Branch name or ID to pin in the context (resolved to its name before writing). | string | — | No | | `--checks` | Verify the org/project/branch exist (and resolve the org from the project) before writing. On by default; use --no-checks to write the context offline with no API calls — it then requires --org-id, --project-id, and --branch, and skips env pull. | boolean | `true` | No | | `--clear` | Remove the org/project/branch context (writes an empty context file) instead of linking. | boolean | `false` | No | | `--config` | Offer to create neon.ts after interactive linking. Use --no-config to skip the offer | boolean | `true` | No | | `--env-pull` | Pull the linked branch's Neon env vars (DATABASE\_URL, ...) into a local .env after linking. On by default; use --no-env-pull to skip, for example when injecting env at runtime with `neon-env run` (from `@neon/env`) or `neon dev`. | boolean | `true` | No | | `--org-id` | Organization ID to link to | string | — | No | | `--params` | JSON object with link parameters, e.g. '\{"orgId":"...","projectId":"..."}' or '\{"orgId":"...","projectName":"...","regionId":"..."}'. Flags take precedence over fields in --params. | string | — | No | | `--project-id` | Existing project ID to link to | string | — | No | | `--project-name` | Name for a new project to create and link to | string | — | No | | `--region-id` | Region ID for a new project (e.g. aws-us-east-2). Required with --project-name. | string | — | No | | `--yes`, `-y` | Skip prompts. Select the only organization and project, or print IDs and the flag to pass. Pin the default branch when several exist. Does not create a project unless --project-name and --region-id are set. | boolean | `false` | No | By default, linking pulls the linked branch's environment variables (such as `DATABASE_URL`) into `.env.local` (or `.env` if present). Use `--no-env-pull` to skip this step, for example when you inject environment variables at runtime instead. After an interactive link, `link` also prompts you to create a [`neon.ts` config](https://neon.com/docs/cli/config) when the directory doesn't already have one, so you can manage the project's Neon setup as code. Accept the prompt to write `neon.ts`, or pass `--no-config` to skip it. This applies to interactive linking only; non-interactive runs never prompt. ## Interactive mode (default) Run `neon link` with no flags for guided prompts: ```bash neon link ``` ```text filename="Output" ? Which organization would you like to link? ' Personal Org (org-abc123) ? Which project would you like to link? ' + Create new project ? Name for the new project: ' my-app ? Which region should the new project run in? ' AWS US East (Ohio) (aws-us-east-2) Created project my-app in aws-us-east-2 Linked .neon Project my-app (polished-snowflake-12345678) Branch br-steep-math-aiu3vve7 Org org-abc123 ``` ## Non-interactive mode Use flags or a `--params` JSON blob for scripts, CI, and AI agents: ```bash # Link to an existing project (pin a branch, or pass -y for the default) neon link --org-id org-abc123 --project-id polished-snowflake-12345678 --branch main # Create a new project and link neon link --org-id org-abc123 --project-name my-app --region-id aws-us-east-2 # Same payload, one JSON blob neon link --params '{"orgId":"org-abc123","projectName":"my-app","regionId":"aws-us-east-2"}' ``` Flags take precedence over fields in `--params`. Because `link` writes a complete context, a non-interactive run needs a branch: pass `--branch` (or `--branch-id`), or use `-y` to pin the project's default branch. `link` pins the only branch automatically when a project has just one. Agents find the IDs with `neon orgs list --output json` and `neon projects list --org-id --output json`, then link with `--project-id` (or create a project with `--org-id`, `--project-name`, and `--region-id`). ## The `.neon` context file `link` is a thin wrapper around [`set-context`](https://neon.com/docs/cli/set-context): both write to the same `.neon` file, so anything `link` can write, `set-context` can write too. `link` writes the file into the current working directory by default. If an existing `.neon` is found in any parent directory, that file is reused, so commands run from a subdirectory of a linked project still pick up the project's context. To pin the location explicitly, pass the global `--context-file ` option. See [Using a named context file](https://neon.com/docs/cli/set-context#using-a-named-context-file). Example `.neon` file: ```json { "orgId": "org-abc123", "projectId": "polished-snowflake-12345678", "branch": "br-steep-math-aiu3vve7" } ``` The first time a `.neon` file is created, the CLI adds `.neon` to `.gitignore` in that folder so local project settings are not committed by accident. If you want to commit `.neon` and share context with your team, remove the entry from `.gitignore`. The CLI doesn't re-add it when updating an existing file. **Note:** Neon does not save confidential information to the context file (for example, auth tokens). You can safely commit this file to your repository or share it with others. ## Organization-scoped API keys Organization-scoped API keys (those created at the organization level rather than the user level) cannot list user organizations or call the regions endpoint. `link` handles this transparently: - If the API key is org-scoped and at least one project already exists in the org, the CLI auto-detects the `org_id` from the first project. - When the regions endpoint is not allowed, `link` falls back to a built-in static region list. --- [Document source](https://neon.com/docs/cli/login.md) --- > Summary: The `neon login` command authenticates the Neon CLI to a Neon account by launching a browser OAuth flow that saves credentials to `~/.config/neon/credentials.json`. Use this command when setting up the CLI for the first time or when not using an API key. `neon auth` is a legacy alias for `neon login`. Vercel-Managed Integration users must authenticate via API key (`--api-key` or `NEON_API_KEY`) instead. The CLI resolves authentication in priority order: `--api-key` flag, then `NEON_API_KEY` env var, then the credentials file, then triggers browser login if none are found. # Neon CLI command: login Authenticate to Neon via browser or API key and manage credentials Last updated: 2026-10-09 The `login` command authenticates you to Neon. `neon auth` is a legacy alias for `neon login`. ## Usage ```bash neon login [options] ``` The command launches a browser window where you authorize the Neon CLI to access your Neon account. Your credentials are then saved locally to `credentials.json`: ```text filename="Output" ~/.config/neon/credentials.json ``` **Note:** If you use Neon through the [Vercel-Managed Integration](https://neon.com/docs/guides/vercel-managed-integration), authenticate with a Neon API key instead (see below). The `neon login` command requires an account registered through Neon rather than Vercel. Instead of running `neon login`, you can provide an API key with the global `--api-key` option or the `NEON_API_KEY` environment variable. See [Global options](https://neon.com/docs/cli#global-options). **Info:** The Neon CLI resolves authentication in this order: - The `--api-key` option, if provided. - The `NEON_API_KEY` environment variable, if set. - The `credentials.json` file created by `neon login`. - If none are found, the CLI starts the `neon login` web authentication flow. `neon me` is the exception: it reports that you're signed out instead. ## Options | Option | Description | Type | Default | Required | | ----------- | ------------------------------------------------------------------------------------------------------------------------- | ------- | ------- | :------: | | `--keyring` | Store the credential in the OS keyring. Per profile; a later login without the flag stays there. See `neon profile list`. | boolean | — | No | Pass `--keyring` to store the credential in your operating system's keyring instead of the `credentials.json` file. The choice is saved per profile, so once set, `neon login` keeps using the keyring for that profile even without the flag. Along with this option, `login` accepts the [global options](https://neon.com/docs/cli#global-options). --- [Document source](https://neon.com/docs/cli/logs.md) --- > Summary: The Neon CLI `neon logs` command reads the logs a branch's services emit. Today that covers Neon Functions and Object Storage; Postgres compute logs are coming. Query records over a time window, filter by source, severity, or OpenTelemetry attributes, run raw LogQL, list which fields and values a branch reports, and call the branch's Loki-compatible read API. Logs are available in AWS US East (Ohio), US East (N. Virginia), Europe (Frankfurt), and Asia Pacific (Singapore). # Neon CLI command: logs Query the logs a branch's services emit Last updated: 2026-11-06 The `logs` command reads the logs a branch's services emit. Today that covers Neon Functions and Object Storage; Postgres compute logs are coming. Query records over a time window, filter by source, severity, or OpenTelemetry attribute, and list which fields and values a branch reports so you can build precise filters. For output in Loki's format, use [`neon logs loki`](https://neon.com/docs/cli/logs#loki). Logs are currently available in AWS US East (Ohio) (`aws-us-east-2`), AWS US East (N. Virginia) (`aws-us-east-1`), AWS Europe (Frankfurt) (`aws-eu-central-1`), and AWS Asia Pacific (Singapore) (`aws-ap-southeast-1`), so your project must be in one of these regions to use them. Support is expanding toward [all regions](https://neon.com/docs/introduction/regions). Every subcommand resolves the project and branch from your [context](https://neon.com/docs/cli/link). Pass `--project-id` and `--branch` to target a specific branch instead. Subcommands: [field-values](https://neon.com/docs/cli/logs#field-values), [fields](https://neon.com/docs/cli/logs#fields), [loki](https://neon.com/docs/cli/logs#loki), [query](https://neon.com/docs/cli/logs#query) ## neon logs query Query log records over a time window. By default it returns the last hour of logs on the default branch, newest first. ```bash neon logs query [options] ``` | Option | Description | Type | Default | Required | | -------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ------ | ------- | :------: | | `--body-contains` | Match the case-sensitive rendered message. Structured bodies are rendered as compact JSON. | string | — | No | | `--cursor` | Pagination cursor returned as next\_cursor by a previous call. Repeat the same time range and filters. | string | — | No | | `--end-time` | Exclusive end of the window (RFC 3339). Defaults to the current time. | string | — | No | | `--limit` | Maximum number of records to return per page (1-1000) | number | `100` | No | | `--logql` | Raw LogQL expression (stream selectors and line filters only). Replaces the structured filters; the window, --limit, --sort-order and --cursor still apply. | string | — | No | | `--minimum-severity` | Only records at or above this severity. Combines with --severity-text. If Neon reports that this filter is unsupported, use --severity-text instead. Possible values: `trace`, `debug`, `info`, `warn`, `error`, `fatal` | string | — | No | | `--scope-name` | Match the OpenTelemetry instrumentation scope name exactly | string | — | No | | `--service-name` | Match the OpenTelemetry service.name resource attribute exactly | string | — | No | | `--severity-text` | Match the OpenTelemetry severity text exactly. Run `neon logs field-values severity_text` to discover the values present. | string | — | No | | `--since` | Length of the window, ending at --end-time or now. Defaults to 1h; the maximum window is 7d. Mutually exclusive with --start-time. | string | — | No | | `--sort-order` | Order records by timestamp. Defaults to desc (newest first). Possible values: `asc`, `desc` | string | — | No | | `--source` | Only records emitted by this service Possible values: `function`, `storage`, `pg_endpoint` | string | — | No | | `--start-time` | Inclusive start of the window (RFC 3339, e.g. 2025-01-01T00:00:00Z). The maximum window is 7d. Mutually exclusive with --since. | string | — | No | | `--trace-id` | Match records carrying this trace ID (32 lowercase hex digits) | string | — | No | | `--branch` | Branch ID or name | string | — | No | | `--project-id` | Project ID | string | — | No | Bound the window with `--since` (a duration like `30m` or `1h`, ending at `--end-time` or now) or with an explicit `--start-time`/`--end-time` pair. `--since` and `--start-time` are mutually exclusive, and the maximum window is 7 days. The structured content filters (`--source`, `--service-name`, `--scope-name`, `--severity-text`, `--body-contains`, and `--trace-id`) combine with each other. Passing `--logql` replaces all of them with a raw [LogQL](https://grafana.com/docs/loki/latest/query/) expression (stream selectors and line filters only); the window, `--limit`, `--sort-order`, and `--cursor` still apply. `--source` accepts `function`, `storage`, and `pg_endpoint`. Only `function` and `storage` return records today; `pg_endpoint` (Postgres compute) is accepted but comes back empty until Postgres logs ship. Filter by severity with `--severity-text`, which matches the exact, case-sensitive value a record carries (for example `ERROR` or `INFO`, uppercase). Severities vary by source, so a filter can legitimately return nothing. Storage logs take their level from the HTTP status (`WARN` for 4xx, `ERROR` for 5xx, `INFO` otherwise), so `--source storage --severity-text ERROR` returns only server errors. Run `neon logs field-values severity_text` to see the values a branch actually reports before filtering. `--minimum-severity` (match a level and everything above it) is not supported by the branch log backend; use `--severity-text` for an exact match instead. ```bash neon logs query --since 30m ``` Filter function errors on a specific branch: ```bash neon logs query --branch main --source function --severity-text ERROR ``` Read one function's logs. A function's service name is `neon-function/`: ```bash neon logs query --source function --service-name neon-function/hello ``` Use a raw LogQL selection instead of the structured filters: ```bash neon logs query --since 1h --logql '{entity_type="function"} |= "timeout"' ``` When more records match than fit in one page, the command reports a pagination cursor on stderr. Re-run with the same window and filters plus `--cursor=` to fetch the next page. ## neon logs fields List the log fields a branch reports. Pass any of these field names to `neon logs field-values` to see the values it carries. ```bash neon logs fields [options] ``` | Option | Description | Type | Default | Required | | -------------- | ----------------- | ------ | ------- | :------: | | `--branch` | Branch ID or name | string | — | No | | `--project-id` | Project ID | string | — | No | ## neon logs field-values List the distinct values a single field carries over a time window, so you know what to filter on with `neon logs query`. By default it looks back six hours. ```bash neon logs field-values [options] ``` | Option | Description | Type | Default | Required | | -------------- | ---------------------------------------------------------------------------------------------------------------------------------- | ------ | ------- | :------: | | `--end-time` | Exclusive end of the window (RFC 3339). Defaults to the current time. | string | — | No | | `--limit` | Maximum number of distinct values to return (1-1000) | number | — | No | | `--since` | Length of the window, ending at --end-time or now. Defaults to 6h; the maximum window is 7d. Mutually exclusive with --start-time. | string | — | No | | `--source` | Only consider records emitted by this service Possible values: `function`, `storage`, `pg_endpoint` | string | — | No | | `--start-time` | Inclusive start of the window (RFC 3339, e.g. 2025-01-01T00:00:00Z). The maximum window is 7d. Mutually exclusive with --since. | string | — | No | | `--branch` | Branch ID or name | string | — | No | | `--project-id` | Project ID | string | — | No | Show the service names seen in the last six hours: ```bash neon logs field-values service_name --since 6h ``` ## neon logs loki Call the branch's [Loki-compatible read API](https://neon.com/docs/cli/logs#loki-read-api) and print its JSON response unchanged. Lines come back grouped by their stream labels, with nanosecond timestamps, where [`neon logs query`](https://neon.com/docs/cli/logs#query) returns one record per line rounded to the second. Use `neon logs loki` when the order of lines within a second matters or a tool expects Loki output. You can also use it to try a LogQL selector before you point a Loki client at the endpoint. For readable tables, structured filters, and cursor pagination, use `neon logs query`. ```bash neon logs loki [query] [options] ``` | Option | Description | Type | Default | Required | | -------------- | -------------------------------------------------------------------------------------------------------------------------------------------------- | ------ | ------------- | :------: | | `--branch` | Branch ID or name (defaults to the project's default branch) | string | — | No | | `--direction` | Timestamp order (query\_range only): forward (oldest first) or backward (newest first) Possible values: `forward`, `backward` | string | — | No | | `--end` | Window end as RFC 3339 or Unix nanoseconds (kept as a string). Defaults to now. | string | — | No | | `--endpoint` | Read endpoint: query\_range, labels, or label/\/values | string | `query_range` | No | | `--limit` | Maximum number of log lines (query\_range only); the server enforces its cap | number | — | No | | `--project-id` | Project ID | string | — | No | | `--since` | Lookback window as a positive Go duration, e.g. 30m or 24h. Defaults to 1h for queries and 6h for label values. Explicit --start takes precedence. | string | — | No | | `--start` | Window start as RFC 3339 or Unix nanoseconds (kept as a string) | string | — | No | The default endpoint, `query_range`, needs a LogQL query. `--endpoint labels` and `--endpoint label//values` list labels and their values; for these, the query is optional and can only be a stream selector. Neon supports stream selectors and line filters, and rejects metric queries and parser stages. The window can be at most 168 hours. Output is JSON or YAML only. Each value in a range result is a `[timestamp, line]` pair, with the timestamp as a nanosecond string. There's no cursor: a result that reaches `--limit`, or the server's cap of 10,000 lines, may be incomplete. Narrow the window or the selector to get everything. List the services that logged on the branch in the last six hours: ```bash neon logs loki --endpoint label/service_name/values --since 6h ``` Query function log lines that contain `invoke end`: ```bash neon logs loki '{entity_type="function"} |= "invoke end"' --since 6h --limit 2 ```
Show output ```json { "status": "success", "data": { "resultType": "streams", "result": [ { "stream": { "entity_type": "function", "scope_name": "neon.function.request", "service_name": "neon-function/todos", "severity_text": "INFO" }, "values": [ [ "1793993911665404000", "invoke end" ], [ "1793993910924177000", "invoke end" ] ] } ] } } ```
## Loki-compatible read API The same branch logs are also readable over HTTP through a Loki-compatible endpoint, for tools that speak the [Loki](https://grafana.com/docs/loki/latest/reference/loki-http-api/) query API directly rather than through the CLI. [`neon logs loki`](https://neon.com/docs/cli/logs#loki) calls the same endpoints from the terminal. Authenticate with a Neon API key as a bearer token, against this branch-scoped base URL: ```text https://console.neon.tech/telemetry/v1/projects/{project_id}/branches/{branch_id}/loki ``` It exposes a read-only subset of the Loki HTTP API: - `GET /api/v1/query_range`: query log lines over a window. Supports LogQL stream selectors and line filters, `since` or `start`/`end`, `limit`, and `direction`. It does not support aggregations, parsers, or formatting stages. - `GET /api/v1/labels`: list the available stream labels (for example `entity_type`, `service_name`, `severity_text`). - `GET /api/v1/label/{name}/values`: list the values a label carries (for example `entity_type` returns `function` and `storage`). ```bash curl "https://console.neon.tech/telemetry/v1/projects/$PROJECT_ID/branches/$BRANCH_ID/loki/api/v1/labels" \ -H "Authorization: Bearer $NEON_API_KEY" ``` The stream label is `entity_type` (not `--source`), so a LogQL selector reads `{entity_type="function"}`. This is a read-only subset, not a push endpoint or a complete Loki deployment. A Loki client that builds its own paths may need a different root: a Grafana data source, for example, appends `/loki/api/v1` to whatever URL it is given. Confirm the data-source URL against this base rather than pasting it verbatim. Like the CLI, this API reads logs only on branches in a supported region: AWS US East (Ohio) (`aws-us-east-2`), AWS US East (N. Virginia) (`aws-us-east-1`), AWS Europe (Frankfurt) (`aws-eu-central-1`), or AWS Asia Pacific (Singapore) (`aws-ap-southeast-1`). Support is expanding toward all regions. A branch in any other region returns `404`. --- [Document source](https://neon.com/docs/cli/mcp.md) --- > Summary: The Neon CLI `mcp` command installs the [Neon MCP Server](/docs/ai/neon-mcp-server) into your coding agents by writing their MCP config for you. Run it with no flags for an interactive walkthrough, or pass flags to skip the prompts and script the install. It handles the server URL, authentication, and which tools each agent gets. # Neon CLI command: mcp Install the Neon MCP Server into your coding agents Last updated: 2026-11-03 The `mcp` command installs the [Neon MCP Server](https://neon.com/docs/ai/neon-mcp-server) into your coding agents by writing their MCP config for you. It points each agent at the hosted server (`https://mcp.neon.tech/mcp`), sets up authentication, and can narrow which tools the agent sees. Run `neon mcp` with no flags for an interactive walkthrough: it asks whether to write global or project-level config, which detected agents to install into, and whether to authenticate with a minted API key or OAuth, then shows you what it will do before writing anything. Pass flags to skip the prompts and run it non-interactively, which is what you want in scripts or a headless environment. **mcp vs init:** For the full setup, use [`neon init`](https://neon.com/docs/cli/init). For just one piece: [`neon skills`](https://neon.com/docs/cli/skills) (skills), [`neon plugins`](https://neon.com/docs/cli/plugins) (skills and MCP), or `neon mcp` (MCP server). ## Usage ```bash neon mcp [options] ``` ## Options | Option | Description | Type | Default | Required | | --------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------- | ------- | :------: | | `--agent`, `-a` | Coding agent to install into (repeatable). Skips the agent picker. Values listed below | array | — | No | | `--category` | MCP tool category (repeatable or comma-separated). Default: all. Values listed below | array | — | No | | `--oauth` | Write the server URL only. The agent prompts for Neon sign-in on first use. No CLI login, no API key minted. Skips the auth question | boolean | `false` | No | | `--project` | Write project-level MCP config. Skips the config-location question. A linked project-folder install may still pin a project and scope a newly minted key | boolean | `false` | No | | `--project-id` | Pin MCP tools to one Neon project (?projectId=). A newly minted API key is limited to that project. A linked project-folder install asks the same when you pick API-key auth | string | — | No | | `--read-only`, `--readonly` | Restrict MCP tools to read-only (?readonly=true). Not prompted. Does not change the minted key | boolean | `false` | No | | `--yes`, `-y` | Skip prompts. Defaults listed below. --agent, --project, --oauth, --read-only, --project-id and --category still apply | boolean | `false` | No | ### Authentication By default, `mcp` mints a new Neon API key and writes it into each agent's config. Minting requires you to already be signed in, so run [`neon login`](https://neon.com/docs/cli/login) first or pass `--api-key`. If you aren't authenticated, the command stops and tells you to sign in, pass `--api-key`, or use `--oauth`. **Warning: Minted keys are account-wide by default** By default a minted API key reaches everything your account can access, in every organization. Pass `--project-id` to limit a newly minted key to a single project instead (see [Scoping the tools](https://neon.com/docs/cli/mcp#scoping-the-tools)). The command prints the key's id when it mints one. Revoke it with [`neon api-keys revoke `](https://neon.com/docs/cli/api-keys). To install without minting a key, pass `--oauth`. This writes the server URL only, and the agent prompts you to sign in to Neon on first use. When `mcp` finds a Neon API key already configured for an agent, it reuses that key instead of minting a new one. ### Choosing agents Without `--agent`, the interactive command detects installed agents and lets you pick from them. In non-interactive mode, `-y` installs into every detected agent. Pass `--agent ` (repeatable) to name agents explicitly and skip the picker. The supported agents are `antigravity`, `cline`, `cline-cli`, `claude-code`, `codex`, `cursor`, `factory-droid`, `fx`, `gemini-cli`, `goose`, `github-copilot-cli`, `grok-build`, `hermes`, `junie`, `kilo-code`, `kimi-code`, `kiro-cli`, `mcporter`, `opencode`, `pi`, `vscode`, `windsurf`, and `zed`. A few names also accept aliases (`claude` for `claude-code`, `copilot` for `vscode`, `gemini` for `gemini-cli`). Passing an unknown agent stops the command and prints the current supported list. A supported agent that can't take the chosen config (for example, one with no project-level config file when you pass `--project`) is reported and skipped. ### Scoping the tools By default the server exposes every MCP tool. Use these flags to narrow what an agent can do: - `--read-only` hides the write tools by adding `?readonly=true` to the server URL. - `--category ` limits tools to one or more categories (repeatable, or comma-separated). Categories are `projects`, `branches`, `endpoints`, `snapshots`, `schema`, `querying`, `neon_auth`, `data_api`, `observability`, `docs`, `functions`, `storage`, and `realtime`. The flag currently accepts only `projects`, `branches`, `schema`, `querying`, `neon_auth`, `data_api`, `observability`, and `docs`. For the other categories, add `?category=` to the server URL in your agent's config yourself (see [Category filtering](https://neon.com/docs/ai/neon-mcp-server#category-filtering)). - `--project-id ` pins the tools to a single Neon project with `?projectId=`, and limits a newly minted key to that project. `--read-only` and `--category` shape the server URL only; they don't change a key's scope, and neither does reusing an already-configured key. ### Global vs project config By default `mcp` writes global (per-user) agent config. Pass `--project` to write project-level config in the current directory instead, so the setup travels with the repository. If a project-level config file is tracked by git, the command refuses to write an API key into it. Use `--oauth` in that case, or untrack the file first. ## Examples Run the interactive install. It walks you through config location, agents, and authentication, then asks you to confirm: ```bash neon mcp ``` Install non-interactively into every detected agent, using global config. It reuses an API key already configured for an agent, or mints a new one (you must be signed in to mint): ```bash neon mcp -y ``` Install without minting a key. Each agent prompts you to sign in to Neon on first use: ```bash neon mcp --oauth ``` Install into specific agents only: ```bash neon mcp --agent cursor --agent claude-code ``` Write project-level config that travels with the repository. Here, `--oauth` skips minting a key and `--agent` names the target directly, so the command runs without prompts: ```bash neon mcp --oauth --project --agent cursor ``` ```text Wrote /home/user/my-app/.cursor/mcp.json URL: https://mcp.neon.tech/mcp MCP Agent Status cursor installed The agent will prompt for Neon sign-in on first use. ``` Give the agent read-only access: ```bash neon mcp --read-only ``` Limit the agent to schema and querying tools: ```bash neon mcp --category querying --category schema ``` Pin the tools to one project and limit the minted key to it: ```bash neon mcp --project-id cold-grass-40154007 ``` --- [Document source](https://neon.com/docs/cli/me.md) --- > Summary: The `neon me` CLI command prints the authenticated user's login, email, name, and credential source in the default table output. Use it to confirm which account is active and how it's authenticated. JSON output (`-o json`) exposes additional fields, such as the account id, plan, and linked auth accounts. # Neon CLI command: me View the authenticated user and login details Last updated: 2026-10-09 The `me` command shows information about the authenticated Neon CLI user: login, email, name, and how you're authenticated (the credential source, such as `OAuth` or an API key, and the profile in use). ## Usage ```bash neon me [options] ``` ## Options Takes only the [global options](https://neon.com/docs/cli#global-options). ## Examples ```bash neon me ``` ```text filename="Output" Login sally Email sally@example.com Name Sally Smith Authentication OAuth (profile DEFAULT) ``` When you're signed out, `me` doesn't start a browser sign-in. It prints a notice to stderr and exits with status `1`, so scripts and agents can run `neon me` as a sign-in check: ```text filename="Output" Not signed in: profile "DEFAULT" has no stored credential. Run `neon login --profile DEFAULT` to sign in, or use an API key with --api-key or NEON_API_KEY. ``` Show details with `--output json`, which includes data omitted from the `table` output: ```bash neon me -o json ```
Show output ```json { "active_seconds_limit": 0, "auth_accounts": [ { "email": "sally@example.com", "image": "", "login": "sally", "name": "Sally Smith", "provider": "google" } ], "email": "sally@example.com", "id": "8a9f604e-d04e-1234-baf7-e78909a5d123", "image": "", "login": "sally", "name": "Sally Smith", "last_name": "", "projects_limit": 0, "branches_limit": 0, "max_autoscaling_limit": 0, "plan": "free" } ```
The `active_seconds_limit`, `projects_limit`, `branches_limit`, and `max_autoscaling_limit` fields report `0`. These are account-level limits from before Neon moved to organizations; project and branch quotas are now governed by your organization, not your user account. --- [Document source](https://neon.com/docs/cli/neon-auth.md) --- > Summary: The Neon CLI `neon neon-auth` command manages Managed Better Auth on a database branch from the terminal. Use `enable`, `status`, and `disable` to provision, inspect, or remove Managed Better Auth, and the `oauth-provider` subcommands to add, update, or delete Google, GitHub, Vercel, Microsoft, and Apple OAuth providers. The `domain` subcommands manage trusted redirect domains, including `allow-localhost` settings for local development. The `config` subcommands cover email and password authentication, the email provider, the organization plugin, webhooks, and the OAuth server, and `oauth-client` manages that server's clients, while `plugins` and `user` let you inspect plugin configurations and manage auth users. # Neon CLI command: neon-auth Manage Managed Better Auth from the CLI Last updated: 2026-10-30 The `neon-auth` command manages [Managed Better Auth](https://neon.com/docs/auth/overview) on a database branch from the terminal. You can enable or disable Managed Better Auth, configure OAuth providers, trusted domains, email settings, and webhooks, and manage auth users. Subcommands: [config](https://neon.com/docs/cli/neon-auth#config), [disable](https://neon.com/docs/cli/neon-auth#disable), [domain](https://neon.com/docs/cli/neon-auth#domain), [enable](https://neon.com/docs/cli/neon-auth#enable), [oauth-client](https://neon.com/docs/cli/neon-auth#oauth-client), [oauth-provider](https://neon.com/docs/cli/neon-auth#oauth-provider), [plugins](https://neon.com/docs/cli/neon-auth#plugins), [status](https://neon.com/docs/cli/neon-auth#status), [user](https://neon.com/docs/cli/neon-auth#user) If `--project-id` or `--branch` are omitted, the CLI resolves them from your [context file](https://neon.com/docs/cli/link), auto-selects when there is only one option, and otherwise asks you to pass the flag. ## Enable and status ### neon neon-auth enable Provisions Managed Better Auth on the current branch. ```bash neon neon-auth enable [options] ``` | Option | Description | Type | Default | Required | | ----------------- | ---------------------------------- | ------ | ------- | :------: | | `--database-name` | Database name to use for auth data | string | — | No | | `--branch` | Branch ID or name | string | — | No | | `--project-id` | Project ID | string | — | No | ```bash neon neon-auth enable ``` ### neon neon-auth status Shows whether Managed Better Auth is configured on the branch and displays the current connection details. ```bash neon neon-auth status [options] ``` | Option | Description | Type | Default | Required | | -------------- | ----------------- | ------ | ------- | :------: | | `--branch` | Branch ID or name | string | — | No | | `--project-id` | Project ID | string | — | No | ```bash neon neon-auth status ``` ### neon neon-auth disable Removes Managed Better Auth from the branch. ```bash neon neon-auth disable [options] ``` | Option | Description | Type | Default | Required | | --------------- | ------------------------------------------------------------------ | ------- | ------- | :------: | | `--delete-data` | Permanently delete all Neon Auth data and schema from the database | boolean | `false` | No | | `--branch` | Branch ID or name | string | — | No | | `--project-id` | Project ID | string | — | No | **Important:** The `--delete-data` option permanently deletes all Managed Better Auth data and schema from the database. This can't be undone. Remove Managed Better Auth from the branch and delete its data: ```bash neon neon-auth disable --delete-data ``` ## OAuth providers The `oauth-provider` subcommands manage the OAuth providers (`google`, `github`, `vercel`, `microsoft`, and `apple`) for the branch. Subcommands: [add](https://neon.com/docs/cli/neon-auth#oauth-provider-add), [delete](https://neon.com/docs/cli/neon-auth#oauth-provider-delete), [list](https://neon.com/docs/cli/neon-auth#oauth-provider-list), [update](https://neon.com/docs/cli/neon-auth#oauth-provider-update) ### neon neon-auth oauth-provider list Lists the OAuth providers configured for the branch. ```bash neon neon-auth oauth-provider list [options] ``` | Option | Description | Type | Default | Required | | -------------- | ----------------- | ------ | ------- | :------: | | `--branch` | Branch ID or name | string | — | No | | `--project-id` | Project ID | string | — | No | ```bash neon neon-auth oauth-provider list ``` ### neon neon-auth oauth-provider add Adds an OAuth provider. ```bash neon neon-auth oauth-provider add [options] ``` | Option | Description | Type | Default | Required | | ---------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------ | ------- | :------: | | `--apple-key-id` | Key ID of the Sign in with Apple private key (apple only). Sent together with a new apple client secret, and only with one | string | — | No | | `--apple-team-id` | Apple Developer Team ID (apple only) | string | — | No | | `--microsoft-tenant-id` | Tenant ID for the microsoft provider: common, organizations, consumers, a tenant GUID, or a domain | string | — | No | | `--oauth-client-id` | OAuth client ID from your provider app. For apple, the Services ID. Omit to use Neon's shared OAuth app, where one exists; microsoft and apple always need your own credentials. | string | — | No | | `--oauth-client-secret` | OAuth client secret from your provider app. Omit to use Neon's shared OAuth app, where one exists; microsoft and apple always need your own credentials. | string | — | No | | `--oauth-client-secret-file` | Read the OAuth client secret from a file, for example the apple .p8 private key | string | — | No | | `--provider-id` | OAuth provider ID. Supported values: google, github, vercel, microsoft, apple | string | — | Yes | | `--branch` | Branch ID or name | string | — | No | | `--project-id` | Project ID | string | — | No | Add the Google OAuth provider with your own credentials: ```bash neon neon-auth oauth-provider add --provider-id google --oauth-client-id --oauth-client-secret ``` Add Apple with the `.p8` key file, Team ID, and Key ID: ```bash neon neon-auth oauth-provider add --provider-id apple --oauth-client-id --oauth-client-secret-file AuthKey_XXXXXXXXXX.p8 --apple-team-id --apple-key-id ``` Add Microsoft, optionally restricted to a tenant: ```bash neon neon-auth oauth-provider add --provider-id microsoft --oauth-client-id --oauth-client-secret --microsoft-tenant-id ``` See [Set up OAuth](https://neon.com/docs/auth/guides/setup-oauth) for the provider-side setup. ### neon neon-auth oauth-provider update Updates the credentials for an existing OAuth provider. ```bash neon neon-auth oauth-provider update [options] ``` | Option | Description | Type | Default | Required | | ---------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------ | ------- | :------: | | `--apple-key-id` | Key ID of the Sign in with Apple private key (apple only). Sent together with a new apple client secret, and only with one | string | — | No | | `--apple-team-id` | Apple Developer Team ID (apple only) | string | — | No | | `--microsoft-tenant-id` | Tenant ID for the microsoft provider: common, organizations, consumers, a tenant GUID, or a domain | string | — | No | | `--oauth-client-id` | OAuth client ID from your provider app. For apple, the Services ID. Omit to use Neon's shared OAuth app, where one exists; microsoft and apple always need your own credentials. | string | — | No | | `--oauth-client-secret` | OAuth client secret from your provider app. Omit to use Neon's shared OAuth app, where one exists; microsoft and apple always need your own credentials. | string | — | No | | `--oauth-client-secret-file` | Read the OAuth client secret from a file, for example the apple .p8 private key | string | — | No | | `--provider-id` | OAuth provider ID. Supported values: google, github, vercel, microsoft, apple | string | — | Yes | | `--branch` | Branch ID or name | string | — | No | | `--project-id` | Project ID | string | — | No | ```bash neon neon-auth oauth-provider update --provider-id github --oauth-client-id --oauth-client-secret ``` ### neon neon-auth oauth-provider delete Deletes an OAuth provider from the branch. ```bash neon neon-auth oauth-provider delete [options] ``` | Option | Description | Type | Default | Required | | --------------- | ----------------------------------------------------------------------------- | ------ | ------- | :------: | | `--provider-id` | OAuth provider ID. Supported values: google, github, vercel, microsoft, apple | string | — | Yes | | `--branch` | Branch ID or name | string | — | No | | `--project-id` | Project ID | string | — | No | ```bash neon neon-auth oauth-provider delete --provider-id vercel ``` ## Domains The `domain` subcommands manage the trusted domains that Managed Better Auth accepts as redirect URIs for the branch. Subcommands: [add](https://neon.com/docs/cli/neon-auth#domain-add), [allow-localhost](https://neon.com/docs/cli/neon-auth#domain-allow-localhost), [delete](https://neon.com/docs/cli/neon-auth#domain-delete), [list](https://neon.com/docs/cli/neon-auth#domain-list) ### neon neon-auth domain list Lists the trusted domains configured for the branch. ```bash neon neon-auth domain list [options] ``` | Option | Description | Type | Default | Required | | -------------- | ----------------- | ------ | ------- | :------: | | `--branch` | Branch ID or name | string | — | No | | `--project-id` | Project ID | string | — | No | ```bash neon neon-auth domain list ``` ### neon neon-auth domain add Adds a trusted domain. ```bash neon neon-auth domain add [options] ``` | Option | Description | Type | Default | Required | | -------------- | ----------------- | ------ | ------- | :------: | | `--branch` | Branch ID or name | string | — | No | | `--project-id` | Project ID | string | — | No | ```bash neon neon-auth domain add https://app.example.com ``` A trusted domain is an origin, so include the protocol (`https://`, or `http://` for local development) and omit any trailing slash. Use `https://app.example.com`, not `app.example.com` or `https://app.example.com/`. See [Configure trusted domains](https://neon.com/docs/auth/guides/configure-domains). ### neon neon-auth domain delete Deletes a trusted domain. ```bash neon neon-auth domain delete [options] ``` | Option | Description | Type | Default | Required | | -------------- | ----------------- | ------ | ------- | :------: | | `--branch` | Branch ID or name | string | — | No | | `--project-id` | Project ID | string | — | No | ```bash neon neon-auth domain delete example.com ``` ### neon neon-auth domain allow-localhost Manages localhost connection settings for the branch. Subcommands: [disable](https://neon.com/docs/cli/neon-auth#domain-allow-localhost-disable), [enable](https://neon.com/docs/cli/neon-auth#domain-allow-localhost-enable), [get](https://neon.com/docs/cli/neon-auth#domain-allow-localhost-get) ### neon neon-auth domain allow-localhost get Gets the current localhost connection setting. ```bash neon neon-auth domain allow-localhost get [options] ``` | Option | Description | Type | Default | Required | | -------------- | ----------------- | ------ | ------- | :------: | | `--branch` | Branch ID or name | string | — | No | | `--project-id` | Project ID | string | — | No | ```bash neon neon-auth domain allow-localhost get ``` ### neon neon-auth domain allow-localhost enable Allows localhost connections for local development. ```bash neon neon-auth domain allow-localhost enable [options] ``` | Option | Description | Type | Default | Required | | -------------- | ----------------- | ------ | ------- | :------: | | `--branch` | Branch ID or name | string | — | No | | `--project-id` | Project ID | string | — | No | ```bash neon neon-auth domain allow-localhost enable ``` ### neon neon-auth domain allow-localhost disable Restricts localhost connections. ```bash neon neon-auth domain allow-localhost disable [options] ``` | Option | Description | Type | Default | Required | | -------------- | ----------------- | ------ | ------- | :------: | | `--branch` | Branch ID or name | string | — | No | | `--project-id` | Project ID | string | — | No | ```bash neon neon-auth domain allow-localhost disable ``` ## Configuration The `config` subcommands configure auth features for the branch: email and password authentication, the email provider, the organization plugin, and webhooks. Subcommands: [email-password](https://neon.com/docs/cli/neon-auth#config-email-password), [email-provider](https://neon.com/docs/cli/neon-auth#config-email-provider), [oauth-server](https://neon.com/docs/cli/neon-auth#config-oauth-server), [organization](https://neon.com/docs/cli/neon-auth#config-organization), [webhook](https://neon.com/docs/cli/neon-auth#config-webhook) ### neon neon-auth config email-password Manages email and password authentication settings. Subcommands: [get](https://neon.com/docs/cli/neon-auth#config-email-password-get), [update](https://neon.com/docs/cli/neon-auth#config-email-password-update) ### neon neon-auth config email-password get Gets the current email and password configuration. ```bash neon neon-auth config email-password get [options] ``` | Option | Description | Type | Default | Required | | -------------- | ----------------- | ------ | ------- | :------: | | `--branch` | Branch ID or name | string | — | No | | `--project-id` | Project ID | string | — | No | ```bash neon neon-auth config email-password get ``` ### neon neon-auth config email-password update Updates the email and password configuration. ```bash neon neon-auth config email-password update [options] ``` | Option | Description | Type | Default | Required | | -------------------------------------- | ------------------------------------------------------------ | ------- | ------- | :------: | | `--auto-sign-in-after-verification` | Auto sign in users after verifying their email | boolean | — | No | | `--disable-sign-up` | Disable new user sign ups | boolean | — | No | | `--email-verification-method` | Email verification method | string | — | No | | `--enabled` | Enable email and password authentication | boolean | — | No | | `--require-email-verification` | Require email verification before users can sign in | boolean | — | No | | `--revoke-sessions-on-password-reset` | Revoke all of a user's sessions when their password is reset | boolean | — | No | | `--send-verification-email-on-sign-in` | Send verification email on sign in | boolean | — | No | | `--send-verification-email-on-sign-up` | Send verification email on sign up | boolean | — | No | | `--branch` | Branch ID or name | string | — | No | | `--project-id` | Project ID | string | — | No | ```bash neon neon-auth config email-password update --enabled --require-email-verification ``` ### neon neon-auth config email-provider Manages the email provider configuration. Subcommands: [get](https://neon.com/docs/cli/neon-auth#config-email-provider-get), [test](https://neon.com/docs/cli/neon-auth#config-email-provider-test), [update](https://neon.com/docs/cli/neon-auth#config-email-provider-update) ### neon neon-auth config email-provider get Gets the current email provider configuration. ```bash neon neon-auth config email-provider get [options] ``` | Option | Description | Type | Default | Required | | -------------- | ----------------- | ------ | ------- | :------: | | `--branch` | Branch ID or name | string | — | No | | `--project-id` | Project ID | string | — | No | ```bash neon neon-auth config email-provider get ``` ### neon neon-auth config email-provider update Updates the email provider configuration. ```bash neon neon-auth config email-provider update [options] ``` | Option | Description | Type | Default | Required | | ---------------- | --------------------------------------------------------- | ------ | ------- | :------: | | `--host` | SMTP host (required for standard) | string | — | No | | `--password` | SMTP password (required for standard) | string | — | No | | `--port` | SMTP port (required for standard) | number | — | No | | `--sender-email` | Sender email address | string | — | No | | `--sender-name` | Sender display name | string | — | No | | `--type` | Email provider type Possible values: `standard`, `shared` | string | — | Yes | | `--username` | SMTP username (required for standard) | string | — | No | | `--branch` | Branch ID or name | string | — | No | | `--project-id` | Project ID | string | — | No | Configure the `standard` email provider type with your own SMTP server: ```bash neon neon-auth config email-provider update --type standard --host smtp.example.com --port 587 --username example_username --password AbC123dEf --sender-email noreply@example.com --sender-name "Example App" ``` ### neon neon-auth config email-provider test Sends a test email through your saved SMTP provider so you can verify it works. Configure the provider first with [`update`](https://neon.com/docs/cli/neon-auth#config-email-provider-update). ```bash neon neon-auth config email-provider test [options] ``` | Option | Description | Type | Default | Required | | ------------------- | -------------------------------------------- | ------ | ------- | :------: | | `--recipient-email` | Email address to deliver the test message to | string | — | Yes | | `--branch` | Branch ID or name | string | — | No | | `--project-id` | Project ID | string | — | No | ```bash neon neon-auth config email-provider test --recipient-email user@example.com ``` ### neon neon-auth config organization Manages organization plugin settings. Subcommands: [get](https://neon.com/docs/cli/neon-auth#config-organization-get), [update](https://neon.com/docs/cli/neon-auth#config-organization-update) ### neon neon-auth config organization get Gets the current organization plugin configuration. ```bash neon neon-auth config organization get [options] ``` | Option | Description | Type | Default | Required | | -------------- | ----------------- | ------ | ------- | :------: | | `--branch` | Branch ID or name | string | — | No | | `--project-id` | Project ID | string | — | No | ```bash neon neon-auth config organization get ``` ### neon neon-auth config organization update Updates the organization plugin configuration. ```bash neon neon-auth config organization update [options] ``` | Option | Description | Type | Default | Required | | ---------------- | ----------------------------------------------------------------------- | ------- | ------- | :------: | | `--creator-role` | Role assigned to organization creator Possible values: `admin`, `owner` | string | — | No | | `--enabled` | Enable the organization plugin | boolean | — | No | | `--limit` | Maximum number of organizations a user can create | number | — | No | | `--branch` | Branch ID or name | string | — | No | | `--project-id` | Project ID | string | — | No | ```bash neon neon-auth config organization update --enabled --limit 5 --creator-role owner ``` ### neon neon-auth config webhook Manages webhook configuration. Subcommands: [get](https://neon.com/docs/cli/neon-auth#config-webhook-get), [update](https://neon.com/docs/cli/neon-auth#config-webhook-update) ### neon neon-auth config webhook get Gets the current webhook configuration. ```bash neon neon-auth config webhook get [options] ``` | Option | Description | Type | Default | Required | | -------------- | ----------------- | ------ | ------- | :------: | | `--branch` | Branch ID or name | string | — | No | | `--project-id` | Project ID | string | — | No | ```bash neon neon-auth config webhook get ``` ### neon neon-auth config webhook update Updates the webhook configuration. ```bash neon neon-auth config webhook update [options] ``` | Option | Description | Type | Default | Required | | ------------------ | ----------------------------------------------------------------------------------------------------- | ------- | ------- | :------: | | `--enabled` | Enable webhooks | boolean | — | Yes | | `--enabled-events` | Events to enable Possible values: `user.before_create`, `user.created`, `send.otp`, `send.magic_link` | array | — | No | | `--timeout` | Webhook timeout in seconds (1-10) | number | — | No | | `--url` | Webhook endpoint URL | string | — | No | | `--branch` | Branch ID or name | string | — | No | | `--project-id` | Project ID | string | — | No | ```bash neon neon-auth config webhook update --enabled --url https://example.com/webhooks/neon-auth --enabled-events user.created --timeout 5 ``` ### neon neon-auth config oauth-server Manages the [OAuth provider plugin](https://neon.com/docs/auth/guides/plugins/oauth-provider), which turns Managed Better Auth into an OAuth 2.1 authorization server for your MCP server, API, or other apps. These commands configure the server. To manage its clients, see [OAuth clients](https://neon.com/docs/cli/neon-auth#oauth-client). The `oauth-provider` commands are for social sign-in providers, not this server. Subcommands: [get](https://neon.com/docs/cli/neon-auth#config-oauth-server-get), [resource](https://neon.com/docs/cli/neon-auth#config-oauth-server-resource), [update](https://neon.com/docs/cli/neon-auth#config-oauth-server-update) ### neon neon-auth config oauth-server get Gets the current OAuth server configuration. ```bash neon neon-auth config oauth-server get [options] ``` | Option | Description | Type | Default | Required | | -------------- | ----------------- | ------ | ------- | :------: | | `--branch` | Branch ID or name | string | — | No | | `--project-id` | Project ID | string | — | No | ```bash neon neon-auth config oauth-server get ``` ### neon neon-auth config oauth-server update Updates the OAuth server configuration. To enable the server, it needs a login page, a consent page, and at least one protected resource or an MCP server URL. The login and consent pages must be on a [trusted domain](https://neon.com/docs/cli/neon-auth#domain). ```bash neon neon-auth config oauth-server update [options] ``` | Option | Description | Type | Default | Required | | | ------------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------- | ------- | :------: | -- | | `--consent-page` | URL of the page authorization requests redirect to for consent | string | — | No | | | `--enabled` | Enable the OAuth server. Use --no-enabled or --enabled false to disable | boolean | — | No | | | `--login-page` | URL of the page authorization requests redirect to for sign-in | string | — | No | | | `--mcp` | Remove the MCP configuration (only --no-mcp is accepted) | boolean | — | No | | | `--mcp-client-id-metadata-documents` | Allow MCP clients to identify themselves with a Client ID Metadata Document (CIMD) URL. Use --no-mcp-client-id-metadata-documents to disallow | boolean | — | No | | | `--mcp-resource` | MCP server URL that MCP clients are linked to. Defaults to the stored value when another --mcp-\* flag is given. To remove the MCP configuration, use --no-mcp | string | — | No | | | `--resources` | Protected resource URLs that clients can be linked to; replaces the stored list. Use \`resource add | remove\` for incremental changes | array | — | No | | `--branch` | Branch ID or name | string | — | No | | | `--project-id` | Project ID | string | — | No | | ```bash neon neon-auth config oauth-server update --enabled --login-page https://app.example.com/sign-in --consent-page https://app.example.com/consent ``` Set the MCP server URL to protect an MCP server, or remove the MCP configuration with `--no-mcp`: ```bash neon neon-auth config oauth-server update --mcp-resource https://mcp.example.com/mcp ``` ### neon neon-auth config oauth-server resource Manages the protected resources that OAuth clients can request tokens for. `add` and `remove` read the stored list and write back the full list, so a change someone else makes at the same time can be overwritten. Subcommands: [add](https://neon.com/docs/cli/neon-auth#config-oauth-server-resource-add), [list](https://neon.com/docs/cli/neon-auth#config-oauth-server-resource-list), [remove](https://neon.com/docs/cli/neon-auth#config-oauth-server-resource-remove) ### neon neon-auth config oauth-server resource list Lists the protected resources. ```bash neon neon-auth config oauth-server resource list [options] ``` | Option | Description | Type | Default | Required | | -------------- | ----------------- | ------ | ------- | :------: | | `--branch` | Branch ID or name | string | — | No | | `--project-id` | Project ID | string | — | No | ```bash neon neon-auth config oauth-server resource list ``` ### neon neon-auth config oauth-server resource add Adds one or more protected resources. ```bash neon neon-auth config oauth-server resource add [options] ``` | Option | Description | Type | Default | Required | | -------------- | ----------------- | ------ | ------- | :------: | | `--branch` | Branch ID or name | string | — | No | | `--project-id` | Project ID | string | — | No | ```bash neon neon-auth config oauth-server resource add https://api.example.com ``` ### neon neon-auth config oauth-server resource remove Removes one or more protected resources. Clients stop listing a removed resource, and list it again if you add it back. On an enabled server, removing the last resource fails unless an MCP server URL is set. ```bash neon neon-auth config oauth-server resource remove [options] ``` | Option | Description | Type | Default | Required | | -------------- | ----------------- | ------ | ------- | :------: | | `--branch` | Branch ID or name | string | — | No | | `--project-id` | Project ID | string | — | No | ```bash neon neon-auth config oauth-server resource remove https://api.example.com ``` ## OAuth clients The `oauth-client` subcommands manage the clients registered with the branch's OAuth server. Enable and configure the server first with [`config oauth-server`](https://neon.com/docs/cli/neon-auth#config-oauth-server). Subcommands: [create](https://neon.com/docs/cli/neon-auth#oauth-client-create), [delete](https://neon.com/docs/cli/neon-auth#oauth-client-delete), [get](https://neon.com/docs/cli/neon-auth#oauth-client-get), [list](https://neon.com/docs/cli/neon-auth#oauth-client-list), [rotate-secret](https://neon.com/docs/cli/neon-auth#oauth-client-rotate-secret), [update](https://neon.com/docs/cli/neon-auth#oauth-client-update) ### neon neon-auth oauth-client list Lists the OAuth clients. ```bash neon neon-auth oauth-client list [options] ``` | Option | Description | Type | Default | Required | | -------------- | ----------------- | ------ | ------- | :------: | | `--branch` | Branch ID or name | string | — | No | | `--project-id` | Project ID | string | — | No | ```bash neon neon-auth oauth-client list ``` ### neon neon-auth oauth-client create Creates an OAuth client. Each resource you link must already be a [protected resource](https://neon.com/docs/cli/neon-auth#config-oauth-server-resource). A confidential client gets a client secret, which the command prints only once. Store it before you continue. ```bash neon neon-auth oauth-client create [options] ``` | Option | Description | Type | Default | Required | | ----------------- | ------------------------------------------------------------------------------------------------------------------------ | ------- | ------- | :------: | | `--name` | Display name of the client | string | — | Yes | | `--redirect-uris` | Redirect URIs the client may use (https, or http on loopback when localhost is allowed) | array | — | Yes | | `--resources` | Protected resource URLs to link the client to; each must be configured with `neon-auth config oauth-server resource add` | array | — | Yes | | `--skip-consent` | Skip the consent prompt (first-party clients only) | boolean | — | No | | `--type` | Client type. Confidential clients receive a secret that is shown only once Possible values: `confidential`, `public` | string | — | Yes | | `--branch` | Branch ID or name | string | — | No | | `--project-id` | Project ID | string | — | No | ```bash neon neon-auth oauth-client create --name "Example app" --type confidential --redirect-uris https://app.example.com/callback --resources https://api.example.com ``` ### neon neon-auth oauth-client get Gets an OAuth client. ```bash neon neon-auth oauth-client get [options] ``` | Option | Description | Type | Default | Required | | -------------- | ----------------- | ------ | ------- | :------: | | `--branch` | Branch ID or name | string | — | No | | `--project-id` | Project ID | string | — | No | ```bash neon neon-auth oauth-client get ``` ### neon neon-auth oauth-client update Updates an OAuth client. `--redirect-uris` and `--resources` replace the stored lists. You can't change the client type. ```bash neon neon-auth oauth-client update [options] ``` | Option | Description | Type | Default | Required | | ----------------- | ------------------------------------------------------------------------------------------------------------- | ------- | ------- | :------: | | `--disabled` | Disable the client. Use --no-disabled or --disabled false to re-enable | boolean | — | No | | `--name` | Display name of the client | string | — | No | | `--redirect-uris` | Redirect URIs the client may use; replaces the stored list | array | — | No | | `--resources` | Protected resource URLs to link the client to; replaces the stored list (at least one) | array | — | No | | `--skip-consent` | Skip the consent prompt (first-party clients only). Use --no-skip-consent or --skip-consent false to turn off | boolean | — | No | | `--branch` | Branch ID or name | string | — | No | | `--project-id` | Project ID | string | — | No | ```bash neon neon-auth oauth-client update --name "Example app (staging)" ``` ### neon neon-auth oauth-client rotate-secret Rotates the secret of a confidential client. The old secret stops working immediately. ```bash neon neon-auth oauth-client rotate-secret [options] ``` | Option | Description | Type | Default | Required | | -------------- | ----------------- | ------ | ------- | :------: | | `--branch` | Branch ID or name | string | — | No | | `--project-id` | Project ID | string | — | No | ```bash neon neon-auth oauth-client rotate-secret ``` ### neon neon-auth oauth-client delete Deletes an OAuth client. Tokens the client already received stay valid until they expire. ```bash neon neon-auth oauth-client delete [options] ``` | Option | Description | Type | Default | Required | | -------------- | ----------------- | ------ | ------- | :------: | | `--branch` | Branch ID or name | string | — | No | | `--project-id` | Project ID | string | — | No | ```bash neon neon-auth oauth-client delete ``` ## Plugins The `plugins` subcommands show the Managed Better Auth plugin configurations for the branch. Subcommands: [get](https://neon.com/docs/cli/neon-auth#plugins-get), [list](https://neon.com/docs/cli/neon-auth#plugins-list) ### neon neon-auth plugins list Lists all plugin configurations. ```bash neon neon-auth plugins list [options] ``` | Option | Description | Type | Default | Required | | -------------- | ----------------- | ------ | ------- | :------: | | `--branch` | Branch ID or name | string | — | No | | `--project-id` | Project ID | string | — | No | ```bash neon neon-auth plugins list ``` ### neon neon-auth plugins get Gets a specific plugin configuration. ```bash neon neon-auth plugins get [options] ``` | Option | Description | Type | Default | Required | | -------------- | ----------------- | ------ | ------- | :------: | | `--branch` | Branch ID or name | string | — | No | | `--project-id` | Project ID | string | — | No | ```bash neon neon-auth plugins get organization ``` ## Users The `user` subcommands manage Managed Better Auth users on the branch. Subcommands: [create](https://neon.com/docs/cli/neon-auth#user-create), [delete](https://neon.com/docs/cli/neon-auth#user-delete), [set-role](https://neon.com/docs/cli/neon-auth#user-set-role) ### neon neon-auth user create Creates an auth user. ```bash neon neon-auth user create [options] ``` | Option | Description | Type | Default | Required | | -------------- | ----------------------------------------------------- | ------ | ------- | :------: | | `--email` | User email address | string | — | Yes | | `--name` | User display name (defaults to email if not provided) | string | — | No | | `--branch` | Branch ID or name | string | — | No | | `--project-id` | Project ID | string | — | No | ```bash neon neon-auth user create --email alex@example.com --name "Alex Lopez" ``` ### neon neon-auth user delete Deletes an auth user. ```bash neon neon-auth user delete [options] ``` | Option | Description | Type | Default | Required | | -------------- | ----------------- | ------ | ------- | :------: | | `--branch` | Branch ID or name | string | — | No | | `--project-id` | Project ID | string | — | No | ```bash neon neon-auth user delete ``` ### neon neon-auth user set-role Sets roles for an auth user. ```bash neon neon-auth user set-role [options] ``` | Option | Description | Type | Default | Required | | -------------- | ----------------- | ------ | ------- | :------: | | `--roles` | Roles to assign | array | — | Yes | | `--branch` | Branch ID or name | string | — | No | | `--project-id` | Project ID | string | — | No | ```bash neon neon-auth user set-role --roles admin ``` --- [Document source](https://neon.com/docs/cli/open.md) --- > Summary: The Neon CLI `open` command opens your linked project's dashboard in the Neon Console in your default browser. It resolves the project from your local `.neon` context file, or from an explicit `--project-id`. Use it to jump from the terminal to the Console without looking up the project URL. # Neon CLI command: open Open the linked project in the Neon Console in your browser Last updated: 2026-11-01 The `open` command opens the linked project's dashboard in the [Neon Console](https://console.neon.tech) in your default browser. It resolves the project from your local `.neon` [context file](https://neon.com/docs/cli/link), so run [`neon link`](https://neon.com/docs/cli/link) or [`neon set-context`](https://neon.com/docs/cli/set-context) first, or pass `--project-id` to target a project directly. If no project is linked and you don't pass `--project-id`, the command tells you to run `neon link`. ## Usage ```bash neon open [options] ``` ## Options | Option | Description | Type | Default | Required | | -------------- | ---------------------------------------------------- | ------ | ------- | :------: | | `--project-id` | Project ID (defaults to the project linked in .neon) | string | — | No | ## Examples Open the project linked in the current directory's `.neon` context file: ```bash neon open ``` ```text Opening https://console.neon.tech/app/projects/cold-grass-40154007 in your browser. ``` Open a specific project without relying on the linked context: ```bash neon open --project-id cold-grass-40154007 ``` --- [Document source](https://neon.com/docs/cli/operations.md) --- > Summary: The Neon CLI `neon operations list` command retrieves the history of system operations for a Neon project, showing each operation's ID, action type (such as `apply_config` or `suspend_compute`), status, and creation timestamp. Use this command to inspect or audit long-running or recently completed operations when debugging project state or configuration changes. Requires the Neon CLI to be installed and authenticated; scope to a specific project with `--project-id` when your account has multiple projects. # Neon CLI command: operations List operations for a Neon project and check the status of one Last updated: 2026-11-05 From the terminal, the `operations` command lists a project's operations and shows the details of one. For information about operations in Neon, see [System operations](https://neon.com/docs/manage/operations). If `--project-id` is omitted, the CLI resolves it from your [context file](https://neon.com/docs/cli/link), auto-selects when your account has only one project, and otherwise asks you to pass `--project-id`. Subcommands: [get](https://neon.com/docs/cli/operations#get), [list](https://neon.com/docs/cli/operations#list) ## neon operations list Lists operations for a Neon project. ```bash neon operations list [options] ``` | Option | Description | Type | Default | Required | | -------------- | ----------- | ------ | ------- | :------: | | `--project-id` | Project ID | string | — | No | ```bash neon operations list ``` ```text filename="Output" ID Action Status Created At fce8642e-259e-4662-bdce-518880aee723 apply_config finished 2026-06-20T00:45:19Z dc1dfb0c-b854-474b-be20-2ea1d2172563 apply_config finished 2026-06-20T00:43:17Z 7a83e300-cf5f-4c1a-b9b5-569b6d6feab9 suspend_compute finished 2026-06-19T23:50:56Z ``` ## neon operations get Shows one operation, including its branch, compute, failure count, and duration. Get the ID from `neon operations list`. ```bash neon operations get [options] ``` | Option | Description | Type | Default | Required | | -------------- | ----------- | ------ | ------- | :------: | | `--project-id` | Project ID | string | — | No | ```bash neon operations get 8f3c2a1e-5b7d-4c9a-a1e2-3d4f5a6b7c8d ``` ```text filename="Output" ID 8f3c2a1e-5b7d-4c9a-a1e2-3d4f5a6b7c8d Action suspend_compute Status finished Branch ID br-lively-sunset-123456 Endpoint ID ep-cool-king-123456 Failures Count 0 Total Duration Ms 84 Created At 2026-11-05T14:24:09Z Updated At 2026-11-05T14:24:09Z ``` --- [Document source](https://neon.com/docs/cli/orgs.md) --- > Summary: The `neon orgs` CLI command lists the Neon organizations you belong to and shows one organization's details. Its subcommands also list, inspect, update, and remove members, list and send invitations, and get, set, or remove the organization's monthly spending limit. Use it to look up an org ID before running org-scoped commands, or to manage an organization from the terminal. # Neon CLI command: orgs List and inspect organizations, and manage members, invitations, and the spending limit Last updated: 2026-11-05 The `orgs` command lists the organizations you belong to, shows one organization, and manages its members, invitations, and monthly spending limit. For background, see [Manage organizations](https://neon.com/docs/manage/orgs-manage). Every subcommand except `list` takes `--org-id`. Without it, the CLI uses the organization in your [`.neon` context file](https://neon.com/docs/cli/link#the-neon-context-file), then the only organization you belong to. Otherwise, it fails and asks you to pass `--org-id`. Changing a member's role, removing a member, and setting or removing the spending limit require an organization Admin. Subcommands: [get](https://neon.com/docs/cli/orgs#get), [invitations](https://neon.com/docs/cli/orgs#invitations), [list](https://neon.com/docs/cli/orgs#list), [members](https://neon.com/docs/cli/orgs#members), [spending-limit](https://neon.com/docs/cli/orgs#spending-limit) ## neon orgs list Lists all organizations associated with the authenticated Neon CLI user. ```bash neon orgs list [options] ``` List your organizations with the default `table` output format. The organization in your [`.neon` context file](https://neon.com/docs/cli/link#the-neon-context-file) is marked `[current]`: ```bash neon orgs list ``` ```text filename="Output" Organizations ID Name Plan org-xxxxxxxx-xxxxxxxx [current] Example Org Launch org-yyyyyyyy-yyyyyyyy Another Org Free ``` List your organizations with `--output json`, which also shows the fields omitted from the `table` output, such as the handle and timestamps. JSON keeps the API's plan ID (for example, `launch`) rather than the display name: ```bash neon orgs list -o json ```
Show output ```json [ { "id": "org-xxxxxxxx-xxxxxxxx", "name": "Example Org", "handle": "example-org-xxxxxxxx", "plan": "launch", "created_at": "2026-04-22T16:50:41Z", "managed_by": "console", "updated_at": "2026-06-28T15:38:26Z", "require_mfa": false } ] ```
## neon orgs get Shows an organization's details. Pass the organization ID as an argument or with `--org-id`. ```bash neon orgs get [id] [options] ``` | Option | Description | Type | Default | Required | | ---------- | ---------------------------------------------------------------------- | ------ | ------- | :------: | | `--org-id` | Organization ID. Defaults to the linked organization, or your only one | string | — | No | ```bash neon orgs get org-xxxxxxxx-xxxxxxxx ``` ```text filename="Output" ID org-xxxxxxxx-xxxxxxxx Name Example Org Handle example-org-xxxxxxxx Plan Scale Created At 2026-09-10T16:36:29Z ``` ## neon orgs members Lists, inspects, updates, and removes the members of an organization. ```bash neon orgs members [options] ``` | Option | Description | Type | Default | Required | | ---------- | ---------------------------------------------------------------------- | ------ | ------- | :------: | | `--org-id` | Organization ID. Defaults to the linked organization, or your only one | string | — | No | Subcommands: [get](https://neon.com/docs/cli/orgs#members-get), [list](https://neon.com/docs/cli/orgs#members-list), [remove](https://neon.com/docs/cli/orgs#members-remove), [update](https://neon.com/docs/cli/orgs#members-update) ### neon orgs members list Lists members with their email and organization role. Use the `ID` column as the `` for the other `members` subcommands. JSON and YAML output keep the API's shape: each item has a `member` object and a `user` object. ```bash neon orgs members list [options] ``` | Option | Description | Type | Default | Required | | ---------- | ---------------------------------------------------------------------- | ------ | ------- | :------: | | `--org-id` | Organization ID. Defaults to the linked organization, or your only one | string | — | No | ```bash neon orgs members list ``` ```text filename="Output" Members of org-xxxxxxxx-xxxxxxxx ID Email Role Joined At a1b2c3d4-1111-4a2b-8c3d-0123456789ab alex@example.com admin 2026-09-10T16:36:29Z b2c3d4e5-2222-4b3c-9d4e-123456789abc dana@example.com admin 2026-09-25T18:18:32Z ``` ### neon orgs members get Shows one member. ```bash neon orgs members get [options] ``` | Option | Description | Type | Default | Required | | ---------- | ---------------------------------------------------------------------- | ------ | ------- | :------: | | `--org-id` | Organization ID. Defaults to the linked organization, or your only one | string | — | No | ```bash neon orgs members get a1b2c3d4-1111-4a2b-8c3d-0123456789ab ``` ### neon orgs members update Changes a member's organization role. The role sets the member's baseline access across every project in the organization. See [Organization roles](https://neon.com/docs/manage/user-permissions#organization-roles). `--role` accepts `admin`, `editor`, `viewer`, or `collaborator`. `member` is a legacy alias for `editor`. Some roles may not be available for every organization. ```bash neon orgs members update [options] ``` | Option | Description | Type | Default | Required | | ---------- | ------------------------------------------------------------------------------------------------ | ------ | ------- | :------: | | `--role` | The new organization role Possible values: `admin`, `member`, `editor`, `viewer`, `collaborator` | string | — | Yes | | `--org-id` | Organization ID. Defaults to the linked organization, or your only one | string | — | No | ```bash neon orgs members update b2c3d4e5-2222-4b3c-9d4e-123456789abc --role viewer ``` ### neon orgs members remove Removes a member from the organization. ```bash neon orgs members remove [options] ``` | Option | Description | Type | Default | Required | | ---------- | ---------------------------------------------------------------------- | ------ | ------- | :------: | | `--org-id` | Organization ID. Defaults to the linked organization, or your only one | string | — | No | ```bash neon orgs members remove b2c3d4e5-2222-4b3c-9d4e-123456789abc ``` ## neon orgs invitations Lists and sends invitations to join an organization. ```bash neon orgs invitations [options] ``` | Option | Description | Type | Default | Required | | ---------- | ---------------------------------------------------------------------- | ------ | ------- | :------: | | `--org-id` | Organization ID. Defaults to the linked organization, or your only one | string | — | No | Subcommands: [create](https://neon.com/docs/cli/orgs#invitations-create), [list](https://neon.com/docs/cli/orgs#invitations-list) ### neon orgs invitations list Lists pending invitations. ```bash neon orgs invitations list [options] ``` | Option | Description | Type | Default | Required | | ---------- | ---------------------------------------------------------------------- | ------ | ------- | :------: | | `--org-id` | Organization ID. Defaults to the linked organization, or your only one | string | — | No | ```bash neon orgs invitations list ``` ```text filename="Output" Invitations to org-xxxxxxxx-xxxxxxxx ID Email Role Invited At c3d4e5f6-3333-4c4d-8e5f-23456789abcd zhang@example.com viewer 2026-11-05T14:26:14Z ``` ### neon orgs invitations create Invites people by email. Repeat `--email` to invite several people at once. Every invitee gets the same `--role`. Neon emails each one, and anyone who already has a Neon account joins right away. [Organization API keys](https://neon.com/docs/manage/api-keys#types-of-api-keys) can't send invitations. Use a personal API key instead. ```bash neon orgs invitations create [options] ``` | Option | Description | Type | Default | Required | | ---------- | --------------------------------------------------------------------------------------------------------------- | ------ | ------- | :------: | | `--email` | Email address to invite. Repeat to invite several | array | — | Yes | | `--role` | The organization role every invitee gets Possible values: `admin`, `member`, `editor`, `viewer`, `collaborator` | string | — | Yes | | `--org-id` | Organization ID. Defaults to the linked organization, or your only one | string | — | No | ```bash neon orgs invitations create --email dana@example.com --email zhang@example.com --role editor ``` ## neon orgs spending-limit Gets, sets, and removes the organization's monthly spending limit, which the Console calls the [spending notification](https://neon.com/docs/introduction/spending-notifications) threshold. Available on the Launch and Scale plans. ```bash neon orgs spending-limit [options] ``` | Option | Description | Type | Default | Required | | ---------- | ---------------------------------------------------------------------- | ------ | ------- | :------: | | `--org-id` | Organization ID. Defaults to the linked organization, or your only one | string | — | No | Subcommands: [delete](https://neon.com/docs/cli/orgs#spending-limit-delete), [get](https://neon.com/docs/cli/orgs#spending-limit-get), [set](https://neon.com/docs/cli/orgs#spending-limit-set) ### neon orgs spending-limit get Shows the monthly spending limit, or `Not set`. JSON and YAML output keep the API's `spending_limit_cents` field. ```bash neon orgs spending-limit get [options] ``` | Option | Description | Type | Default | Required | | ---------- | ---------------------------------------------------------------------- | ------ | ------- | :------: | | `--org-id` | Organization ID. Defaults to the linked organization, or your only one | string | — | No | ```bash neon orgs spending-limit get ``` ```text filename="Output" Spending limit for org-xxxxxxxx-xxxxxxxx Monthly Limit $500.00 ``` ### neon orgs spending-limit set Sets the monthly spending limit in US dollars, with up to two decimal places. Neon emails organization Admins at 80% and 100% of the limit. Reaching the limit doesn't suspend computes. ```bash neon orgs spending-limit set [options] ``` | Option | Description | Type | Default | Required | | ---------- | ---------------------------------------------------------------------- | ------ | ------- | :------: | | `--org-id` | Organization ID. Defaults to the linked organization, or your only one | string | — | No | ```bash neon orgs spending-limit set 500 ``` ### neon orgs spending-limit delete Removes the monthly spending limit. ```bash neon orgs spending-limit delete [options] ``` | Option | Description | Type | Default | Required | | ---------- | ---------------------------------------------------------------------- | ------ | ------- | :------: | | `--org-id` | Organization ID. Defaults to the linked organization, or your only one | string | — | No | ```bash neon orgs spending-limit delete ``` ```text filename="Output" Spending limit removed from org-xxxxxxxx-xxxxxxxx ``` --- [Document source](https://neon.com/docs/cli/plugins.md) --- > Summary: The Neon CLI `plugins` command installs the `neon-postgres` plugin into coding agents that support plugin marketplaces, such as Claude Code, Cursor, and Codex. The plugin bundles Neon's agent skills and MCP access. Run it with no flags for an interactive walkthrough, or pass `--agent` and `-y` to pick the agents and skip the prompts. # Neon CLI command: plugins Install the Neon plugin into coding agents that support plugin marketplaces Last updated: 2026-11-01 The `plugins` command installs the `neon-postgres` plugin into coding agents that support plugin marketplaces, so tools like Claude Code, Cursor, and Codex know how to work with Neon. The plugin bundles [Neon's agent skills](https://neon.com/docs/ai/agent-skills) and the [Neon MCP Server](https://neon.com/docs/ai/neon-mcp-server) in one package. ```bash neon plugins ``` [Install the Neon CLI](https://neon.com/docs/cli/install) with `npm i -g neon@latest`, or run it once with `npx neon@latest plugins`. With no flags it runs an interactive walkthrough: pick the agents, then confirm. Pass flags to skip the prompts and script it. Without a terminal, pass `-y` to install into detected agents, or name agents with `--agent`. **plugins vs skills vs mcp:** Use [`neon plugins`](https://neon.com/docs/cli/plugins) for agents that support plugin marketplaces, where the plugin bundles skills and MCP in one. For the full setup, use [`neon init`](https://neon.com/docs/cli/init); for skills or the MCP server on their own, use [`neon skills`](https://neon.com/docs/cli/skills) or [`neon mcp`](https://neon.com/docs/cli/mcp). `plugins` runs via `npx`, so it needs Node.js; without it the command stops with a message to install Node.js and retry. ## Usage ```bash neon plugins [options] ``` ## Options | Option | Description | Type | Default | Required | | --------------- | --------------------------------------------------------------------------------------------- | ------- | ------- | :------: | | `--agent`, `-a` | Coding agent to install into (repeatable). Skips the agent picker. Values listed below | array | — | No | | `--yes`, `-y` | Skip prompts. Detected agents (project folders, else the host CLI agent, else installed apps) | boolean | `false` | No | ### Choosing agents Without `--agent`, the interactive command lists the supported agents, pre-selects the ones it detects, and lets you toggle the selection. In non-interactive mode, `-y` installs into every detected agent. Pass `--agent ` (repeatable) to name agents explicitly and skip the picker. The agents that support plugins are `claude-code`, `claude-desktop`, `codex`, `cursor`, `github-copilot-cli`, `grok-build`, `kimi-code`, and `vscode`. Several also accept aliases: `claude` for `claude-code`, `grok` for `grok-build`, and `copilot`, `github-copilot`, or `vs-code` for `vscode`. Passing an unknown agent stops the command and prints the supported list. An agent with no plugin support is skipped when others can install, or stops the command when it's the only one selected. Agents that share a target collapse into one: Claude Desktop and Claude Code both write to `claude-code`, and VS Code and the GitHub Copilot CLI both write to `github-copilot`. ### Install location `plugins` installs the plugin user-level, so it applies to every project. There's no project-level install. The `--global` flag from earlier versions is still accepted and does the same thing as the default, so existing scripts keep working (Neon CLI 8.23.2 and later). ## Examples Run the interactive install: ```bash neon plugins ``` Install into a specific agent, skipping every prompt: ```bash neon plugins --agent claude-code -y ``` ```text filename="Output" Plugins Scope Plugin Agent Status user neon-postgres claude-code installed Installed the Neon plugin (user). ``` Install into several agents at once: ```bash neon plugins --agent cursor --agent claude-code ``` Install non-interactively into every detected agent: ```bash neon plugins -y ``` --- [Document source](https://neon.com/docs/cli/postgres.md) --- > Summary: The Neon CLI `postgres` command (aliases `pg` and `lakebase`) groups the Lakebase Postgres commands: `computes`, `databases`, `roles`, `connection-string`, and `psql`. Use this reference for `neon postgres computes`, which lists, inspects, resizes, suspends, starts, restarts, and deletes the computes in a Neon project. The other subcommands match their top-level forms, such as `neon roles` and `neon psql`. # Neon CLI command: postgres Manage computes, databases, and roles, and connect to Lakebase Postgres, from one command group The `postgres` command groups the commands that work with Lakebase Postgres in a Neon project: [computes](https://neon.com/docs/cli/postgres#computes), [databases](https://neon.com/docs/cli/databases), [roles](https://neon.com/docs/cli/roles), [connection strings](https://neon.com/docs/cli/connection-string), and [psql](https://neon.com/docs/cli/psql). Its aliases are `pg` and `lakebase`, so `neon pg roles list` and `neon lakebase roles list` work too. `computes` is only available under `postgres`. The other subcommands run the same command as their top-level spelling, so `neon postgres roles list` and `neon roles list` do the same thing. Both spellings work. If `--project-id` is omitted, the CLI resolves it from your [context file](https://neon.com/docs/cli/link), auto-selects when your account has only one project, and otherwise asks you to pass `--project-id`. Subcommands: [computes](https://neon.com/docs/cli/postgres#computes), [connection-string](https://neon.com/docs/cli/postgres#connection-string), [databases](https://neon.com/docs/cli/postgres#databases), [psql](https://neon.com/docs/cli/postgres#psql), [roles](https://neon.com/docs/cli/postgres#roles) ## neon postgres computes Manages the computes in a Neon project. Aliases: `compute`, `endpoints`, and `endpoint`. For background, see [Manage computes](https://neon.com/docs/manage/computes). ```bash neon postgres computes [options] ``` | Option | Description | Type | Default | Required | | -------------- | ----------- | ------ | ------- | :------: | | `--project-id` | Project ID | string | — | No | Subcommands: [delete](https://neon.com/docs/cli/postgres#computes-delete), [get](https://neon.com/docs/cli/postgres#computes-get), [list](https://neon.com/docs/cli/postgres#computes-list), [restart](https://neon.com/docs/cli/postgres#computes-restart), [start](https://neon.com/docs/cli/postgres#computes-start), [suspend](https://neon.com/docs/cli/postgres#computes-suspend), [update](https://neon.com/docs/cli/postgres#computes-update) `update`, `start`, `suspend`, `restart`, and `delete` wait until the change is applied. Pass `--no-wait` to return as soon as the API accepts the request. To add a compute, use [`neon branches add-compute`](https://neon.com/docs/cli/branches#add-compute). ### neon postgres computes list Lists computes. With `--branch`, or when your `.neon` context file pins a branch, it lists that branch's computes. Otherwise it lists every compute in the project. `--all-branches` lists every compute in the project even when `.neon` pins a branch. ```bash neon postgres computes list [options] ``` | Option | Description | Type | Default | Required | | ---------------- | ------------------------------------------------------------------------------ | ------- | ------- | :------: | | `--all-branches` | List every compute in the project, ignoring --branch and the branch .neon pins | boolean | `false` | No | | `--branch` | Branch ID or name | string | — | No | | `--project-id` | Project ID | string | — | No | ```bash neon postgres computes list --branch main ``` ```text filename="Output" Computes on main ID Branch ID Type Current State Autoscaling Limit Min Cu Autoscaling Limit Max Cu ep-cool-king-123456 br-lively-sunset-123456 read_write active 0.25 2 ``` ### neon postgres computes get Shows a compute's details, including its host, state, autoscaling limits, and scale-to-zero timeout. ```bash neon postgres computes get [options] ``` | Option | Description | Type | Default | Required | | -------------- | ----------- | ------ | ------- | :------: | | `--project-id` | Project ID | string | — | No | ```bash neon postgres computes get ep-cool-king-123456 ```
Show output ```text ID ep-cool-king-123456 Branch ID br-lively-sunset-123456 Type read_write Current State active Host ep-cool-king-123456.us-east-2.aws.neon.tech Region ID aws-us-east-2 Autoscaling Limit Min Cu 0.25 Autoscaling Limit Max Cu 2 Suspend Timeout Seconds 600 Disabled false Last Active 2026-11-05T14:46:05Z Created At 2026-11-05T14:46:01Z ```
### neon postgres computes update Changes a compute's size, scale-to-zero timeout, name, or connection access. It sends only the options you pass, and fails if you pass none. When the change is applied, it prints the compute. ```bash neon postgres computes update [options] ``` | Option | Description | Type | Default | Required | | ------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------- | ------- | :------: | | `--cu` | The number of Compute Units. Could be a fixed size (e.g. "2") or a range delimited by a dash (e.g. "0.5-3"). | string | — | No | | `--disabled` | Restrict connections to the compute. Disabling schedules a suspend. Use --disabled=false to allow connections again. | boolean | — | No | | `--name` | Name of the compute | string | — | No | | `--suspend-timeout` | Scale-to-zero idle timeout, in seconds, before the compute suspends. `0` uses the plan default; `-1` disables scale-to-zero (never suspends). Minimum is plan-dependent (Scale: 60); maximum 604800 (one week). Free cannot change it; Launch can only enable or disable; Scale can set any value. | number | — | No | | `--wait` | Wait until the change is applied. Use --no-wait to return as soon as the API accepts it | boolean | `true` | No | | `--project-id` | Project ID | string | — | No | Set autoscaling to 0.25 to 2 compute units (CU) and suspend after 10 minutes of inactivity: ```bash neon postgres computes update ep-cool-king-123456 --cu 0.25-2 --suspend-timeout 600 ``` `--disabled` restricts connections to the compute and schedules a suspend. Pass `--disabled=false` to allow connections again: ```bash neon postgres computes update ep-cool-king-123456 --disabled=false ``` ### neon postgres computes start Starts a suspended compute and prints it once it's active. ```bash neon postgres computes start [options] ``` | Option | Description | Type | Default | Required | | -------------- | --------------------------------------------------------------------------------------- | ------- | ------- | :------: | | `--wait` | Wait until the change is applied. Use --no-wait to return as soon as the API accepts it | boolean | `true` | No | | `--project-id` | Project ID | string | — | No | ```bash neon postgres computes start ep-cool-king-123456 ``` ### neon postgres computes suspend Suspends a compute and prints it once it's idle. ```bash neon postgres computes suspend [options] ``` | Option | Description | Type | Default | Required | | -------------- | --------------------------------------------------------------------------------------- | ------- | ------- | :------: | | `--wait` | Wait until the change is applied. Use --no-wait to return as soon as the API accepts it | boolean | `true` | No | | `--project-id` | Project ID | string | — | No | ```bash neon postgres computes suspend ep-cool-king-123456 ``` ### neon postgres computes restart Restarts a compute and prints it once it's back up. ```bash neon postgres computes restart [options] ``` | Option | Description | Type | Default | Required | | -------------- | --------------------------------------------------------------------------------------- | ------- | ------- | :------: | | `--wait` | Wait until the change is applied. Use --no-wait to return as soon as the API accepts it | boolean | `true` | No | | `--project-id` | Project ID | string | — | No | ```bash neon postgres computes restart ep-cool-king-123456 ``` With `--no-wait`, the output says the restart was accepted but not yet applied: ```text filename="Output" Compute ep-cool-king-123456: restart accepted, not yet applied ``` ### neon postgres computes delete Deletes a compute, such as a [read replica](https://neon.com/docs/introduction/read-replicas) you no longer need, and prints a confirmation. ```bash neon postgres computes delete [options] ``` | Option | Description | Type | Default | Required | | -------------- | --------------------------------------------------------------------------------------- | ------- | ------- | :------: | | `--wait` | Wait until the change is applied. Use --no-wait to return as soon as the API accepts it | boolean | `true` | No | | `--project-id` | Project ID | string | — | No | ```bash neon postgres computes delete ep-divine-tree-123456 ``` ```text filename="Output" Compute ep-divine-tree-123456 deleted ``` ## neon postgres databases Lists, creates, and deletes databases. It's the same command as [`neon databases`](https://neon.com/docs/cli/databases), which documents its subcommands and options. ```bash neon postgres databases [options] ``` ```bash neon postgres databases list ``` ## neon postgres roles Lists, inspects, creates, and deletes roles, and resets their passwords. It's the same command as [`neon roles`](https://neon.com/docs/cli/roles), which documents its subcommands and options. ```bash neon postgres roles [options] ``` ```bash neon postgres roles list ``` ## neon postgres connection-string Prints a connection string for a branch. Alias: `cs`. It's the same command as [`neon connection-string`](https://neon.com/docs/cli/connection-string), which documents its options. ```bash neon postgres connection-string [branch] [options] ``` ```bash neon pg cs main ``` ## neon postgres psql Opens a psql session on a branch. It's the same command as [`neon psql`](https://neon.com/docs/cli/psql), which documents its options. ```bash neon postgres psql [branch] [options] [-- psql-args] ``` ```bash neon postgres psql main -- -c "SELECT version()" ``` --- [Document source](https://neon.com/docs/cli/profile.md) --- > Summary: The `neon profile` CLI command creates, lists, rotates, and removes named credential sets, so one machine can hold logins for several Neon accounts. Use it to see which profile is active, which account each one holds, rotate a profile's key, and revoke a profile's token when you no longer need it. # Neon CLI command: profile Manage named sets of Neon credentials Last updated: 2026-10-19 A profile is a pointer to a credentials file, so one machine can hold logins for several Neon accounts and pick between them per command. Create one with `neon profile create`, or by authenticating with a name: ```bash neon profile create work ``` `--profile` is a [global option](https://neon.com/docs/cli#global-options), so you can pass it to any command to act as that profile's account. `neon me` confirms which account a profile holds: ```bash neon me --profile work ``` ```text filename="Output" Login alex Email alex@domain.com Name Alex Lopez Authentication OAuth (profile work) ``` Naming a profile that doesn't exist is an error, not a silent fall back to `DEFAULT`. Credentials resolve from `--profile`, then `NEON_PROFILE`, then a profile named `DEFAULT`. Nothing persists between commands, so set `NEON_PROFILE` to avoid repeating the flag. `DEFAULT` is what a plain `neon login` gives you, with or without profiles. Profiles live in `profiles.json` in the config directory, which is `~/.config/neon` by default (`XDG_CONFIG_HOME` moves it) and `--config-dir` overrides per command. That file maps each profile name to the credentials file that holds its token. The CLI manages it for you, so create and remove profiles with the commands below rather than editing it by hand. **Note: Profiles carry credentials, not context** A profile sets which account you act as, not which organization or project. Commands that need one still resolve it from `--org-id`, the `.neon` context file, or a prompt: ```bash neon projects list --profile work --org-id org-example-12345678 ``` See [set-context](https://neon.com/docs/cli/set-context) and [checkout](https://neon.com/docs/cli/checkout) for pinning an org or branch. Subcommands: [create](https://neon.com/docs/cli/profile#create), [list](https://neon.com/docs/cli/profile#list), [remove](https://neon.com/docs/cli/profile#remove), [rotate-key](https://neon.com/docs/cli/profile#rotate-key) ## neon profile create Creates a profile. It holds either a browser sign-in or an API key, never both. ```bash neon profile create [options] ``` | Option | Description | Type | Default | Required | | -------------- | ------------------------------------------------------------------------------------------------------------------------ | ------- | ------- | :------: | | `--api-key` | API key to store, or "-" to read it from stdin | string | — | No | | `--keyring` | Store the credential in the OS keyring. Per profile; later create without the flag stays there. See `neon profile list`. | boolean | — | No | | `--mint` | Sign in once in the browser, then store a freshly minted API key and nothing else | boolean | `false` | No | | `--org-id` | With --mint, mint a key for this organization instead of your account | string | — | No | | `--project-id` | With --mint, mint a key that can access only this project | string | — | No | Most of the time you create a profile one of two ways: a browser sign-in, or a freshly minted key. Sign in with the browser, the same as `neon login --profile work`: ```bash neon profile create work ``` With `--mint`, sign in once in the browser, then store a freshly minted API key and nothing else. This leaves no browser session behind, which suits CI: ```bash neon profile create ci --mint --org-id org-abc-123 ``` Pass `--project-id` with `--mint` to mint a key that can access only one project, or `--org-id` to mint it for an organization instead of your account. If you already have a key minted elsewhere, store it with `--api-key`. Pipe it to `--api-key -`, where `-` tells the CLI to read the key from stdin, so it stays out of the process arguments where `ps` would otherwise expose it. Here `$KEY` is a shell variable holding the key: ```bash echo "$KEY" | neon profile create work --api-key - ``` Passing the key as the argument value works too, but avoid it outside a throwaway shell, since the key is then visible to other processes: ```bash neon profile create work --api-key "$KEY" ``` `create` ignores `NEON_API_KEY`, so exporting that variable doesn't supply the key here. Pass it explicitly with `--api-key`. By default the credential is saved to a `credentials.json` file. Pass `--keyring` to store it in your operating system's keyring instead. The choice is saved per profile. `neon profile list` shows `keyring` in the `Credentials` column for a keyring profile, and `-o json` includes a `storage` field. ## neon profile list Lists each profile, the account it holds, and where its credentials live. `Active` marks the profile this invocation would use. ```bash neon profile list [options] ``` ```bash neon profile list ``` ```text filename="Output" Profiles Active Name Account Auth Credentials Scope * DEFAULT 3f8a1c2e-5b7d-4e9a-8c1f-2d6b9e0a4c53 oauth credentials.json account work alex@example.com oauth credentials.work.json account ci alex@example.com api key credentials.ci.json account org org-example-12345678 api key credentials.org.json org org-example-12345678 project org-example-12345678 api key credentials.project.json project cool-darkness-12345678 laptop alex@example.com oauth keyring account ``` `Account` is the recorded email label, the user ID when there's no label (as with a `DEFAULT` profile from a plain `neon login`), or the organization identifier for an organization- or project-scoped key. `Auth` shows how the profile authenticates (`oauth` for a browser sign-in, `api key` for a stored key). `Credentials` gives the credentials file's name, or `keyring` when the credential is kept in the OS keyring. `Scope` shows what the credential can reach: `account` for a browser sign-in or an account key, or `org ` or `project ` for a key limited to that organization or project. Pass `-o json` to also get two more fields: `file`, which reports whether the credential could be read (`ok`, or else `missing`, `invalid`, or `unreadable`), and `storage`, which is `file` or `keyring`. ## neon profile rotate-key Mints a fresh API key for a profile, at the same scope, and revokes the one it replaces. Anything using the old key stops working immediately. ```bash neon profile rotate-key [options] ``` ```bash neon profile rotate-key ci ``` This works for account-scoped keys, where the profile's own credential can mint the replacement. An organization- or project-scoped key can't rotate itself, since only a personal credential can mint those keys. Re-mint it with a browser sign-in instead, matching the original scope: ```bash neon profile create ci --mint --org-id org-example-12345678 ``` The `rotate-key` error names the exact command to run for the profile's scope. ## neon profile remove Revokes the profile's token, then removes the profile. Anything using that token stops working immediately. Pass `--yes` to skip the confirmation prompt. In CI, a removal without `--yes` is refused rather than assumed. The credentials file is deleted only if the CLI created it. A profile pointing outside the config directory is left on disk, and the command says so, so the secret is still there. If the token can't be revoked, the profile is still removed locally, and the command tells you the token may remain valid. Revoke it yourself from the [Neon Console](https://console.neon.tech) if it was an API key. Removing the last profile deletes `profiles.json` too, leaving the config directory as it was before you created any profiles. ```bash neon profile remove [options] ``` | Option | Description | Type | Default | Required | | ------------- | ---------------------------- | ------- | ------- | :------: | | `--yes`, `-y` | Skip the confirmation prompt | boolean | `false` | No | Remove a profile: ```bash neon profile remove work ``` ```text filename="Output" ? Remove profile "work" (alex@domain.com)? ' (y/N) ``` The prompt defaults to no, so pressing Enter leaves the profile in place. To switch accounts rather than discard one, authenticate again under the same name: ```bash neon login --profile work ``` --- [Document source](https://neon.com/docs/cli/projects.md) --- > Summary: The Neon CLI `neon projects` command provides subcommands to list, create, update, delete, recover, and retrieve Neon projects from the terminal, including support for region selection (AWS and Azure), blocking public or VPC connections, and filtering shared projects. Use this page when you need CLI automation for project lifecycle tasks or to recover a deleted project within its 7-day recovery window. Projects created via the CLI default to Postgres 18; use `--pg-version` to select a different major version. # Neon CLI command: projects List, create, update, delete, recover, and get Neon projects Last updated: 2026-10-09 The `projects` command lists, creates, updates, deletes, recovers, and retrieves Neon projects from the terminal. For information about projects in Neon, see [Projects](https://neon.com/docs/manage/projects). Subcommands that show no options table accept only the [global options](https://neon.com/docs/cli#global-options). If `--project-id` is omitted, the CLI resolves it from your [context file](https://neon.com/docs/cli/link), auto-selects when your account has only one project, and otherwise asks you to pass `--project-id`. Subcommands: [create](https://neon.com/docs/cli/projects#create), [delete](https://neon.com/docs/cli/projects#delete), [get](https://neon.com/docs/cli/projects#get), [list](https://neon.com/docs/cli/projects#list), [recover](https://neon.com/docs/cli/projects#recover), [update](https://neon.com/docs/cli/projects#update) ## neon projects list Lists projects that belong to your Neon account, as well as any projects that were shared with you. ```bash neon projects list [options] ``` | Option | Description | Type | Default | Required | | -------------------- | ------------------------------------------------------------- | ------- | ------- | :------: | | `--org-id` | List projects of a given organization | string | — | No | | `--recoverable-only` | List only deleted projects within their deletion grace period | boolean | — | No | - List projects in your [default organization](https://neon.com/docs/reference/glossary#default-organization). If no organization context is set, the CLI prompts you to select one. ```bash neon projects list ``` ```text Projects ID Name Region ID Created At crimson-voice-12345678 frontend aws-us-east-2 2026-04-15T11:17:30Z calm-thunder-12121212 backend aws-us-east-2 2026-04-10T15:21:01Z nameless-hall-87654321 billing aws-us-east-2 2026-04-10T14:35:17Z Shared with you ID Name Region ID Created At noisy-fire-212121 API aws-eu-central-1 2026-04-22T18:41:13Z ``` In the default table, your currently linked project (the one recorded in `.neon`) is marked `[current]` next to its name. List all projects belonging to a specific organization: ```bash neon projects list --org-id org-xxxx-xxxx ``` List projects that can be recovered (deleted within the last 7 days): ```bash neon projects list --recoverable-only ``` ```text filename="Output" Projects ID Name Region ID Created At Deleted At Recoverable Until crimson-voice-12345 myproject aws-us-east-2 2026-04-15T11:17:30Z 2026-04-16T14:22:15Z 2026-04-23T14:22:15Z ``` ## neon projects create Creates a Neon project. ```bash neon projects create [options] ``` | Option | Description | Type | Default | Required | | ---------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ------- | ------------------ | :------: | | `--block-public-connections` | When set, connections from the public internet are disallowed. This supersedes the AllowedIPs list. This parameter is under active development and its semantics may change in the future. | boolean | — | No | | `--block-vpc-connections` | When set, connections using VPC endpoints are disallowed. This parameter is under active development and its semantics may change in the future. | boolean | — | No | | `--cu` | The number of Compute Units. Could be a fixed size (e.g. "2") or a range delimited by a dash (e.g. "0.5-3"). | string | — | No | | `--database` | The database name. If not specified, the default database name, `neondb`, will be used. | string | neondb | No | | `--hipaa` | Enable HIPAA compliance for the project. | boolean | — | No | | `--name` | The project name. If not specified, the name will be identical to the generated project ID | string | project ID | No | | `--org-id` | The project's organization ID | string | — | No | | `--pg-version` | Major PostgreSQL version (14–19). Version 19 is available only in regions where it has been enabled. | number | — | No | | `--psql` | Connect to a new project via psql | boolean | `false` | No | | `--region-id` | The region ID. Possible values: aws-us-west-2, aws-ap-southeast-1, aws-ap-southeast-2, aws-eu-central-1, aws-us-east-2, aws-us-east-1, azure-eastus2 | string | — | No | | `--role` | The role name. If not specified, the default role name, `{database_name}_owner`, will be used. | string | \{database}\_owner | No | | `--secrets` | Include connection credentials in command output. Use --no-secrets to omit them | boolean | `true` | No | | `--set-context` | Set the current context to the new project | boolean | `false` | No | The `--region-id` value defaults to `aws-us-east-2` if not specified. `--block-public-connections` and `--block-vpc-connections` are part of [Private Networking](https://neon.com/docs/guides/neon-private-networking); `--hipaa` enables [HIPAA compliance](https://neon.com/docs/security/hipaa) for the project. **Note:** Neon projects created using the CLI use the default Postgres version, which is Postgres 18. To create a project with a different Postgres version, pass `--pg-version`: ```bash neon projects create --name mynewproject --pg-version 17 ``` You can also enable logical replication for an existing project with `neon projects update --enable-logical-replication` (add `--yes` to skip the confirmation prompt), and create protected branches with `neon branches create --protected`. Create a project with a user-defined name in a specific region: ```bash neon projects create --name mynewproject --region-id aws-us-west-2 ``` ```text filename="Output" Project ID muddy-wood-123456 Name mynewproject Region ID aws-us-west-2 Created At 2026-07-09T17:04:29Z Connection URIs Connection URI postgresql://[user]:[password]@[neon_hostname]/[dbname] ``` **Tip:** The Neon CLI provides a `neon connection-string` command you can use to extract a connection URI programmatically. See [the connection-string command](https://neon.com/docs/cli/connection-string). Create a project with a specific Postgres major version: ```bash neon projects create --name mynewproject --pg-version 17 ``` Omit the connection string from the output, keeping it out of terminal scrollback and CI logs: ```bash neon projects create --name mynewproject --no-secrets ``` Needs Neon CLI 4.9.0+; older versions ignore `--no-secrets` and still print the connection string. - Create a project with `--output json`, which returns the full project response data and is the recommended format for scripts and agents. The output below was captured on an earlier CLI version; new projects report `"pg_version": 18`. ```bash neon projects create --output json ```
Show output ```json { "project": { "data_storage_bytes_hour": 0, "data_transfer_bytes": 0, "written_data_bytes": 0, "compute_time_seconds": 0, "active_time_seconds": 0, "cpu_used_sec": 0, "id": "long-wind-77910944", "platform_id": "aws", "region_id": "aws-us-east-2", "name": "long-wind-77910944", "provisioner": "k8s-pod", "default_endpoint_settings": { "autoscaling_limit_min_cu": 1, "autoscaling_limit_max_cu": 1, "suspend_timeout_seconds": 0 }, "pg_version": 17, "proxy_host": "us-east-2.aws.neon.tech", "branch_logical_size_limit": 204800, "branch_logical_size_limit_bytes": 214748364800, "store_passwords": true, "creation_source": "neon", "history_retention_seconds": 604800, "created_at": "2026-08-04T16:16:45Z", "updated_at": "2026-08-04T16:16:45Z", "consumption_period_start": "0001-01-01T00:00:00Z", "consumption_period_end": "0001-01-01T00:00:00Z", "owner_id": "e56ad68e-7f2f-4d74-928c-9ea25d7e9864" }, "connection_uris": [ { "connection_uri": "postgresql://alex:AbC123dEf@ep-cool-darkness-123456.us-east-2.aws.neon.tech/dbname?sslmode=require&channel_binding=require", "connection_parameters": { "database": "dbname", "password": "AbC123dEf", "role": "alex", "host": "ep-cool-darkness-123456.us-east-2.aws.neon.tech", "pooler_host": "ep-cool-darkness-123456-pooler.us-east-2.aws.neon.tech" } } ] } ```
Create a project and connect to it with `psql` immediately. Arguments after `--` are passed through to psql, so you can run an `.sql` file or a query on creation: ```bash neon projects create --psql neon projects create --psql -- -f dump.sql neon projects create --psql -- -c "SELECT version()" ``` Create a project and set the Neon CLI project context to it: ```bash neon projects create --set-context ``` ## neon projects update Updates a Neon project. The `` is the project ID, which you can obtain by listing your projects or from the **Settings** page in the Neon Console. ```bash neon projects update [options] ``` | Option | Description | Type | Default | Required | | ------------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------- | ------- | :------: | | `--block-public-connections` | When set, connections from the public internet are disallowed. This supersedes the AllowedIPs list. This parameter is under active development and its semantics may change in the future. Use --block-public-connections=false to set the value to false. | boolean | — | No | | `--block-vpc-connections` | When set, connections using VPC endpoints are disallowed. This parameter is under active development and its semantics may change in the future. Use --block-vpc-connections=false to set the value to false. | boolean | — | No | | `--cu` | The number of Compute Units. Could be a fixed size (e.g. "2") or a range delimited by a dash (e.g. "0.5-3"). | string | — | No | | `--enable-logical-replication` | Enable logical replication for all project endpoints. This suspends active endpoints and cannot be disabled. | boolean | — | No | | `--hipaa` | Enable HIPAA compliance for the project. | boolean | — | No | | `--name` | The project name | string | — | No | | `--yes` | Skip the confirmation prompt when enabling logical replication. | boolean | `false` | No | `--block-public-connections`, `--block-vpc-connections`, and `--hipaa` behave as described under [projects create](https://neon.com/docs/cli/projects#create). Update the project name: ```bash neon projects update muddy-wood-123456 --name dev_project_1 ``` ```text filename="Output" ID muddy-wood-123456 Name dev_project_1 Region ID aws-us-west-2 Created At 2026-07-09T17:04:29Z ``` Block connections from the public internet (see [restrict public internet access](https://neon.com/docs/guides/neon-private-networking#restrict-public-internet-access)): ```bash neon projects update orange-credit-12345678 --block-public-connections=true ``` Enable [logical replication](https://neon.com/docs/guides/logical-replication-neon) for the project. This suspends active endpoints and cannot be disabled, so `--yes` skips the confirmation prompt: ```bash neon projects update orange-credit-12345678 --enable-logical-replication --yes ``` ## neon projects delete Deletes a Neon project. The `` is the project ID. ```bash neon projects delete [options] ``` ```bash neon projects delete muddy-wood-123456 ``` ```text filename="Output" ID muddy-wood-123456 Name dev_project_1 Region ID aws-us-west-2 Created At 2026-07-09T17:04:29Z ``` Verify the deletion with `neon projects list`. ## neon projects recover Recovers a deleted project within the deletion recovery period. The `` is the project ID, which you can obtain by listing recoverable projects with `neon projects list --recoverable-only`. ```bash neon projects recover [options] ``` ```bash neon projects recover crimson-voice-12345678 ``` ```text filename="Output" ID crimson-voice-12345678 Name myproject Region ID aws-us-east-2 Created At 2026-04-15T11:17:30Z ``` For details on what's recovered and what requires reconfiguration after recovery, see [Recover a deleted project](https://neon.com/docs/manage/projects#recover-a-deleted-project). ## neon projects get Retrieves details about a Neon project. The `` is the project ID. ```bash neon projects get [options] ``` ```bash neon projects get muddy-wood-123456 ``` ```text filename="Output" Project Name dev_project_1 ID muddy-wood-123456 Region ID aws-us-west-2 Postgres Version 18 Organization org-xxxxxxxx-xxxx Default Compute 0.25 CU History Retention 6 hours Created At 2026-07-09T17:04:29Z Updated At 2026-07-09T17:04:29Z ``` The table shows a detail view: Postgres version, organization, default compute range, and history retention alongside the identifiers. For the complete project record, including all settings and quotas, use `--output json`. --- [Document source](https://neon.com/docs/cli/psql.md) --- > Summary: Covers the usage of the `psql` command in the Neon CLI to open a psql session against a branch in your Neon project, including pooled connections and time-travel support. # Neon CLI command: psql Connect to a Neon database via psql Last updated: 2026-11-05 The `psql` command connects to a database in your Neon project using the `psql` client. It builds a connection string for the specified branch (or the default branch from your [context file](https://neon.com/docs/cli/link)) and launches `psql`, equivalent to running [`neon connection-string --psql`](https://neon.com/docs/cli/connection-string) as a dedicated top-level command. It's also available as [`neon postgres psql`](https://neon.com/docs/cli/postgres#psql). If `--project-id` is omitted, the CLI resolves it from your [context file](https://neon.com/docs/cli/link), auto-selects when your account has only one project, and otherwise asks you to pass `--project-id`. `--role-name` and `--database-name` are needed only when the branch has more than one role or database. ## Usage ```bash neon psql [branch] [options] [-- psql-args] ``` The `[branch]` is the branch name or ID. If omitted, the default branch from your context (or the project's default branch) is used. You can also use the point-in-time format `branch@timestamp` or `branch@lsn` for [time travel](https://neon.com/docs/guides/time-travel-assist) connections. Arguments after `--` are forwarded to `psql`. ## Options | Option | Description | Type | Default | Required | | ----------------- | ----------------------------------------------------------------------- | ------- | --------- | :------: | | `--database-name` | Database name | string | — | No | | `--endpoint-type` | Endpoint type | string | — | No | | `--pooled` | Use pooled connection | boolean | `false` | No | | `--project-id` | Project ID | string | — | No | | `--role-name` | Role name | string | — | No | | `--ssl` | SSL mode Possible values: `require`, `verify-ca`, `verify-full`, `omit` | string | `require` | No | `neon psql` uses the native `psql` binary from your `$PATH` if one is available, and otherwise falls back to a built-in TypeScript implementation, so no PostgreSQL client tools installation is required. The built-in implementation is a full port, not a simplified subset: it supports SCRAM-SHA-256 authentication, backslash commands (`\d`, `\dt`, `\d+`, etc.), tab completion, command history, and COPY. It's verified against Postgres 14 through 18. To force the built-in implementation in CI or other environments where native `psql` is present but you want consistent behavior, set `NEONCTL_PSQL_FALLBACK=1`. ## Examples Connect to the default branch: ```bash neon psql ``` Connect to a named branch. Projects created with the CLI or API get a default branch named `main`; Console-created projects use `production` (run `neon branches list` if you're unsure): ```bash neon psql main ``` Run a single query: ```bash neon psql main -- -c "SELECT version()" ``` Run an SQL file: ```bash neon psql main -- -f dump.sql ``` Connect to a branch at a specific point in time: ```bash neon psql main@2024-01-01T00:00:00Z ``` Use a pooled connection: ```bash neon psql --pooled ``` --- [Document source](https://neon.com/docs/cli/quickstart.md) --- > Summary: The Neon CLI quickstart installs neon on macOS, Windows, or Linux via Homebrew, npm, or bun, then authenticates using browser-based `neon login` or a personal API key. Use this page when setting up terminal access to Neon for the first time, before working through the full CLI reference. It also covers the `.neon` context file (`neon link`) to avoid repeating `--project-id` and `--org-id` flags, shell tab completion, and first commands like `neon projects list`, `neon branches create`, and `neon connection-string`. # Neon CLI quickstart Get set up with the Neon CLI in just a few steps Last updated: 2026-09-18 The Neon CLI lets you manage Neon directly from the terminal. This guide helps you set up and start using it. The CLI is invoked as `neon`; `neonctl` is an alias for `neon`, so commands work with either name. ## Install the CLI Choose your platform and install the Neon CLI: **macOS** **Install with Homebrew** ```bash brew install neonctl ``` **Install via npm** ```shell npm i -g neon ``` **Install with bun** ```bash bun install -g neon ``` **Windows** **Install via npm** ```shell npm i -g neon ``` **Install with bun** ```bash bun install -g neon ``` **Linux** **Install via npm** ```shell npm i -g neon ``` **Install with bun** ```bash bun install -g neon ``` Verify the installation by checking the CLI version: ```bash neon --version ``` For the latest version, refer to the [Neon CLI GitHub repository](https://github.com/neondatabase/neon-pkgs/tree/main/packages/cli). ## Authenticate Authenticate with your Neon account using one of these methods: **Web Authentication (recommended)** Run the command below to authenticate through your browser: ```bash neon login ``` This opens a browser window where you can authorize the CLI to access your Neon account. **API Key Authentication** Alternatively, use a personal Neon API key, which you can create in the Neon Console. See [Create a personal API key](https://neon.com/docs/manage/api-keys#create-a-personal-api-key). ```bash neon projects list --api-key ``` To avoid entering your API key with each command, set it as an environment variable: ```bash export NEON_API_KEY= ``` For more about authenticating, see [Neon CLI commands: login](https://neon.com/docs/cli/login). ## Link your project The easiest way to set up CLI context is with [`neon link`](https://neon.com/docs/cli/link). It guides you through organization and project selection and writes a `.neon` context file in your project directory. ```bash neon link ``` You can also link non-interactively for scripts and CI. `link` writes a complete context, so pin a branch with `--branch` (or pass `-y` to pin the project's default branch): ```bash neon link --org-id --project-id --branch main ``` **Tip:** If you run a CLI command without an organization context, the CLI prompts you to select an organization and offers to save it as your default, creating a `.neon` context file automatically. **Tip:** Once linked, you can run CLI commands from any subdirectory of your project; the CLI walks up parent folders to find the `.neon` file. The file is also automatically added to `.gitignore` so it's not committed by accident. **Info:** You can find your organization ID in the Neon Console by selecting your organization and navigating to **Settings**. You can find your Neon project ID by opening your project in the Neon Console and navigating to **Settings** > **General**. Either form of `neon link` creates a `.neon` file in your current directory with your project context. ```bash cat .neon ``` ```json { "projectId": "broad-surf-52155946", "orgId": "org-solid-base-83603457", "branch": "main" } ``` **Note: Deprecated** Earlier versions of the CLI used [`neon set-context`](https://neon.com/docs/cli/set-context) to write the `.neon` file directly. That command is deprecated in favor of `neon link`, prints a deprecation warning when you run it, and may be removed in a future release. Use `neon link` for new workflows. ## Enable shell completion Set up autocompletion to make using the CLI faster: **Bash** ```bash neon completion >> ~/.bashrc source ~/.bashrc ``` **Zsh** ```bash neon completion >> ~/.zshrc source ~/.zshrc ``` Now you can press **Tab** to complete Neon CLI commands and options. For further details, see [Neon CLI commands: completion](https://neon.com/docs/cli/completion). ## Common operations ### List your projects ```bash neon projects list ``` If no organization context is set, the CLI prompts you to select an organization. For more about the `projects` command, see [Neon CLI commands: projects](https://neon.com/docs/cli/projects). ### Create a branch ```bash neon branches create --name ``` Set your project context or specify `--project-id ` if you have more than one Neon project. To switch the active branch in your context file, use [`neon checkout`](https://neon.com/docs/cli/checkout): ```bash neon checkout ``` For more about the `branches` command, see [Neon CLI commands: branches](https://neon.com/docs/cli/branches). ### Get a connection string Get the connection string for the default branch in your project: ```bash neon connection-string ``` For a specific branch, specify the branch name: ```bash neon connection-string ``` To connect with `psql` directly, use the dedicated [`neon psql`](https://neon.com/docs/cli/psql) command: ```bash neon psql ``` For more about the `connection-string` command, see [Neon CLI commands: connection-string](https://neon.com/docs/cli/connection-string). ## Next steps Now that you're set up with the Neon CLI, you can: - Create more Neon projects with `neon projects create` - Manage your branches with various `neon branches` commands such as `reset`, `restore`, `rename`, `schema-diff`, and more - Create and manage databases with `neon databases` commands - Create and manage roles with `neon roles` commands - View the full set of Neon CLI commands available to you with `neon --help` For more details on all available commands, see the [CLI Reference](https://neon.com/docs/cli). --- [Document source](https://neon.com/docs/cli/realtime.md) --- > Summary: The Neon CLI `neon realtime` command manages Neon Realtime on a database branch. Use `enable` to provision Realtime and set the browser origins allowed to connect, `disable` to remove it, `rotate-secret` to replace its shared secret, and `subscribe` to stream a live SQL query. # Neon CLI command: realtime Manage Neon Realtime and subscribe to live queries from the CLI Last updated: 2026-11-05 The `realtime` command enables and disables [Neon Realtime](https://neon.com/docs/realtime/overview) on a branch and rotates the branch's Realtime secret. Once Realtime is on, you can stream a live SQL query's results with `neon realtime subscribe`, and [`neon env pull`](https://neon.com/docs/cli/env) writes the branch's `NEON_REALTIME_URL` and `NEON_REALTIME_SECRET` to your `.env`. To manage Realtime declaratively instead, add it to your `neon.ts` with [`neon config add realtime`](https://neon.com/docs/cli/config#add-realtime). Subcommands: [disable](https://neon.com/docs/cli/realtime#disable), [enable](https://neon.com/docs/cli/realtime#enable), [rotate-secret](https://neon.com/docs/cli/realtime#rotate-secret), [subscribe](https://neon.com/docs/cli/realtime#subscribe) If `--project-id` is omitted, the CLI reads it from your [context file](https://neon.com/docs/cli/link) or auto-selects your only project. If `--branch` is omitted, it uses the context file's branch, or the project's default branch. ## neon realtime enable Requests Realtime provisioning for a branch. Provisioning finishes in the background, usually within a few seconds. Run it again on a branch that already has Realtime to replace its allowed origins with the ones you pass. Without `--allowed-origin`, a re-run keeps the existing origins. ```bash neon realtime enable [options] ``` | Option | Description | Type | Default | Required | | ------------------ | ------------------------------------------------------------- | ------ | ------- | :------: | | `--allowed-origin` | Allowed browser origin (repeatable). "\*" allows every origin | array | — | No | | `--branch` | Branch ID or name | string | — | No | | `--project-id` | Project ID | string | — | No | `--allowed-origin` sets the browser origins allowed to connect. Repeat the flag for each origin, up to 16. Each value must be `*`, which allows every origin, or an `http` or `https` origin with no path, query, or fragment, such as `https://app.example.com`. `*` can't be combined with other origins. The CLI checks the values before it sends the request. By default, any browser origin can connect. Pass `--allowed-origin` to limit connections to the origins you list. A new branch starts with its parent's list. Child branches created from a Realtime-enabled branch have Realtime enabled automatically. A new list can take about a minute to apply after the change finishes. Allowed origins only restrict browsers: a client that sends no `Origin` header, such as a server, can connect either way. ```bash neon realtime enable --allowed-origin https://app.example.com --allowed-origin http://localhost:3000 ``` ```text Realtime enable requested for branch br-cool-darkness-123456. ``` ## neon realtime disable Requests Realtime deprovisioning for a branch. ```bash neon realtime disable [options] ``` | Option | Description | Type | Default | Required | | -------------- | ----------------- | ------ | ------- | :------: | | `--branch` | Branch ID or name | string | — | No | | `--project-id` | Project ID | string | — | No | ```bash neon realtime disable ``` ```text Realtime disable requested for branch br-cool-darkness-123456. ``` Disabling also discards the branch's Realtime secret, so apps using that branch's `NEON_REALTIME_SECRET` stop working. If you enable Realtime again later, the branch gets a new secret, so pull the env vars again. After you disable Realtime, `neon realtime subscribe` on that branch fails with an error that points you back to `neon realtime enable`. ## neon realtime rotate-secret Requests a new Realtime shared secret for a branch. Rotation runs in the background: until it finishes, the current secret keeps working. Once it finishes, the new secret takes over and the old one stops working, so update every app that uses it. ```bash neon realtime rotate-secret [options] ``` | Option | Description | Type | Default | Required | | -------------- | ----------------------------------------------- | ------- | ------- | :------: | | `--wait` | Wait for the Realtime secret rotation to finish | boolean | `true` | No | | `--branch` | Branch ID or name | string | — | No | | `--project-id` | Project ID | string | — | No | By default, the command waits up to a minute for the rotation to finish, then reminds you to pull the new secret. If the wait times out, the command exits with an error, but the rotation may still be in progress. With `--no-wait`, it prints only the "rotation requested" line and returns right away. If the rotation is still running, `neon env pull` waits for it to finish, then writes the new secret. ```bash neon realtime rotate-secret ``` ```text Realtime secret rotation requested for branch br-cool-darkness-123456. Realtime secret rotation completed for branch br-cool-darkness-123456. Run neon env pull --service realtime to update NEON_REALTIME_SECRET. ``` The command doesn't print the new secret. Write the new `NEON_REALTIME_SECRET` to your env file with [`neon env pull`](https://neon.com/docs/cli/env): ```bash neon env pull --service realtime ``` Every `rotate-secret` run replaces the secret, so only repeat the command when you want another rotation. ## neon realtime subscribe Runs a `SELECT` query as a live subscription and prints its results as they change. Use it to watch a table while you develop, or to check what a Realtime client would receive. For a guided walkthrough, see the [Realtime quickstart](https://neon.com/docs/realtime/quickstart). The branch needs Realtime enabled first: run `neon realtime enable`, or declare it in `neon.ts` with [`neon config add realtime`](https://neon.com/docs/cli/config#add-realtime) and apply. ```bash neon realtime subscribe "" [options] ``` | Option | Description | Type | Default | Required | | -------------- | -------------------------------- | ------- | ------- | :------: | | `--branch` | Branch ID or name | string | — | No | | `--changes` | Show raw rows and changes events | boolean | `false` | No | | `--project-id` | Project ID | string | — | No | The CLI resolves the branch's Realtime URL, secret, and database name for you, the same values [`neon env pull`](https://neon.com/docs/cli/env) writes, so you don't need a `.env` file first. If Realtime is still provisioning, it waits until it's ready. Quote the query so your shell passes it as one argument. If `--project-id` is omitted, it reads it from your [context file](https://neon.com/docs/cli/link) or auto-selects your only project. If `--branch` is omitted, it uses the context file's branch, or the project's default branch. The subscription runs until you press Ctrl+C, or until the server closes it or reports an error. ### Output The default table output is an append-only log, so it doesn't take over your terminal. It opens with a header naming the project, branch, database, mode, and query, then prints: - The initial result once, as a table. - One entry per transaction, labeled with its transaction ID and a `+inserted ~updated -deleted` count, listing each changed row with its change type. A deleted row shows its last known values. A row that changes position in an ordered result shows as `↔ move` with its values, and the count ends with `↔` and the number of rows that moved. - Connection state changes, such as connecting, live, and stale. Every entry starts with a UTC timestamp. The server can send a complete `rows` replacement instead of incremental `changes` at any point, and then `realtime subscribe` prints the full result again. Some queries, such as ones with `ORDER BY`, can get a complete replacement for a change. With `--changes`, it prints the raw events instead: a `rows` event with the complete current result, each row carrying a row ID, followed by `changes` events that list each change's type (`upsert`, `remove`, or `move`), row ID, and row. In table output, a `move` also shows `after_row_id`, the ID of the row it now follows, or `(head)` when it moved to the first position. A `rows` event replaces the full row set and invalidates earlier row IDs. With `--output json`, each event is one JSON object per line. With `--output yaml`, each event is a separate YAML document. Each event has a `type` of `snapshot` (the default mode), or `rows` or `changes` (with `--changes`). Machine-readable output carries only the events: the header and connection states are terminal-only. ### Examples Print the initial result, then a log of each transaction: ```bash neon realtime subscribe "SELECT * FROM items" ``` Here, a row is inserted, another is renamed, the new row is deleted, and then one transaction inserts a row and renames another:
Show output ```text Live query Project cool-darkness-12345678 Branch dev (br-small-cell-a1b2c3d4) Database neondb Mode Materialized result Query SELECT * FROM items [2026-10-13T13:49:35.168Z] Connecting… [2026-10-13T13:49:35.725Z] Initial snapshot · 2 rows ID Name 1 apple 2 banana [2026-10-13T13:49:35.726Z] Live — waiting for changes. [2026-10-13T13:49:42.349Z] Transaction 15379 · +1 ~0 -0 Change ID Name + insert 3 cherry [2026-10-13T13:49:45.992Z] Transaction 15380 · +0 ~1 -0 Change ID Name ~ update 2 blueberry [2026-10-13T13:49:49.636Z] Transaction 15381 · +0 ~0 -1 Change ID Name - delete 3 cherry [2026-10-13T13:49:53.284Z] Transaction 15382 · +1 ~1 -0 Change ID Name + insert 4 date ~ update 1 apricot ```
Print the raw `rows` and `changes` events: ```bash neon realtime subscribe --changes "SELECT * FROM items" ``` Here, a row is inserted, updated, and then deleted, one transaction each:
Show output ```text Live query Project cool-darkness-12345678 Branch dev (br-small-cell-a1b2c3d4) Database neondb Mode Raw changes Query SELECT * FROM items [2026-10-13T13:48:40.801Z] Connecting… [2026-10-13T13:48:41.461Z] Rows · 2 rows Row ID Row 97254c8a1b75b7e21a05f98973614ea5af20ae9f4d481389eddb304c9b331ecf {"id":1,"name":"apple"} 3045adcead9109b462b3c0e501e1c78c48b6cdbeb28bd3d3e01b83a61eaee302 {"id":2,"name":"banana"} [2026-10-13T13:48:41.462Z] Live — waiting for changes. [2026-10-13T13:48:48.072Z] Transaction 15370 · 1 upsert, 0 removals Type Row ID Row upsert 1257d5759a0894512f6859dd60b504e69cbf6f8d9d4d977ee9b3b396661928bf {"id":3,"name":"cherry"} [2026-10-13T13:48:51.750Z] Transaction 15371 · 1 upsert, 0 removals Type Row ID Row upsert 3045adcead9109b462b3c0e501e1c78c48b6cdbeb28bd3d3e01b83a61eaee302 {"id":2,"name":"blueberry"} [2026-10-13T13:48:55.376Z] Transaction 15372 · 0 upserts, 1 removal Type Row ID remove 1257d5759a0894512f6859dd60b504e69cbf6f8d9d4d977ee9b3b396661928bf ```
Stream events as newline-delimited JSON, for example to pipe into another tool. Each event is a full snapshot of the result: ```bash neon realtime subscribe "SELECT * FROM items ORDER BY id" --output json ``` ```json {"type":"snapshot","rows":[{"id":1,"name":"apple"},{"id":2,"name":"banana"}]} {"type":"snapshot","rows":[{"id":1,"name":"apple"},{"id":2,"name":"banana"},{"id":3,"name":"cherry"}]} {"type":"snapshot","rows":[{"id":1,"name":"apple"},{"id":2,"name":"blueberry"},{"id":3,"name":"cherry"}]} ``` --- [Document source](https://neon.com/docs/cli/roles.md) --- > Summary: The `neon roles` CLI command lists, inspects, creates, and deletes database roles in a Neon project and resets their passwords. Its subcommands target a specific branch or the project default. Use it when you need to add an admin or a scoped read-only or read-write role, create a passwordless role with `--no-login`, rotate a password, or remove a role from the command line. Role names are capped at 63 bytes; commands require the Neon CLI and either browser-based auth or an API key. # Neon CLI command: roles List, inspect, create, and delete database roles, and reset their passwords Last updated: 2026-11-05 From the terminal, the `roles` command lists, inspects, creates, and deletes roles in a Neon project, and resets their passwords. It's also available as [`neon postgres roles`](https://neon.com/docs/cli/postgres#roles). For information about roles in Neon, see [Manage roles](https://neon.com/docs/manage/roles). If `--project-id` is omitted, the CLI resolves it from your [context file](https://neon.com/docs/cli/link), auto-selects when your account has only one project, and otherwise asks you to pass `--project-id`. Subcommands: [create](https://neon.com/docs/cli/roles#create), [delete](https://neon.com/docs/cli/roles#delete), [get](https://neon.com/docs/cli/roles#get), [list](https://neon.com/docs/cli/roles#list), [reset-password](https://neon.com/docs/cli/roles#reset-password) ## neon roles list Lists roles. If you don't specify a branch ID or name with `--branch`, the command targets the project's default branch. This applies to all `roles` subcommands. ```bash neon roles list [options] ``` | Option | Description | Type | Default | Required | | -------------- | ----------------- | ------ | ------- | :------: | | `--branch` | Branch ID or name | string | — | No | | `--project-id` | Project ID | string | — | No | List roles with the default `table` output format: ```bash neon roles list ``` ```text filename="Output" Roles on main Name Created At neondb_owner 2026-06-19T18:27:19Z ``` The table is titled with the branch the roles belong to, so you can tell at a glance which branch you're looking at. List roles with the `--output` format set to `json`: ```bash neon roles list --output json ```
Show output ```json [ { "branch_id": "br-odd-frog-123456", "name": "neondb_owner", "protected": false, "created_at": "2026-06-28T10:17:28Z", "updated_at": "2026-06-28T10:17:28Z" } ] ```
## neon roles create Creates a role. The role name cannot exceed 63 bytes. ```bash neon roles create [options] ``` | Option | Description | Type | Default | Required | | -------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------- | ------- | :------: | | `--access` | admin joins neon\_superuser. read\_only grants SELECT; read\_write adds INSERT, UPDATE, DELETE. Scoped roles are created with SQL as the database owner and cover tables that owner owns, now and later Possible values: `admin`, `read_only`, `read_write` | string | `admin` | No | | `--database` | Database a read\_only or read\_write role is scoped to. Defaults to the branch's only database | string | — | No | | `--name` | Role name | string | — | Yes | | `--no-login` | Create a passwordless role that cannot login | boolean | — | No | | `--schema` | Schema a read\_only or read\_write role can use. Repeat for more. Defaults to public | array | — | No | | `--branch` | Branch ID or name | string | — | No | | `--project-id` | Project ID | string | — | No | ```bash neon roles create --name sally ``` ```text filename="Output" Role created on main Name sally Password npg_aBcDeFgH1234 Created At 2026-06-20T00:43:17Z ``` The create output includes the password Neon generated for the new role. Neon returns it only once, so copy it now, or run [`neon roles reset-password`](https://neon.com/docs/cli/roles#reset-password) later to get a new one. A `--no-login` role has no password, so no `Password` row appears. By default, a new role joins `neon_superuser`, which makes it an admin on every database. Pass `--access read_only` for a role that can only read, or `--access read_write` for one that can also insert, update, and delete rows. A scoped role applies to one database. Name it with `--database`, or leave it out when the branch has only one. Its access is limited to the `public` schema unless you pass `--schema`, and to tables owned by that database's owner, including tables the owner creates later. ```bash neon roles create --name reporting --access read_only ``` ```bash neon roles create --name app_writer --access read_write --database neondb --schema public ``` `--database` and `--schema` work only with `--access read_only` or `--access read_write`. ## neon roles get Shows a role's details. The `` is the role name. ```bash neon roles get [options] ``` | Option | Description | Type | Default | Required | | -------------- | ----------------- | ------ | ------- | :------: | | `--branch` | Branch ID or name | string | — | No | | `--project-id` | Project ID | string | — | No | ```bash neon roles get reporting ``` ```text filename="Output" Name reporting Branch ID br-lively-sunset-123456 Protected false Authentication Method password Created At 2026-11-05T14:24:30Z Updated At 2026-11-05T14:24:30Z ``` ## neon roles reset-password Generates a new password for a role and prints it. The old password stops working. By default the command waits until the compute applies the new password, so you can connect with it right away. With `--no-wait`, it returns as soon as the API accepts the reset. ```bash neon roles reset-password [options] ``` | Option | Description | Type | Default | Required | | -------------- | ------------------------------------------------------------------------------------------------------------- | ------- | ------- | :------: | | `--wait` | Wait until the compute applies the new password. Use --no-wait to return as soon as the API accepts the reset | boolean | `true` | No | | `--branch` | Branch ID or name | string | — | No | | `--project-id` | Project ID | string | — | No | ```bash neon roles reset-password sally ``` ```text filename="Output" Password reset for sally on main Name sally Password npg_aBcDeFgH1234 Created At 2026-06-20T00:43:17Z ``` ## neon roles delete Deletes a role. The `` is the role name. ```bash neon roles delete [options] ``` | Option | Description | Type | Default | Required | | -------------- | ----------------- | ------ | ------- | :------: | | `--branch` | Branch ID or name | string | — | No | | `--project-id` | Project ID | string | — | No | ```bash neon roles delete sally ``` ```text filename="Output" Role deleted from main Name sally Created At 2026-06-20T00:43:17Z ``` --- [Document source](https://neon.com/docs/cli/set-context.md) --- > Summary: The `set-context` Neon CLI command saves a project ID, organization ID, or branch to a `.neon` context file so subsequent commands run against that project or org without requiring `--project-id` or `--org-id` flags each time. Use this command when working repeatedly against the same project to eliminate repetitive flag passing across a CLI session. Context is stored in a `.neon` file (or a named `--context-file`) found by walking up the directory tree to the project root, supports multiple independent named files, and persists until reset with `neon set-context` or deleted manually. # Neon CLI command: set-context Set default project context for CLI sessions to avoid repeating project ID Last updated: 2026-10-09 The `set-context` command sets a background context for your CLI sessions, so you don't have to specify the project ID in every command. The context is saved to a default `.neon` file in the current directory, or to a [named context file](https://neon.com/docs/cli/set-context#using-a-named-context-file) of your choice, and stays in place until you reset it or remove the file. **Note: Deprecated** `set-context` is deprecated in favor of [`neon link`](https://neon.com/docs/cli/link), which writes the same `.neon` context file. It still works but prints a deprecation warning when you run it, and may be removed in a future release. Use `neon link` to set project context; it verifies your inputs and infers your organization. For a write-without-checks behavior like `set-context` (for example, in scripts), use `neon link --no-checks` with `--org-id`, `--project-id`, and `--branch`. To switch branches, use [`neon checkout`](https://neon.com/docs/cli/checkout). **Tip: How the CLI finds your `.neon` file** When you run a command, the CLI starts in your current directory and checks for a `.neon` file. If it does not find one, it checks the parent directory, then the parent of that, and so on until it finds a `.neon` file or reaches your home directory. This means you can run commands from any subdirectory of a linked project without re-specifying `--project-id`. To write context to a specific file or location, use `--context-file`. ## Usage ```bash neon set-context [options] ``` To save the context to a file other than the default `.neon` file, add the global `--context-file ` option. You can switch contexts by providing different files. ## Options | Option | Description | Type | Default | Required | | -------------- | --------------- | ------ | ------- | :------: | | `--branch-id` | Branch ID | string | — | No | | `--org-id` | Organization ID | string | — | No | | `--project-id` | Project ID | string | — | No | Set at least one of these options. ## Using the default context file Set the context to the default `.neon` file: ```bash neon set-context --project-id patient-frost-50125040 --org-id org-bright-sky-12345678 ``` List all branches for this project with `branches list`, without including `--project-id` or `--org-id`, even if you belong to multiple organizations or have multiple projects: ```bash neon branches list ``` ```text filename="Output" Name ID Current State Expires At Created At development br-raspy-meadow-123456 ready never 2026-11-28T19:19:11Z [default] main br-curly-bar-123456 ready never 2026-10-23T12:49:41Z ``` ## Using a named context file Set the context to the context file of your choice: ```bash neon set-context --project-id plain-waterfall-84865553 --context-file Documents/MyContext ``` List all branches with `branches list`. The context file provides the project: ```bash neon branches list --context-file Documents/MyContext ``` ```text filename="Output" Name ID Current State Expires At Created At development br-soft-base-123456 ready never 2026-11-21T18:41:47Z [default] main br-young-bush-123456 ready never 2026-11-21T18:00:10Z staging br-billowing-union-123456 ready never 2026-11-21T18:44:22Z ``` **Note:** These two `branches list` commands use independent contexts in the same account: the default `.neon` file points to `patient-frost-50125040`, while the named context file points to `plain-waterfall-84865553`. You can set as many context files as you'd like, using unique names or different directories. ## Setting context when creating a new project Use `--set-context` to set the project context at creation time: ```bash neon projects create --name MyLatest --set-context ``` This creates a hidden `.neon` file by default with the following context: ```json { "projectId": "quiet-water-76237589" } ``` Commands that would normally require `--project-id` now default to this context. ## Reset or remove context To clear the current context, either: 1. Run the `set-context` command with no options: ```bash neon set-context ``` 2. Delete the `.neon` file (or your custom `--context-file`): ```bash rm .neon # Or for a custom context file: rm your_context_file ``` ## `.gitignore` on first create The first time a `.neon` file is created in a directory, the CLI adds `.neon` to `.gitignore` in that same folder: - If no `.gitignore` exists, the CLI creates one with a single `.neon` line. - If `.gitignore` already exists, the CLI appends `.neon` only if it is not already listed. This keeps local project settings out of git by default. If you want to commit `.neon` and share context with your team, remove the entry from `.gitignore`. The CLI will not re-add it when updating an existing `.neon` file. **Note:** Neon does not save any confidential information to the context file (for example, auth tokens). You can safely commit this file to your repository or share with others. --- [Document source](https://neon.com/docs/cli/skills.md) --- > Summary: The Neon CLI `skills` command installs [Neon agent skills](/docs/ai/agent-skills) into your coding agents so they know how to work with Neon. Run it with no flags for an interactive walkthrough, or pass flags to pick the skills and agents and skip the prompts. Use `neon skills update` to refresh installed skills to their latest versions, and `neon skills status` to check whether they're current. # Neon CLI command: skills Install, update, and check Neon agent skills in your coding agents Last updated: 2026-11-02 The `skills` command installs [Neon agent skills](https://neon.com/docs/ai/agent-skills) into your coding agents, so tools like Cursor and Claude Code know how to work with Neon's Postgres, AI Gateway, Object Storage, and Functions. ```bash neon skills ``` [Install the Neon CLI](https://neon.com/docs/cli/install) with `npm i -g neon@latest`, or run it once with `npx neon@latest skills`. With no flags it runs an interactive walkthrough: pick the agents, then the skills, then confirm. Pass flags to skip the prompts and script it. Without a terminal, pass `-y` or `--skill` to tell it which skills to install; `--agent` alone isn't enough. **skills vs init:** For the full setup, use [`neon init`](https://neon.com/docs/cli/init). For just one piece: `neon skills` (skills), [`neon plugins`](https://neon.com/docs/cli/plugins) (skills and MCP), or [`neon mcp`](https://neon.com/docs/cli/mcp) (MCP server). `skills` runs via `npx`, so it needs Node.js 22.20.0+; older or missing Node stops the command with an upgrade message. Subcommands: [status](https://neon.com/docs/cli/skills#status), [update](https://neon.com/docs/cli/skills#update) ## neon skills ```bash neon skills [command] [options] ``` | Option | Description | Type | Default | Required | | --------------- | ------------------------------------------------------------------------------------------------------------------------------- | ------- | ------- | :------: | | `--agent`, `-a` | Coding agent to install into (repeatable). Skips the agent picker. Values listed below | array | — | No | | `--global` | Install user-level skills (skills CLI -g). Default is this directory | boolean | `false` | No | | `--skill`, `-s` | Skill to install (repeatable). Skips the skill picker. Does not select agents. Values listed below | array | — | No | | `--yes`, `-y` | Skip prompts. Detected agents (project folders, else the host CLI agent). --global uses installed apps, else the host CLI agent | boolean | `false` | No | ### Choosing agents Without `--agent`, the interactive command lists all supported agents, pre-selects the ones it detects, and lets you toggle the selection. In non-interactive mode, `-y` installs into every detected agent. Pass `--agent ` (repeatable) to name agents explicitly and skip the picker. The supported agents are `antigravity`, `cline`, `cline-cli`, `claude-code`, `claude-desktop`, `codex`, `cursor`, `factory-droid`, `fx`, `gemini-cli`, `goose`, `github-copilot-cli`, `grok-build`, `hermes`, `junie`, `kilo-code`, `kimi-code`, `kiro-cli`, `opencode`, `pi`, `vscode`, `windsurf`, and `zed`. A few also accept aliases (`claude` for `claude-code`, `copilot` for `vscode`, `gemini` for `gemini-cli`). Passing an unknown agent stops the command and prints the current supported list. An agent that can't install skills is skipped with a warning. Agents that share a target collapse into one: Claude Desktop and Claude Code both write to `claude-code`, and VS Code and the GitHub Copilot CLI both write to `github-copilot`. ### Choosing skills Without `--skill`, the interactive command lets you pick from the catalog, and `-y` installs the default set. Pass `--skill ` (repeatable) to name skills explicitly and skip the picker. The available skills are: | Skill | Installed by default | | ------------------------------- | -------------------- | | `neon` | Yes | | `neon-ai-gateway` | Yes | | `neon-auth` | Yes | | `neon-functions` | Yes | | `neon-object-storage` | Yes | | `neon-postgres` | Yes | | `neon-realtime` | Yes | | `neon-postgres-agent-platforms` | No | Passing an unknown skill stops the command and prints the current supported list. The list of installable skills is built into each CLI release, so a skill that Neon publishes after the version you installed won't appear until you upgrade the CLI. ### Directory vs user-level By default `skills` installs into the current directory, so the setup travels with the repository. Pass `--global` to install user-level skills instead, which apply across your projects. ### Examples Run the interactive install: ```bash neon skills ``` Install non-interactively into every detected agent, using the default skills in the current directory: ```bash neon skills -y ``` Install named skills into a specific agent. Naming both `--skill` and `--agent` skips every prompt: ```bash neon skills -s neon -s neon-ai-gateway --agent cursor ``` ```text filename="Output" Skills Scope Skills Agents Status this directory neon, neon-ai-gateway cursor installed Wrote skills in this directory. ``` Install user-level skills that apply across your projects: ```bash neon skills --global ``` ## neon skills update Updates every skill installed in the current directory to its latest version, or every user-level skill with `--global`. It takes neither `--agent` nor `--skill`; it updates whatever is already installed. When there's nothing to update, the status is `none` and the `Detail` column shows the reason. ```bash neon skills update [options] ``` | Option | Description | Type | Default | Required | | --------------- | -------------------------------------------------------------------------------------------------- | ------- | ------- | :------: | | `--global` | Update user-level skills (skills CLI -g). Default is this directory | boolean | `false` | No | | `--yes`, `-y` | Skip the confirm prompt | boolean | `false` | No | | `--agent`, `-a` | Coding agent to install into (repeatable). Skips the agent picker. Values listed below | array | — | No | | `--skill`, `-s` | Skill to install (repeatable). Skips the skill picker. Does not select agents. Values listed below | array | — | No | Update skills in the current directory without prompting: ```bash neon skills update -y ``` ```text filename="Output" Skills Scope Status Detail this directory updated ✓ Updated 1 skill(s) ``` Update user-level skills: ```bash neon skills update --global -y ``` ## neon skills status Checks whether the Neon skills installed in the current directory match their source, or the user-level ones with `--global`. Passing `--agent` or `--skill` returns an error. The command reads the skills lock file that `neon skills` and `npx skills add` write: `skills-lock.json` in the current directory, or with `--global`, `~/.agents/.skill-lock.json` (`$XDG_STATE_HOME/skills/.skill-lock.json` when `XDG_STATE_HOME` is set). It checks only skills installed from a Neon repository, and leaves out skills pinned to a git ref. Skills installed through an agent's plugin marketplace aren't in these files, so they aren't checked. Unlike installing and updating, `status` doesn't run `npx`, so it works without Node.js 22.20.0. ```bash neon skills status [options] ``` | Option | Description | Type | Default | Required | | --------------- | ------------------------------------------------------------------------------------------------------------------------------- | ------- | ------- | :------: | | `--global` | Check user-level skills (skills CLI -g). Default is this directory | boolean | `false` | No | | `--agent`, `-a` | Coding agent to install into (repeatable). Skips the agent picker. Values listed below | array | — | No | | `--skill`, `-s` | Skill to install (repeatable). Skips the skill picker. Does not select agents. Values listed below | array | — | No | | `--yes`, `-y` | Skip prompts. Detected agents (project folders, else the host CLI agent). --global uses installed apps, else the host CLI agent | boolean | `false` | No | Each skill gets one of three statuses: - `up to date`: the installed copy matches the source. - `outdated`: the source has changed since you installed it. Run `neon skills update`, or `neon skills update --global` for user-level skills, to refresh it. - `not found upstream`: the skill no longer exists in its source repository. Check skills in the current directory: ```bash neon skills status ``` ```text filename="Output" Skills Scope Skill Status this directory neon outdated this directory neon-ai-gateway up to date Update them: neon skills update -y ``` Check user-level skills: ```bash neon skills status --global ``` Each run fetches the latest skill files from GitHub, so the command needs network access. If you hit the GitHub API rate limit, set `GITHUB_TOKEN` (or `GH_TOKEN`) and run the command again. ### Outdated skills warning You don't have to run `status` to find out. Once a day, after a command succeeds, other `neon` commands print a warning that names the outdated skills in the current directory and at the user level, followed by the update command for each: ```text filename="Output" WARNING: Neon agent skills have updates: user-level: neon-postgres, neon, neon-ai-gateway, neon-functions, neon-object-storage this directory: neon Update them: neon skills update --global -y neon skills update -y ``` The check runs in the background, so a new result shows up on a later command. The warning also appears when the CLI runs without a terminal, so coding agents see it too. It doesn't appear with `--output json` or `--output yaml`, in CI, in the standalone binary, or for `neon skills` commands. Set `NO_UPDATE_NOTIFIER` to turn it off, along with the CLI's update notice. --- [Document source](https://neon.com/docs/cli/snapshots.md) --- > Summary: The Neon CLI `snapshots` command provides subcommands (create, list, get, update, delete, restore, finalize, schedule) to manage point-in-time snapshots of your Neon branches. Use this reference for exact flags and syntax: snapshot a branch at an LSN or timestamp, set an expiration, restore a snapshot into a new or existing branch, and configure an automatic backup schedule. # Neon CLI command: snapshots Create, list, restore, and schedule branch snapshots from the terminal Last updated: 2026-09-29 The `snapshots` command creates, lists, updates, deletes, and restores snapshots of your Neon branches, and manages the automatic backup schedule of a branch. A snapshot captures the state of a branch at a point in time, so you can restore it later. For background on the feature, plans, and limits, see [Backup and restore](https://neon.com/docs/guides/backup-restore). If `--project-id` is omitted, the CLI resolves it from your [context file](https://neon.com/docs/cli/link), auto-selects when your account has only one project, and otherwise asks you to pass `--project-id`. Subcommands: [create](https://neon.com/docs/cli/snapshots#create), [delete](https://neon.com/docs/cli/snapshots#delete), [finalize](https://neon.com/docs/cli/snapshots#finalize), [get](https://neon.com/docs/cli/snapshots#get), [list](https://neon.com/docs/cli/snapshots#list), [restore](https://neon.com/docs/cli/snapshots#restore), [schedule](https://neon.com/docs/cli/snapshots#schedule), [update](https://neon.com/docs/cli/snapshots#update) ## neon snapshots create Creates a snapshot from a branch. By default, it snapshots the head of the branch from your context or the project's default branch. Use `--lsn` or `--timestamp` to capture an earlier point within the branch's [history window](https://neon.com/docs/introduction/history-window); the two options are mutually exclusive. ```bash neon snapshots create [options] ``` | Option | Description | Type | Default | Required | | ---------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------- | ------ | ------- | :------: | | `--branch`, `-b` | Branch id or name to snapshot. Defaults to the branch in your context, or the project's default branch. | string | — | No | | `--expires-at` | When the snapshot is automatically deleted (RFC 3339, e.g. 2025-12-31T23:59:59Z). Omit to keep it indefinitely. | string | — | No | | `--lsn` | Take the snapshot at this LSN (e.g. 0/1F3C8A0). Must fall within the branch's restore window. Mutually exclusive with --timestamp. | string | — | No | | `--name` | A name for the snapshot | string | — | No | | `--timestamp` | Take the snapshot at this point in time (RFC 3339, e.g. 2025-01-01T00:00:00Z). Must fall within the branch's restore window. Mutually exclusive with --lsn. | string | — | No | | `--project-id` | Project ID | string | — | No | Snapshot the head of a branch with a name: ```bash neon snapshots create --branch main --name pre-migration ``` Snapshot a branch at a specific LSN and set an expiration: ```bash neon snapshots create --branch main --lsn 0/1F3C8A0 --expires-at 2027-12-31T23:59:59Z ``` Snapshot a branch at a point in time: ```bash neon snapshots create --branch main --timestamp 2025-01-01T00:00:00Z ``` Timestamps and expiration times use RFC 3339 format. `--timestamp` must be in the past and `--expires-at` in the future. Omit `--expires-at` to keep the snapshot until you delete it; a manual snapshot's expiration has no maximum, unlike the 35-day cap on [scheduled snapshots](https://neon.com/docs/cli/snapshots#schedule-set). Snapshot names must be unique within a project. ## neon snapshots list Lists the snapshots in a project. ```bash neon snapshots list [options] ``` | Option | Description | Type | Default | Required | | -------------- | ----------- | ------ | ------- | :------: | | `--project-id` | Project ID | string | — | No | ```bash neon snapshots list ``` ## neon snapshots get Retrieves a snapshot by ID or name. An ID match wins over a name. ```bash neon snapshots get [options] ``` | Option | Description | Type | Default | Required | | -------------- | ----------- | ------ | ------- | :------: | | `--project-id` | Project ID | string | — | No | ```bash neon snapshots get snap-1234 ``` ## neon snapshots update Renames a snapshot or changes its expiration. Use `--clear-expiration` to keep a snapshot indefinitely; it's mutually exclusive with `--expires-at`. ```bash neon snapshots update [options] ``` | Option | Description | Type | Default | Required | | -------------------- | ------------------------------------------------------------------------------------- | ------- | ------- | :------: | | `--clear-expiration` | Clear the expiration so the snapshot is kept indefinitely. | boolean | — | No | | `--expires-at` | Set when the snapshot expires (RFC 3339). Mutually exclusive with --clear-expiration. | string | — | No | | `--name` | Rename the snapshot | string | — | No | | `--project-id` | Project ID | string | — | No | Rename a snapshot: ```bash neon snapshots update snap-1234 --name pre-migration ``` Clear a snapshot's expiration: ```bash neon snapshots update snap-1234 --clear-expiration ``` ## neon snapshots delete Deletes a snapshot by ID or name. ```bash neon snapshots delete [options] ``` | Option | Description | Type | Default | Required | | -------------- | ----------- | ------ | ------- | :------: | | `--project-id` | Project ID | string | — | No | ```bash neon snapshots delete snap-1234 ``` ## neon snapshots restore Restores a snapshot into a branch. By default, the restore is left un-finalized so you can inspect the restored branch first, then swap it in with [snapshots finalize](https://neon.com/docs/cli/snapshots#finalize). Pass `--finalize` to move computes onto the restored branch and swap it in for the target immediately. ```bash neon snapshots restore [options] ``` | Option | Description | Type | Default | Required | | ----------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------- | ------- | :------: | | `--finalize` | Finalize the restore immediately: move computes onto the restored branch and swap it in for the target. Without this, the restore is left un-finalized so you can inspect it first, then run `snapshots finalize `. | boolean | `false` | No | | `--name` | Name for the newly restored branch. Auto-generated when omitted. | string | — | No | | `--target-branch` | Branch id or name to restore the snapshot onto. Defaults to the snapshot's source branch. Recommended when you intend to finalize (replace an existing branch). | string | — | No | | `--project-id` | Project ID | string | — | No | Restore a snapshot to a new branch: ```bash neon snapshots restore snap-1234 --name recovered ``` Restore onto an existing branch un-finalized to preview, then finalize: ```bash neon snapshots restore snap-1234 --target-branch main ``` Restore onto a branch and swap it in immediately: ```bash neon snapshots restore snap-1234 --target-branch main --finalize ``` ## neon snapshots finalize Finalizes a previewed snapshot restore, swapping the restored branch in for the target. Use this after running `snapshots restore` without `--finalize`. The argument is the ID of the restored branch that `snapshots restore` created, not the target branch. The `restore` command prints the exact `finalize` command to run. ```bash neon snapshots finalize [options] ``` | Option | Description | Type | Default | Required | | -------------- | -------------------------------------------------------------------- | ------ | ------- | :------: | | `--name` | Name to give the replaced (old) branch. Auto-generated when omitted. | string | — | No | | `--project-id` | Project ID | string | — | No | ```bash neon snapshots finalize br-summer-water-au2msxjn ``` The replaced (old) branch is kept under an auto-generated name unless you set one with `--name`. ## Snapshot schedule The `snapshots schedule` subcommands get and set the automatic snapshot (backup) schedule of a branch. Subcommands: [get](https://neon.com/docs/cli/snapshots#schedule-get), [set](https://neon.com/docs/cli/snapshots#schedule-set) ### neon snapshots schedule get Gets a branch's automatic snapshot schedule. ```bash neon snapshots schedule get [options] ``` | Option | Description | Type | Default | Required | | ---------------- | ------------------------------------------------------------------------------------------- | ------ | ------- | :------: | | `--branch`, `-b` | Branch id or name. Defaults to the branch in your context, or the project's default branch. | string | — | No | | `--project-id` | Project ID | string | — | No | ```bash neon snapshots schedule get --branch main ``` ### neon snapshots schedule set Sets a branch's automatic snapshot schedule. Build a single-entry schedule with `--frequency` and its companion flags, or pass a full JSON schedule with `--schedule` for a multi-entry schedule (this overrides the single-entry flags). Pick one `--frequency`; that choice determines which of `--day` and `--hour` you must also set. The supported frequencies are: | `--frequency` | Also required | `--day` range | | ------------- | ----------------- | ------------------- | | `daily` | `--hour` (0-23) | not used | | `weekly` | `--day`, `--hour` | 1-7 (Monday-Sunday) | | `monthly` | `--day`, `--hour` | 1-31 | The server enforces these combinations, so a schedule missing a value its frequency needs is rejected with an error such as `daily schedules must specify the hour of the day`. Use `--retention` with any frequency to set how long each snapshot is kept. ```bash neon snapshots schedule set [options] ``` | Option | Description | Type | Default | Required | | ---------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------- | ------ | ------- | :------: | | `--branch`, `-b` | Branch id or name. Defaults to the branch in your context, or the project's default branch. | string | — | No | | `--day` | Day of the week/month (1-31) to take the snapshot (used with --frequency). | number | — | No | | `--frequency` | How often to take snapshots. Combine with --hour, --day, and --retention to build a single-entry schedule. Possible values: `daily`, `weekly`, `monthly` | string | — | No | | `--hour` | Hour of the day (0-23) to take the snapshot (used with --frequency). | number | — | No | | `--month` | Month of the year (1-12) to take the snapshot (used with --frequency). | number | — | No | | `--retention` | How long to keep each snapshot, in seconds (min 3600). Omit to keep indefinitely. | number | — | No | | `--schedule` | Full schedule as JSON, for multi-entry schedules, e.g. '\[\{"frequency":"daily","hour":3,"retention\_seconds":604800}]'. Overrides the single-entry flags. | string | — | No | | `--project-id` | Project ID | string | — | No | Of the options above, `--month` is the exception: none of the supported frequencies read it, so setting it has no effect on when snapshots are taken. Set a daily 03:00 snapshot kept for 7 days (604800 seconds): ```bash neon snapshots schedule set --branch main --frequency daily --hour 3 --retention 604800 ``` Set a weekly snapshot on Mondays at 04:00: ```bash neon snapshots schedule set --branch main --frequency weekly --day 1 --hour 4 ``` Set a multi-entry schedule with JSON: ```bash neon snapshots schedule set --branch main --schedule '[{"frequency":"daily","hour":3},{"frequency":"weekly","day":1,"hour":4}]' ``` `--retention` is in seconds, from 3600 (1 hour) to 3024000 (35 days). Omit it and scheduled snapshots are kept for 35 days, the maximum. Manual snapshots created with [snapshots create](https://neon.com/docs/cli/snapshots#create) follow the opposite rule: they never expire unless you set `--expires-at`. See [Snapshot retention](https://neon.com/docs/guides/backup-restore#snapshot-retention). --- [Document source](https://neon.com/docs/cli/status.md) --- > Summary: The Neon CLI `neon status` command shows the branch's live Neon state. It is an alias of `neon config status`, so you can check what is currently deployed without going through the config command group. # Neon CLI command: status Show the branch's live Neon state Last updated: 2026-07-01 The `status` command shows the branch's live Neon state. It is an alias of [`neon config status`](https://neon.com/docs/cli/config#status), so it reports the same information without the `config` prefix. ```bash neon status [options] ``` | Option | Description | Type | Default | Required | | ------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------- | ------- | ------- | :------: | | `--branch` | Branch ID or name | string | — | No | | `--config-json` | Print only the branch's live config as neon.ts-shaped JSON (services + branch tuning + preview), to stdout. Useful for scripting or copying into a neon.ts. | boolean | `false` | No | | `--current-branch` | Print only the linked branch name from the local .neon file (no network). Exits non-zero when no branch is pinned. | boolean | `false` | No | | `--project-id` | Project ID | string | — | No | ```bash neon status ``` --- [Document source](https://neon.com/docs/cli/triggers.md) --- > Summary: The Neon CLI `neon triggers` command manages function triggers on a branch: list, get, create, update, enable, disable, and delete triggers that invoke a Neon Function on a cron schedule or when an object is created in Object Storage. # Neon CLI command: triggers Create and manage function triggers that invoke a Neon Function on a cron schedule or when an object is created Last updated: 2026-10-09 The `triggers` command manages function triggers on a branch. A trigger invokes a [Neon Function](https://neon.com/docs/compute/functions/overview) on a cron schedule (`schedule`), or when an object is created in an [Object Storage](https://neon.com/docs/storage/overview) bucket (`storage_object_created`). Use it to run recurring work like a nightly report or cleanup job, or to process uploads as they land, without a separate scheduler. You deploy the function with [`neon functions deploy`](https://neon.com/docs/cli/functions), then point a trigger at it by slug. Triggers are branch-scoped. Pass `--project-id` and `--branch` to target a branch, or let the CLI resolve them from your [context file](https://neon.com/docs/cli/link). Triggers can also be inherited: a trigger created on a parent branch is visible on its child branches, where the `Inherited` column shows `true`. An inherited trigger stays disabled on the child until you enable it there with [`neon triggers enable`](https://neon.com/docs/cli/triggers#enable). Subcommands: [create](https://neon.com/docs/cli/triggers#create), [delete](https://neon.com/docs/cli/triggers#delete), [disable](https://neon.com/docs/cli/triggers#disable), [enable](https://neon.com/docs/cli/triggers#enable), [get](https://neon.com/docs/cli/triggers#get), [list](https://neon.com/docs/cli/triggers#list), [update](https://neon.com/docs/cli/triggers#update) ## neon triggers list Lists the triggers on the branch. ```bash neon triggers list [options] ``` | Option | Description | Type | Default | Required | | -------------- | ----------------- | ------ | ------- | :------: | | `--branch` | Branch ID or name | string | — | No | | `--project-id` | Project ID | string | — | No | ```bash neon triggers list --project-id solitary-heart-93902637 --branch main ``` The `Type` column shows each trigger's type, currently `schedule` or `storage_object_created`. `Schedule` holds the cron for schedule triggers; `Storage` holds the bucket (and prefix, if set) for storage triggers. ```text filename="Output" Trigger ID Name Type Function Slug Function Path Schedule Storage Enabled Inherited Next Run At trigger-12345678-90ab-cdef-1234-567890abcdef nightly-report schedule child404 / 0 6 * * * true false 2026-09-11T06:00:00.000000Z trigger-abcdef12-3456-7890-abcd-ef1234567890 on-upload storage_object_created ingest /object assets logos/ true false ``` ## neon triggers get Shows a single trigger by ID. ```bash neon triggers get [options] ``` | Option | Description | Type | Default | Required | | -------------- | ----------------- | ------ | ------- | :------: | | `--branch` | Branch ID or name | string | — | No | | `--project-id` | Project ID | string | — | No | ```bash neon triggers get trigger-12345678-90ab-cdef-1234-567890abcdef --project-id solitary-heart-93902637 --branch main --output json ```
Show output ```json { "type": "schedule", "trigger_id": "trigger-12345678-90ab-cdef-1234-567890abcdef", "function_slug": "child404", "name": "nightly-report", "function_path": "/", "schedule": { "cron": "0 6 * * *" }, "enabled": true, "version": 1390408, "next_run_at": "2026-09-11T06:00:00.000000Z", "inherited": false } ```
A `storage_object_created` trigger has `storage_object_created` (bucket and optional prefix) in place of `schedule`, and no `next_run_at`:
Show output ```json { "type": "storage_object_created", "trigger_id": "trigger-abcdef12-3456-7890-abcd-ef1234567890", "function_slug": "ingest", "name": "on-upload", "function_path": "/object", "storage_object_created": { "bucket_name": "assets", "prefix": "logos/" }, "enabled": true, "version": 1390512, "inherited": false } ```
## neon triggers create Creates a trigger that invokes a function on a cron schedule or when an object is created. `--function-slug` and `--name` are required, and the name must be unique on the branch. Choose the type with one of: - `--cron` for a `schedule` trigger, a five-field UTC cron expression. - `--bucket` for a `storage_object_created` trigger, with an optional `--prefix` to match only object keys under that prefix. `--cron` and `--bucket` are mutually exclusive (`Pass --cron or --bucket, not both.`), and `--prefix` requires `--bucket`. Object-created triggers (`--bucket` and `--prefix`) require Neon CLI 4.21.0 or later. On an older CLI, `--bucket` isn't recognized and `create` reports a missing `--cron` argument instead. ```bash neon triggers create [options] ``` | Option | Description | Type | Default | Required | | ----------------- | --------------------------------------------------------- | ------- | ------- | :------: | | `--bucket` | Object-storage bucket to watch (storage\_object\_created) | string | — | No | | `--cron` | Five-field UTC cron expression, e.g. '\*/15 \* \* \* \*' | string | — | No | | `--enabled` | Whether the trigger runs (default true) | boolean | — | No | | `--function-path` | Path the invocation is sent to (default '/') | string | — | No | | `--function-slug` | Slug of the function to invoke | string | — | Yes | | `--name` | Trigger name (unique per branch) | string | — | Yes | | `--prefix` | Object-key prefix to match (requires --bucket on create) | string | — | No | | `--branch` | Branch ID or name | string | — | No | | `--project-id` | Project ID | string | — | No | By default the invocation is sent to `/` and the trigger is enabled. Use `--function-path` to send it to another route, and `--enabled false` to create it in a disabled state. A schedule trigger: ```bash neon triggers create --function-slug child404 --name nightly-report --cron '0 6 * * *' --project-id solitary-heart-93902637 --branch main ``` ```text filename="Output" Trigger ID trigger-12345678-90ab-cdef-1234-567890abcdef Name nightly-report Type schedule Function Slug child404 Function Path / Schedule 0 6 * * * Enabled true Inherited false Next Run At 2026-09-11T06:00:00.000000Z ``` A storage trigger that fires when an object is created under `logos/` in the `assets` bucket: ```bash neon triggers create --function-slug ingest --name on-upload --bucket assets --prefix 'logos/' --function-path /object --project-id solitary-heart-93902637 --branch main ``` ## neon triggers update Updates a trigger. Pass at least one of `--function-slug`, `--name`, `--function-path`, or `--enabled`, plus the field matching the trigger's type: `--cron` for a schedule trigger, or `--bucket`/`--prefix` for a `storage_object_created` trigger. With no fields to change, the command returns an error. The type is fixed at creation, so passing `--cron` to a storage trigger, or `--bucket`/`--prefix` to a schedule trigger, is rejected (`Trigger is type ; ...`). Changing a schedule recomputes `Next Run At`. ```bash neon triggers update [options] ``` | Option | Description | Type | Default | Required | | ----------------- | --------------------------------------------------------- | ------- | ------- | :------: | | `--bucket` | Object-storage bucket to watch (storage\_object\_created) | string | — | No | | `--cron` | Five-field UTC cron expression | string | — | No | | `--enabled` | Whether the trigger runs | boolean | — | No | | `--function-path` | Path the invocation is sent to | string | — | No | | `--function-slug` | Slug of the function to invoke | string | — | No | | `--name` | Trigger name (unique per branch) | string | — | No | | `--prefix` | Object-key prefix to match | string | — | No | | `--branch` | Branch ID or name | string | — | No | | `--project-id` | Project ID | string | — | No | Reschedule a schedule trigger: ```bash neon triggers update trigger-12345678-90ab-cdef-1234-567890abcdef --cron '*/30 * * * *' --project-id solitary-heart-93902637 --branch main ``` Change the prefix a storage trigger matches: ```bash neon triggers update trigger-abcdef12-3456-7890-abcd-ef1234567890 --prefix 'incoming/' --project-id solitary-heart-93902637 --branch main ``` ## neon triggers enable Enables a trigger so it runs on its schedule. Enabling recomputes `Next Run At`. ```bash neon triggers enable [options] ``` | Option | Description | Type | Default | Required | | -------------- | ----------------- | ------ | ------- | :------: | | `--branch` | Branch ID or name | string | — | No | | `--project-id` | Project ID | string | — | No | ```bash neon triggers enable trigger-12345678-90ab-cdef-1234-567890abcdef --project-id solitary-heart-93902637 --branch main ``` ## neon triggers disable Disables a trigger without deleting it. A disabled trigger keeps its definition but does not run, and its `Next Run At` is cleared. Re-enable it with [`neon triggers enable`](https://neon.com/docs/cli/triggers#enable). ```bash neon triggers disable [options] ``` | Option | Description | Type | Default | Required | | -------------- | ----------------- | ------ | ------- | :------: | | `--branch` | Branch ID or name | string | — | No | | `--project-id` | Project ID | string | — | No | ```bash neon triggers disable trigger-12345678-90ab-cdef-1234-567890abcdef --project-id solitary-heart-93902637 --branch main ``` ## neon triggers delete Deletes a trigger. ```bash neon triggers delete [options] ``` | Option | Description | Type | Default | Required | | -------------- | ----------------- | ------ | ------- | :------: | | `--branch` | Branch ID or name | string | — | No | | `--project-id` | Project ID | string | — | No | ```bash neon triggers delete trigger-12345678-90ab-cdef-1234-567890abcdef --project-id solitary-heart-93902637 --branch main ``` ```text filename="Output" Trigger trigger-12345678-90ab-cdef-1234-567890abcdef deleted ``` --- [Document source](https://neon.com/docs/cli/vpc.md) --- > Summary: The Neon CLI `neon vpc` command controls Private Networking by registering, updating, removing, and checking VPC endpoints at the organization level, and by restricting or removing per-project VPC access. Use it when you need to limit Neon project connections to a specific AWS or Azure VPC rather than the public internet. # Neon CLI command: vpc Manage Private Networking VPC endpoints and project-level restrictions Last updated: 2026-07-01 The `vpc` command manages [Private Networking](https://neon.com/docs/guides/neon-private-networking) configurations in Neon. Use it to register VPC endpoints at the organization level and to restrict individual projects to connections from a specific VPC. Subcommands: [endpoint](https://neon.com/docs/cli/vpc#endpoint), [project](https://neon.com/docs/cli/vpc#project) ## VPC endpoints The `vpc endpoint` subcommands list, assign, remove, and check the status of VPC endpoints for a Neon organization. Subcommands: [assign](https://neon.com/docs/cli/vpc#endpoint-assign), [list](https://neon.com/docs/cli/vpc#endpoint-list), [remove](https://neon.com/docs/cli/vpc#endpoint-remove), [status](https://neon.com/docs/cli/vpc#endpoint-status) You only need `--org-id` if your Neon account belongs to more than one organization. If your account has a single organization, the CLI uses it automatically. Instead of passing IDs on each command, you can also set them in a [context file](https://neon.com/docs/cli/set-context#using-a-named-context-file) and reference it with the `--context-file` option. ### neon vpc endpoint list Lists the VPC endpoints configured for a Neon organization. ```bash neon vpc endpoint list [options] ``` | Option | Description | Type | Default | Required | | ------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------- | ------ | ------- | :------: | | `--org-id` | Organization ID | string | — | No | | `--region-id` | The region ID. Possible values: aws-us-west-2, aws-ap-southeast-1, aws-ap-southeast-2, aws-eu-central-1, aws-us-east-2, aws-us-east-1, azure-eastus2 | string | — | Yes | ```bash neon vpc endpoint list --org-id org-bold-bonus-12345678 --region-id aws-us-east-1 ``` ### neon vpc endpoint assign Adds or updates a VPC endpoint in a Neon organization. `add` and `update` are aliases for this command. ```bash neon vpc endpoint assign [options] ``` | Option | Description | Type | Default | Required | | ------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------- | ------ | ------- | :------: | | `--label` | An optional descriptive label for the VPC endpoint | string | — | No | | `--org-id` | Organization ID | string | — | No | | `--region-id` | The region ID. Possible values: aws-us-west-2, aws-ap-southeast-1, aws-ap-southeast-2, aws-eu-central-1, aws-us-east-2, aws-us-east-1, azure-eastus2 | string | — | Yes | Add a VPC endpoint to a Neon organization in a specific region: ```bash neon vpc endpoint assign vpce-1234567890abcdef0 --org-id org-bold-bonus-12345678 --region-id aws-us-east-1 ``` After you assign a VPC endpoint to a Neon organization, client connections are accepted from the corresponding VPC for all projects in the organization unless you restrict access at the project level with [vpc project restrict](https://neon.com/docs/cli/vpc#project-restrict). ### neon vpc endpoint remove Removes a VPC endpoint from a Neon organization. ```bash neon vpc endpoint remove [options] ``` | Option | Description | Type | Default | Required | | ------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------- | ------ | ------- | :------: | | `--org-id` | Organization ID | string | — | No | | `--region-id` | The region ID. Possible values: aws-us-west-2, aws-ap-southeast-1, aws-ap-southeast-2, aws-eu-central-1, aws-us-east-2, aws-us-east-1, azure-eastus2 | string | — | Yes | ```bash neon vpc endpoint remove vpce-1234567890abcdef0 --org-id org-bold-bonus-12345678 --region-id aws-us-east-1 ``` **Note:** A removed VPC endpoint cannot be added back to the Neon organization. ### neon vpc endpoint status Gets the status of a VPC endpoint in a Neon organization. ```bash neon vpc endpoint status [options] ``` | Option | Description | Type | Default | Required | | ------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------- | ------ | ------- | :------: | | `--org-id` | Organization ID | string | — | No | | `--region-id` | The region ID. Possible values: aws-us-west-2, aws-ap-southeast-1, aws-ap-southeast-2, aws-eu-central-1, aws-us-east-2, aws-us-east-1, azure-eastus2 | string | — | Yes | ```bash neon vpc endpoint status vpce-1234567890abcdef0 --org-id org-bold-bonus-12345678 --region-id aws-us-east-1 ``` ## Project VPC restrictions The `vpc project` subcommands list, configure, or remove VPC endpoint restrictions for specific projects in your Neon organization. By default, a project accepts connections from any VPC configured at the organization level. A restriction limits a project to connections from a specific VPC. Subcommands: [list](https://neon.com/docs/cli/vpc#project-list), [remove](https://neon.com/docs/cli/vpc#project-remove), [restrict](https://neon.com/docs/cli/vpc#project-restrict) You only need `--project-id` if your Neon account has more than one project. ### neon vpc project list Lists all VPC endpoint restrictions for a Neon project. ```bash neon vpc project list [options] ``` | Option | Description | Type | Default | Required | | -------------- | ----------- | ------ | ------- | :------: | | `--project-id` | Project ID | string | — | No | ```bash neon vpc project list --project-id orange-credit-12345678 ``` ### neon vpc project restrict Configures or updates a VPC endpoint restriction for a Neon project. `update` is an alias for this command. ```bash neon vpc project restrict [options] ``` | Option | Description | Type | Default | Required | | -------------- | -------------------------------------------------------------- | ------ | ------- | :------: | | `--label` | An optional descriptive label for the VPC endpoint restriction | string | — | No | | `--project-id` | Project ID | string | — | No | ```bash neon vpc project restrict vpce-1234567890abcdef0 --project-id orange-credit-12345678 ``` ### neon vpc project remove Removes a VPC endpoint restriction from a Neon project. ```bash neon vpc project remove [options] ``` | Option | Description | Type | Default | Required | | -------------- | ----------- | ------ | ------- | :------: | | `--project-id` | Project ID | string | — | No | ```bash neon vpc project remove vpce-1234567890abcdef0 --project-id orange-credit-12345678 ``` --- [Document source](https://neon.com/docs/community/ai-tools.md) --- > Summary: Claude slash commands in the Neon website repo automate common documentation tasks. Includes writing and rewriting pages, quality checks, MDX validation, PR descriptions, and glossary audits. Use this reference to choose the right command for each task. Commands are stored in .claude/commands/ and their sub-agents in .claude/agents/. # AI tools for documentation Claude commands available when working on Neon docs Last updated: 2026-08-27 The Neon website repo includes Claude commands for common documentation tasks. All changes are reviewed by humans via pull requests. Run `/list-doc-tools` in Claude to see the full list with descriptions, or browse the files under `.claude/commands/` in the [website repository](https://github.com/neondatabase/website). ## Writing content | Command | Description | | ----------------- | ----------------------------------------------------------------------------------------------------------------------------------------- | | `/write-content` | Full orchestrated workflow for new pages or substantial rewrites: IA specialist → drafter → refiner → syntax validator. | | `/simple-content` | Lighter single-thread workflow with confirmation at each step. Use for edits to existing pages or smaller additions. | | `/review-content` | Review a page for terminology, voice, structure, and MDX compliance. Produces a structured findings report with an option to apply fixes. | | `/humanize` | Remove AI writing patterns and apply Neon voice: contractions, active voice, direct address, concise sentences. | | `/improve-intro` | Rewrite just the first paragraph of a page to match Neon style. | | `/golden-corpus` | Load exemplary doc files by type for style and structure reference. | ## Docs quality | Command | Description | | -------------------- | ------------------------------------------------------------------------------------------------- | | `/validate` | Pre-commit check: frontmatter, stray h1 headings, navigation entry, image paths, em dashes, lint. | | `/check-consistency` | Find other pages that say the same thing; surface duplication and drift. | | `/update-glossary` | Find glossary gaps in a doc file (Mode A), or audit the glossary itself (Mode B). | | `/redirect-update` | After moving or renaming a file: add `redirectFrom`, update links and navigation. | ## Pull requests | Command | Description | | -------------------- | ---------------------------------------------------------------------------- | | `/update-pr` | Draft or update a PR title and description from changed files and commits. | | `/add-preview-links` | Add Vercel preview links to a PR description for every changed content file. | ## Reference and navigation | Command | Description | | ------------------------ | ---------------------------------------------------------------------------- | | `/navigation-principles` | Reference for `navigation.yaml` structure and how to add pages and sections. | | `/docs-prime` | Load project structure and key paths into context. | | `/list-doc-tools` | Print the full list of available commands with descriptions. | ## Agents The `.claude/agents/` directory contains specialized sub-agents used by the writing workflow commands: - **content-drafter**, **content-planner**, **content-refiner**, **ia-specialist**, **syntax-validator**, **supervisor** — write, plan, review, structure, validate, and orchestrate multi-step workflows --- [Document source](https://neon.com/docs/community/community-intro.md) --- > Summary: Ways to contribute to Neon's open-source serverless Postgres project: write docs, submit community guides, share example applications, or file bugs in Neon's GitHub repositories. Find the right entry point for contributing or connecting with other Neon users on Discord, X (Twitter), or YouTube. # Neon community Learn how to get involved in the Neon community Last updated: 2026-09-17 Neon is [open source](https://neon.com/docs/get-started/why-neon#neon-is-open-source) and has an enthusiastic user community worldwide. Here's how you can get involved: ## Contribute There are many ways to contribute to the Neon community: - **Neon Docs**: Share suggestions, contribute content, or write new guides to help others working with Neon. Check out our [Documentation Contribution Guide](https://neon.com/docs/community/contribution-guide) to get started. You can also create visual diagrams using our [Mermaid Diagrams Guide](https://neon.com/docs/community/mermaid-diagrams). If you want to consume our docs as markdown (e.g. for LLMs or APIs), see [Using Neon docs as markdown](https://neon.com/docs/community/llms-markdown-guide). - **Community Guides**: Share your knowledge by writing a guide about Neon or Postgres. These guides can help developers learn new technologies, techniques, and best practices. Submit your guide to our [Community Guides](https://neon.com/guides) page by forking the [Neon website repository](https://github.com/neondatabase/website) and creating a PR to add it to the [/content/guides](https://github.com/neondatabase/website/tree/main/content/guides) directory. - **Examples and applications**: Share examples and applications that demonstrate how to integrate Neon with different tools and platforms. Post your examples on our [Discord Server](https://neon.com/discord) or contribute to the [Neon examples repository](https://github.com/neondatabase/examples). - **Code contributions**: Contribute to Neon's development by fixing bugs, proposing new features, or submitting code to [Neon's GitHub repositories](https://github.com/neondatabase). It's also a good way to dig into how Neon is built. ## Join the Discussion Join us on Discord and X (Twitter), and subscribe to the Neon YouTube channel for videos and presentations. - [Neon Discord Server](https://neon.com/discord) - [X (Twitter)](https://twitter.com/neondatabase) - [Neon YouTube](https://www.youtube.com/@neondatabase) --- [Document source](https://neon.com/docs/community/component-architecture.md) --- > Summary: Technical reference for the Neon documentation MDX component system. Covers file layout under src/components/pages/doc/, the sharedMdxComponents.js registry, and the two icon loading strategies. TechCards loads dynamic SVG files from /public/images/technology-logos/. DetailIconCards uses static inline imports mapped in component code. Use this page when adding, modifying, or debugging MDX components, not when looking for usage examples or icon names. # Component architecture Technical implementation details for developers and maintainers Last updated: 2026-06-05 A technical reference for developers and maintainers who need to understand, modify, or extend the Neon documentation component system. This guide covers the architecture, file structure, and implementation details. **What you will learn:** - How MDX components are structured and organized - Technical implementation details for each component type - Development workflows for adding and modifying components - File organization and build process details **Related topics** - [Component Guide](https://neon.com/docs/community/component-guide) - [Component Specialized Guide](https://neon.com/docs/community/component-specialized) - [Component Icon Guide](https://neon.com/docs/community/component-icon-guide) - [Documentation Contribution Guide](https://neon.com/docs/community/contribution-guide) ## Quick navigation - [Component architecture](https://neon.com/docs/community/component-architecture#component-architecture) - How MDX components are integrated - [File structure](https://neon.com/docs/community/component-architecture#file-structure) - Directory organization and component locations - [Component registration](https://neon.com/docs/community/component-architecture#component-registration) - How components are registered in MDX - [Icon systems](https://neon.com/docs/community/component-architecture#icon-systems) - Technical implementation of icon loading - [Shared content](https://neon.com/docs/community/component-architecture#shared-content) - How shared templates work - [Development workflow](https://neon.com/docs/community/component-architecture#development-workflow) - How to add, modify, or debug components - [Build process](https://neon.com/docs/community/component-architecture#build-process) - How components are processed during build - [Troubleshooting](https://neon.com/docs/community/component-architecture#troubleshooting) - Common issues and debugging techniques --- ## Component architecture ### MDX integration Neon documentation uses MDX (Markdown + JSX) to enable React components within markdown content. The component system is built on top of this foundation. ### Component hierarchy ``` MDX Content ↓ Component Registry (sharedMdxComponents) ↓ React Components (src/components/pages/doc/) ↓ Rendered HTML ``` ### Key files - `sharedMdxComponents.js` - Main component registry - `src/components/pages/doc/` - Component implementations - `content/docs/` - MDX content files - `content/docs/shared-content/` - Shared template content --- ## File structure ### Component directory organization Most MDX components follow a consistent pattern in the Neon website repository: ``` src/components/pages/doc/ ├── {component-name}/ │ ├── {component-name}.jsx # Main component implementation │ ├── index.js # Export file │ └── images/ # Component-specific assets │ └── {icons}.inline.svg # Inline SVG icons ├── shared/ # Shared components │ ├── request-form/ │ └── ... └── ... ``` ### Example: DocsList component Let's explore the DocsList component as an example: ``` src/components/pages/doc/docs-list/ ├── docs-list.jsx # Main component implementation ├── index.js # Export: export { default } from './docs-list' └── images/ # Component-specific images ├── docs.inline.svg └── repo.inline.svg ``` ### Key files to check When exploring a component, look for these files: - **Component Definition** (`{component-name}.jsx`) - Contains the React component code - Defines props and their types - Implements the rendering logic - May include styled components or CSS modules - **Index File** (`index.js`) - Usually a simple export: `export { default } from './component-name';` - Makes the component importable from the directory - **Images Directory** (`images/`) - Contains SVGs, icons, or other assets used by the component - For icon-based components, this is where you'll find available icons --- ## Component registration ### Registration process Components are registered in `sharedMdxComponents.js` to make them available in MDX files: ```js // sharedMdxComponents.js import DocsList from '../src/components/pages/doc/docs-list'; import TechCards from '../src/components/pages/doc/tech-cards'; // ... other imports export const sharedMdxComponents = { DocsList, TechCards, // ... other components }; ``` ### MDX Integration The `sharedMdxComponents` object is passed to the MDX processor, making all registered components available in markdown files: ```jsx // In MDX files Node.js Guide ``` ### Component availability - **Global**: Components registered in `sharedMdxComponents` are available in all MDX files - **Local**: Some components may be registered locally for specific pages - **Conditional**: Components may be conditionally available based on page context --- ## Icon systems ### TechCards icon loading TechCards icons are loaded dynamically from the public directory. If the file exists, it will be rendered. Otherwise, the image will be broken or missing. **File Requirements:** - Icons must exist in `/public/images/technology-logos/` - Format: `{icon-name}.svg` and `{icon-name}-dark.svg` - Case-sensitive naming ### DetailIconCards icon loading DetailIconCards icons are statically imported and mapped: ```js // DetailIconCards component implementation import Prisma from './images/prisma.inline.svg'; import NodeJs from './images/node-js.inline.svg'; // ... other imports const icons = { prisma: Prisma, 'node-js': NodeJs, // ... other mappings }; const Icon = icons[icon]; ``` **File Requirements:** - Icons must be imported as inline SVGs - Must be explicitly mapped in the component code - Case-sensitive naming ### Icon system differences | Aspect | TechCards | DetailIconCards | | --------------- | ---------------------------------- | ---------------------------- | | **Loading** | Dynamic file loading | Static imports | | **Location** | `/public/images/technology-logos/` | Component-specific `images/` | | **Format** | Standard SVG files | Inline SVG imports | | **Dark Mode** | Separate `-dark.svg` files | Single file with CSS | | **Flexibility** | Easy to add new icons | Requires code changes | --- ## Shared content ### Shared templates Shared content components load from templates in `content/docs/shared-content/`: ``` content/docs/shared-content/ ├── feature-beta.md ├── public-preview.md ├── early-access.md └── ... ``` ### Template registration Templates are registered in `shared-content/index.js`: ```js // shared-content/index.js export const sharedContent = { 'feature-beta': () => import('./feature-beta.md'), 'public-preview': () => import('./public-preview.md'), // ... other templates }; ``` ### Usage in components Shared content is loaded dynamically: ```jsx // In MDX files // Loads content from feature-beta.md // Loads content from public-preview.md ``` ### Template structure Shared templates are standard MDX files with frontmatter: ```mdx --- title: Feature Beta description: Beta feature announcement --- This feature is currently in beta... ``` --- ## Development workflow ### Adding a new component 1. **Create Component Directory** ```bash mkdir src/components/pages/doc/my-component ``` 2. **Create Component File** ```jsx // src/components/pages/doc/my-component/my-component.jsx import React from 'react'; const MyComponent = ({ title, children }) => { return (

{title}

{children}
); }; export default MyComponent; ``` 3. **Create Index File** ```js // src/components/pages/doc/my-component/index.js export { default } from './my-component'; ``` 4. **Register Component** ```js // sharedMdxComponents.js import MyComponent from '../src/components/pages/doc/my-component'; export const sharedMdxComponents = { // ... existing components MyComponent, }; ``` 5. **Test Component** ```mdx This is a test of my new component. ``` ### Modifying existing components 1. **Locate Component** - Find the component in `src/components/pages/doc/{component-name}/` - Check the main `.jsx` file for implementation 2. **Make Changes** - Modify the component logic in the `.jsx` file - Update props, styling, or functionality as needed 3. **Test Changes** - Check that the component renders correctly - Verify that existing usage still works - Test edge cases and error conditions ### Debugging components 1. **Check Console Errors** - Look for JavaScript errors in browser console - Check for missing imports or undefined variables 2. **Verify Registration** - Ensure component is properly exported from `index.js` - Confirm component is registered in `sharedMdxComponents` 3. **Check File Paths** - Verify all imports resolve correctly - Check that asset files exist in expected locations 4. **Test in Isolation** - Create a simple test page with just the component - Remove other components to isolate issues --- ## Build process ### MDX processing 1. **Content Loading**: MDX files are loaded from `content/docs/` 2. **Component Resolution**: `sharedMdxComponents` are injected into MDX context 3. **Transformation**: MDX is transformed to React components 4. **Rendering**: Components are rendered to HTML ### Build pipeline ``` MDX Files → MDX Processor → React Components → HTML Output ↓ ↓ ↓ ↓ content/docs/ → sharedMdxComponents → src/components/ → public/ ``` ### Optimization - **Code Splitting**: Components are code-split for performance - **Asset Optimization**: Images and SVGs are optimized during build - **Caching**: Static assets are cached for faster loading --- ## Troubleshooting ### Common issues 1. **Component Not Found** - Check that component is registered in `sharedMdxComponents` - Verify the component name matches exactly (case-sensitive) - Ensure the component is properly exported 2. **Icon Not Displaying** - For TechCards: Check if SVG file exists in `/public/images/technology-logos/` - For DetailIconCards: Check if icon is mapped in component code - Verify icon name spelling and case 3. **Build Errors** - Check for syntax errors in component files - Verify all imports resolve correctly - Ensure all required dependencies are installed 4. **Styling Issues** - Check CSS class names and specificity - Verify that styles are properly imported - Test in different browsers and screen sizes ### Debugging techniques 1. **Console Logging** ```jsx const MyComponent = (props) => { console.log('MyComponent props:', props); return
...
; }; ``` 2. **React DevTools** - Use React DevTools to inspect component hierarchy - Check props and state values - Verify component rendering 3. **Network Tab** - Check for failed asset requests - Verify that images and SVGs load correctly - Look for 404 errors 4. **Source Maps** - Enable source maps for better error tracking - Use browser dev tools to step through code ### Performance considerations 1. **Bundle Size** - Keep components lightweight - Use code splitting for large components - Optimize images and assets 2. **Rendering Performance** - Avoid expensive operations in render methods - Use React.memo for expensive components - Implement proper key props for lists 3. **Asset Loading** - Optimize image sizes and formats - Use appropriate loading strategies - Consider lazy loading for non-critical components --- ## Summary This guide provides technical details for working with Neon's MDX component system. Key points: - **Components** are organized in `src/components/pages/doc/` - **Registration** happens in `sharedMdxComponents.js` - **Icons** use different loading strategies for TechCards vs DetailIconCards - **Shared content** loads from templates in `content/docs/shared-content/` - **Development** follows standard React patterns with MDX integration For component usage examples, see the [Component Guide](https://neon.com/docs/community/component-guide) and [Component Specialized Guide](https://neon.com/docs/community/component-specialized). --- [Document source](https://neon.com/docs/community/component-guide.md) --- > Summary: MDX component reference for Neon documentation writers. Covers syntax, props, and live-rendered previews for frequently used components: Admonition, Steps, CodeTabs, TechCards, DetailIconCards, TwoColumnLayout, CheckList, and InfoBlock. Use this page when choosing between similar components or looking up correct prop names and MDX syntax. # Component guide Most commonly used components for documentation writers Last updated: 2026-08-26 A practical guide for the most commonly used MDX components in Neon documentation. This guide focuses on components you'll use most frequently when writing documentation. **What you will learn:** - How to use common MDX components in Neon docs - How to choose between different components - Best practices - Proper syntax and prop usage **Related topics** - [Component Specialized Guide](https://neon.com/docs/community/component-specialized) - [Component Icon Guide](https://neon.com/docs/community/component-icon-guide) - [Component Architecture](https://neon.com/docs/community/component-architecture) - [Documentation Contribution Guide](https://neon.com/docs/community/contribution-guide) ## Quick navigation - [Essential components](https://neon.com/docs/community/component-guide#essential-components) - Most commonly used - [Tabbed content](https://neon.com/docs/community/component-guide#tabbed-content) - CodeTabs and Tabs for organized content - [Content organization](https://neon.com/docs/community/component-guide#content-organization) - Structure and navigation components - [Interactive elements](https://neon.com/docs/community/component-guide#interactive-elements) - UI elements and forms - [Common shared components](https://neon.com/docs/community/component-guide#common-shared-components) - Reusable content - [External content](https://neon.com/docs/community/component-guide#external-content) - Embedding external code and video --- ## Essential components These are the most frequently used components in Neon docs. ### Admonition Callouts for notes, warnings, and tips. There are six types available: `note` (default), `important`, `tip`, `info`, `warning`, `comingSoon`. ```mdx Critical information requiring immediate attention. ``` **Live preview:** **Warning: Important** Critical information requiring immediate attention. **All Admonition types:** **Note: Note** Highlights information that users should take into account. **Important:** Crucial information necessary for users to succeed. **Tip: Pro tip** Optional information to help a user be more successful. **Info:** Information that helps users understand things better. **Warning:** Critical content demanding immediate user attention due to potential risks. **Coming soon:** Information about features that are coming soon. --- ### Callout Highlighted block for supplementary information the reader should notice, but that doesn't carry the urgency of an Admonition. Use it for tips, best practices, or "good to know" context. The default label is "Good to know". ```mdx Make sure you have Node.js 18+ installed. ``` **Live preview:** **Before you start:** Make sure you have Node.js 18+ installed. **Props:** | Prop | Type | Default | Description | | ---------- | ------ | -------------- | ----------------------------------- | | `children` | node | (required) | Content rendered inside the callout | | `title` | string | `Good to know` | Label displayed in the header | **When to use Callout vs Admonition:** - **Callout** — supplementary context, best practices, or neutral "good to know" information. - **Admonition** — warnings, important notices, tips with urgency, or coming-soon flags. Use when missing the information could cause user error. --- ### Steps Numbered step-by-step instructions split by `h2` headings. ```mdx ## Get a Glass Take a clean glass from the cabinet or dish rack. ## Turn on Tap Adjust the faucet to your preferred temperature and flow rate. ## Fill and Drink Fill the glass to desired level and enjoy your water. ``` **Live preview:** ## Get a Glass Take a clean glass from the cabinet or dish rack. ## Turn on Tap Adjust the faucet to your preferred temperature and flow rate. ## Fill and Drink Fill the glass to desired level and enjoy your water. --- ## Tabbed content Components for organizing content into tabs. ### CodeTabs Multi-language code examples with tabs. ````mdx ```javascript const { Client } = require('pg'); const client = new Client({ connectionString: process.env.DATABASE_URL, }); await client.connect(); ``` ```python import psycopg2 import os conn = psycopg2.connect(os.environ["DATABASE_URL"]) cur = conn.cursor() ``` ```go import ( "database/sql" _ "github.com/lib/pq" ) db, err := sql.Open("postgres", os.Getenv("DATABASE_URL")) ``` ```` **Live preview:** **JavaScript** ```javascript const { Client } = require('pg'); const client = new Client({ connectionString: process.env.DATABASE_URL, }); await client.connect(); ``` **Python** ```python import psycopg2 import os conn = psycopg2.connect(os.environ["DATABASE_URL"]) cur = conn.cursor() ``` **Go** ```go import ( "database/sql" _ "github.com/lib/pq" ) db, err := sql.Open("postgres", os.Getenv("DATABASE_URL")) ``` --- ### Tabs General tabbed content (not just code). For code-specific tabs, use [CodeTabs](https://neon.com/docs/community/component-guide#codetabs) instead. ````mdx Create a database using the Neon Console by navigating to your project dashboard and clicking "Create Database". Use the Neon CLI to create a database: ```bash neon databases create --name my-database ``` Use the API to create a database: ```bash curl -X POST https://console.neon.tech/api/v2/projects/my-project/databases \ -H "Authorization: Bearer $NEON_API_KEY" ``` ```` **Live preview:** **Console** Create a database using the Neon Console by navigating to your project dashboard and clicking "Create Database". **CLI** Use the Neon CLI to create a database: ```bash neon databases create --name my-database ``` **API** Use the API to create a database: ```bash curl -X POST https://console.neon.tech/api/v2/projects/my-project/databases \ -H "Authorization: Bearer $NEON_API_KEY" ``` --- ## Content organization Components for structuring and organizing page content. ### TechCards / DetailIconCards Technology cards with icons, titles, and descriptions. These components use different [icon systems](https://neon.com/docs/community/component-icon-guide) - see the [comparison table](https://neon.com/docs/community/component-guide#techcards-vs-detailiconcards-vs-docslist) below to choose the right one. #### TechCards Standard technology cards layout using [TechCards icons](https://neon.com/docs/community/component-icon-guide#techcards-icons): ```mdx Node.js Python Next.js ``` **Live preview:** - [Node.js](https://neon.com/docs/guides/node): Connect Node.js applications to Neon - [Python](https://neon.com/docs/guides/python): Connect Python applications to Neon - [Next.js](https://neon.com/docs/guides/nextjs): Build Next.js apps with Neon --- #### DetailIconCards Alternative layout using [DetailIconCards icons](https://neon.com/docs/community/component-icon-guide#detailiconcards-icons): ```mdx OpenAI Integration LangChain Integration Code Development AWS Integration ``` **Live preview:** - [OpenAI Integration](https://neon.com/docs/ai/openai): Build AI features with OpenAI - [LangChain Integration](https://neon.com/docs/ai/langchain): Create AI workflows with LangChain - [Code Development](https://neon.com/docs/development): Development tools and practices - [AWS Integration](https://neon.com/docs/cloud/aws): Deploy and scale with AWS --- > DetailIconCards uses a different [icon system](https://neon.com/docs/community/component-icon-guide#detailiconcards-icons) than [TechCards](https://neon.com/docs/community/component-icon-guide#techcards-icons), which is why different icons are available._ #### TechCards vs DetailIconCards vs DocsList Quick comparison to help you choose the right component: | Component | Use For | Icon System | Layout | | -------------------------------------------------------------------------------------- | ------------------------------ | ------------------------------------------------------------------------------------------------------- | ----------- | | **[TechCards](https://neon.com/docs/community/component-guide#techcards)** | Technology/framework showcases | [Technology logos](https://neon.com/docs/community/component-icon-guide#techcards-icons) (colorful) | Card grid | | **[DetailIconCards](https://neon.com/docs/community/component-guide#detailiconcards)** | Feature/service showcases | [Detail icons](https://neon.com/docs/community/component-icon-guide#detailiconcards-icons) (monochrome) | Card grid | | **[DocsList](https://neon.com/docs/community/component-guide#docslist)** | Documentation links | Checkbox (default), docs, or repo icon | Simple list | ### DefinitionList Accessible term/definition lists for defining technical terms and concepts. ```mdx Database URL : Connection string for your Neon database : Format: `postgresql://user:password@host:port/database` Connection Pool : A cache of database connections : Improves performance by reusing connections Branch : An isolated copy of your database : Used for development and testing ``` **Live preview:** Database URL : Connection string for your Neon database : Format: `postgresql://user:password@host:port/database` Connection Pool : A cache of database connections : Improves performance by reusing connections Branch : An isolated copy of your database : Used for development and testing --- ### DocsList Simple, clean lists for documentation links with optional theming. DocsList provides a lightweight alternative to card-based components for presenting navigation links or content summaries. **Props:** - `title` (string) - Optional title for the list section - `theme` (string) - Visual theme: `"docs"` (document icon), `"repo"` (repository icon), or default (checkbox icon) **Default Theme (Checkbox Icon):** **MDX Code:** ```mdx Node.js Connection Guide Python Connection Guide API Reference CLI Documentation ``` **Live preview:** **Related documentation** - [Node.js Connection Guide](https://neon.com/docs/guides/node) - [Python Connection Guide](https://neon.com/docs/guides/python) - [API Reference](https://neon.com/docs/api-reference) - [CLI Documentation](https://neon.com/docs/cli) --- ### InfoBlock InfoBlock creates a multi-column layout for organizing related content sections. Use it for "at-a-glance" summaries at the top of documentation pages, combining learning objectives with related resources. Use two columns. **Key Features:** - Commonly paired with DocsList for structured content presentation - Ideal for page introductions and overview sections **Basic Two-Column Layout:** ```mdx

How to view and modify data in the console

Create an isolated database copy per developer

Reset your branch to production when ready to start new work

About branching Branching workflows Connect Neon to your stack
``` **Renders as:** **What you will learn:** - How to view and modify data in the console - Create an isolated database copy per developer - Reset your branch to production when ready to start new work **Related topics** - [About branching](https://neon.com/docs/introduction/branching) - [Branching workflows](https://neon.com/docs/get-started/workflow-primer) - [Connect Neon to your stack](https://neon.com/docs/get-started/connect-neon) --- ### TwoColumnLayout Two-column layout for tutorials and reference documentation. Use `TwoColumnLayout.Step` for numbered tutorial steps, `TwoColumnLayout.Item` for reference items. Add `layout: wide` to the page frontmatter when using this component, to hide the right sidebar and give the layout more room. ````mdx Install the required packages. ```bash npm install @neon/neon-js ``` ```` **Subcomponents:** | Subcomponent | Props | Purpose | | ------------------------ | ----------------------- | ------------------------------------------ | | `TwoColumnLayout.Step` | `title` | Numbered step for tutorials | | `TwoColumnLayout.Item` | `title`, `method`, `id` | Reference item | | `TwoColumnLayout.Block` | `label` (optional) | Content block within a step or item | | `TwoColumnLayout.Footer` | — | Full-width content at the bottom of a step | See [Managed Better Auth with Next.js](https://neon.com/docs/auth/quick-start/nextjs-api-only) for a live example. --- ### FeatureList Visual list of features, split by `##` and `###` headings. Supports an optional `icons` prop. ```mdx ### Instant provisioning Create databases in seconds. ### Autoscaling Scale compute up and down automatically. ``` To add icons, pass an array of icon names (see `src/components/shared/feature-list/icon/icon.jsx` for available icons): ```mdx ``` --- ## Interactive elements Components for user engagement and interaction. ### CheckList Interactive checklists for setup guides and tutorials. CheckList uses CheckItem components internally. ```mdx Sign up for a free Neon account at console.neon.tech Install the required packages for your project Set up your database connection string Verify your application can connect to Neon ``` **Live preview:** ## Setup checklist - [ ] [Create Neon account](https://neon.com/docs/community/component-guide#signup) Sign up for a free Neon account at console.neon.tech - [ ] [Install dependencies](https://neon.com/docs/community/component-guide#install) Install the required packages for your project - [ ] [Configure environment](https://neon.com/docs/community/component-guide#config) Set up your database connection string - [ ] [Test connection](https://neon.com/docs/community/component-guide#test) Verify your application can connect to Neon --- ### CheckItem Individual checklist items used within CheckList components. ```mdx Description of the task or requirement ``` --- **Usage Notes:** - Always used within a `` component - `title` prop is required - `href` prop is optional for anchor linking - Content is the description text --- ### Faq / FaqItem The standard, SEO-friendly frequently-asked-questions section for the end of docs and guides. Use it instead of ad-hoc `### question` headings, `**Q:/A:**` text, or `DefinitionList` for FAQs, so every FAQ looks and behaves the same. It emits `FAQPage` schema.org JSON-LD to help search engines and AI agents parse the questions and answers, and it renders each answer with native collapsible `
`, so answers stay crawlable and accessible even when collapsed. It also gives every FAQ consistent styling and deep-link anchors. Add a `## Frequently asked questions` heading above the component (sentence case) so the section appears in the table of contents. ```mdx ## Frequently asked questions A branch is a copy-on-write clone of your data that you can create from a current or past state. No. Creating a branch does not increase load on the parent branch or affect its performance. ``` **Live preview:** ## Frequently asked questions ### What is a branch? A branch is a copy-on-write clone of your data that you can create from a current or past state. ### Does creating a branch affect my production database? No. Creating a branch does not increase load on the parent branch or affect its performance. **Usage Notes:** - `FaqItem` requires a `question` prop. It renders as an `

` inside the summary and is used verbatim in the JSON-LD. - `id` (optional) sets the anchor; it defaults to a slug of the question, so `#your-question` deep links work. - `defaultOpen` (optional) renders an item expanded on load. - Answers accept full markdown (lists, tables, links, images, code). Keep blank lines around block content. - Questions do not appear in the table of contents; the `## Frequently asked questions` heading is the single TOC entry. - Put shared blocks like `` after ``, not inside an item. ### CTA (Call to Action) Prominent call-to-action buttons for important actions. ```mdx ``` **Live preview:** > **Try Neon free** > > Start building with serverless Postgres today. No credit card required. > > [Sign Up](https://console.neon.tech/signup) --- ### CopyPrompt Displays a copyable LLM prompt from a file. Use when providing a pre-built prompt to help users get started faster. Prompt files go in `public/prompts/`. ```mdx ``` **Props:** | Prop | Type | Default | Description | | ------------- | ------ | -------------------------------------------------- | -------------------------------------------- | | `src` | string | (required) | Path to the prompt file in `public/prompts/` | | `displayText` | string | `Use this pre-built prompt to get started faster.` | CTA text shown to the left | | `buttonText` | string | `Copy prompt` | Button label | --- ### NeedHelp Support widget for getting assistance. ```mdx ``` **Live preview:** --- --- ## Common shared components Reusable content components that load from shared templates. ### LinkAPIKey Link to API key management in the console. ```mdx ``` **Live preview:** **Note:** To learn more about the types of API keys you can create — personal, organization, or project-scoped — see [Manage API Keys](https://neon.com/docs/manage/api-keys). --- ### FeatureBetaProps Status indicator for beta features with custom feature name. ```mdx ``` **Live preview:** **Note: Beta** **OpenTelemetry integration** is in beta. Share your feedback on [Discord](https://neon.com/discord) or via the [Neon Console](https://console.neon.tech/app/projects?modal=feedback). --- --- ## External content Components for embedding content from outside the repo. ### ExternalCode Embed code from an external URL with syntax highlighting. Always use raw GitHub URLs. ```mdx ``` **Props:** | Prop | Type | Default | Description | | ----------------- | ------- | --------------------- | -------------------------------- | | `url` | string | (required) | Raw URL to the file | | `language` | string | (auto from extension) | Language for syntax highlighting | | `showLineNumbers` | boolean | false | Show line numbers | | `shouldWrap` | boolean | false | Enable code wrapping | ### YoutubeIframe Embeds a YouTube video player. ```mdx ``` Pass the video ID from the YouTube URL (the part after `v=`). --- ## Best practices ### Component selection - **[Admonition](https://neon.com/docs/community/component-guide#admonition)** for urgent callouts and warnings - **[Callout](https://neon.com/docs/community/component-guide#callout)** for supplementary "good to know" context - **[Steps](https://neon.com/docs/community/component-guide#steps)** for sequential instructions - **[CodeTabs](https://neon.com/docs/community/component-guide#codetabs)** for multi-language examples - **[TechCards](https://neon.com/docs/community/component-guide#techcards)** for technology showcases - **[TwoColumnLayout](https://neon.com/docs/community/component-guide#twocolumnlayout)** for tutorials and reference docs requiring a two-column layout - **[FeatureList](https://neon.com/docs/community/component-guide#featurelist)** for listing product features visually - **[CheckList](https://neon.com/docs/community/component-guide#checklist)** for setup guides - **[CopyPrompt](https://neon.com/docs/community/component-guide#copyprompt)** for providing a copyable LLM prompt - **[InfoBlock](https://neon.com/docs/community/component-guide#infoblock)** for page introductions with multiple content sections - **[DocsList](https://neon.com/docs/community/component-guide#docslist)** for simple navigation lists with theming options ### Content organization tips - Use [InfoBlock](https://neon.com/docs/community/component-guide#infoblock) at the top of pages to provide quick orientation - Add `layout: wide` to frontmatter when using [TwoColumnLayout](https://neon.com/docs/community/component-guide#twocolumnlayout) - For [TechCards](https://neon.com/docs/community/component-guide#techcards), always check that the SVG file exists in `/public/images/technology-logos/` - For [DetailIconCards](https://neon.com/docs/community/component-guide#detailiconcards), use only icon names that are mapped in the component code - Choose [DocsList](https://neon.com/docs/community/component-guide#docslist) themes based on content type: default for tasks, `docs` for documentation, `repo` for code - Use the [comparison table](https://neon.com/docs/community/component-guide#techcards-vs-detailiconcards-vs-docslist) to choose between [TechCards](https://neon.com/docs/community/component-guide#techcards), [DetailIconCards](https://neon.com/docs/community/component-guide#detailiconcards), and [DocsList](https://neon.com/docs/community/component-guide#docslist) --- ## Component summary This guide covers the most commonly used MDX components in Neon documentation. Each component includes: - **MDX syntax**: Copy-paste ready code examples - **Live rendering**: See exactly how components appear - **Props documentation**: Available parameters and options - **Best practices**: When and how to use each component ### Component categories | **Category** | **Components** | **Use Case** | | -------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------- | | **[Essential](https://neon.com/docs/community/component-guide#essential-components)** | [Admonition](https://neon.com/docs/community/component-guide#admonition), [Steps](https://neon.com/docs/community/component-guide#steps) | Most commonly used components | | **[Tabbed Content](https://neon.com/docs/community/component-guide#tabbed-content)** | [CodeTabs](https://neon.com/docs/community/component-guide#codetabs), [Tabs](https://neon.com/docs/community/component-guide#tabs) | Organizing content into tabs | | **[Content organization](https://neon.com/docs/community/component-guide#content-organization)** | [TechCards](https://neon.com/docs/community/component-guide#techcards--detailiconcards), [DetailIconCards](https://neon.com/docs/community/component-guide#techcards--detailiconcards), [DefinitionList](https://neon.com/docs/community/component-guide#definitionlist), [DocsList](https://neon.com/docs/community/component-guide#docslist), [InfoBlock](https://neon.com/docs/community/component-guide#infoblock) | Structure and navigation | | **[Interactive elements](https://neon.com/docs/community/component-guide#interactive-elements)** | [CheckList](https://neon.com/docs/community/component-guide#checklist), [CheckItem](https://neon.com/docs/community/component-guide#checkitem), [CTA](https://neon.com/docs/community/component-guide#cta-call-to-action), [NeedHelp](https://neon.com/docs/community/component-guide#needhelp) | User engagement and interaction | | **[Common shared components](https://neon.com/docs/community/component-guide#common-shared-components)** | [LinkAPIKey](https://neon.com/docs/community/component-guide#linkapikey), [FeatureBetaProps](https://neon.com/docs/community/component-guide#featurebetaprops) | Reusable content and status indicators | For specialized components and specific use cases, see the [Component Specialized Guide](https://neon.com/docs/community/component-specialized). --- [Document source](https://neon.com/docs/community/component-icon-guide.md) --- > Summary: Icon reference for Neon docs components, covering two systems: TechCards (colorful technology logos, kebab-case names) and DetailIconCards (monochrome feature icons). Use this page to find the exact icon name and correct component when authoring cards. TechCards uses kebab-case. DetailIconCards accepts camelCase or kebab-case. Also covers SVG file locations. # Component icon guide Complete reference for all icon systems and usage Last updated: 2026-10-08 A comprehensive guide to all icon systems used in Neon documentation. This guide helps you understand which icon system to use and how to implement them correctly. **What you will learn:** - How to choose the right icon system for your use case - Which icons are available in each system - How to implement icons correctly in components - Best practices for icon usage and troubleshooting **Related topics** - [Component Guide](https://neon.com/docs/community/component-guide) - [Component Specialized Guide](https://neon.com/docs/community/component-specialized) - [Component Architecture](https://neon.com/docs/community/component-architecture) - [Documentation Contribution Guide](https://neon.com/docs/community/contribution-guide) ## Quick navigation - [Icon system overview](https://neon.com/docs/community/component-icon-guide#icon-system-overview) - Understanding the different icon systems - [TechCards Icons](https://neon.com/docs/community/component-icon-guide#techcards-icons) - Technology logos and frameworks - [DetailIconCards Icons](https://neon.com/docs/community/component-icon-guide#detailiconcards-icons) - Feature and service icons - [Icon usage guidelines](https://neon.com/docs/community/component-icon-guide#icon-usage-guidelines) - Best practices and conventions - [Icon Decision Tree](https://neon.com/docs/community/component-icon-guide#icon-decision-tree) - Which icon system to use when --- ## Icon system overview Neon documentation uses multiple icon systems for different components. Understanding which system to use is crucial for proper implementation. ### Available icon systems 1. **TechCards Icons** - Colorful technology logos and framework icons 2. **DetailIconCards Icons** - Monochrome feature and service icons 3. **DocsList Icons** - Simple navigation and action icons ### Component compatibility | Component | Icon System | Use Case | | ------------------- | --------------------- | ------------------------------ | | **TechCards** | TechCards Icons | Technology/framework showcases | | **DetailIconCards** | DetailIconCards Icons | Feature/service showcases | | **DocsList** | Built-in themes | Documentation links | ### Usage example ```mdx OpenAI Integration LangChain Integration ``` _For technical implementation details, see the [Icon Systems section](https://neon.com/docs/community/component-architecture#icon-systems) in the Component Architecture guide._ --- ## Icon usage guidelines ### Choosing the right icon system - **TechCards**: Use for technology and framework showcases - **DetailIconCards**: Use for feature and service showcases - **DocsList**: Use built-in themes for documentation links ### Icon naming conventions - **TechCards**: Use kebab-case (for example, `node-js`, `next-js`) - **DetailIconCards**: Use camelCase or kebab-case as defined in the mapping - **File Requirements**: Ensure SVG files exist in the correct directories ### Best practices 1. **Test your icons**: Always verify that your chosen icon works in the target component 2. **Check both systems**: If an icon doesn't work in one system, try the other 3. **Use descriptive names**: Choose icon names that clearly represent the technology or feature 4. **Document your choices**: Keep track of which icons work in which components 5. **Fallback gracefully**: Provide alternative text or descriptions when icons aren't available --- ### Component selection guide | Use Case | Component | Icon System | Example | | ------------------- | --------------- | --------------------- | ---------------------- | | Technology showcase | TechCards | TechCards Icons | Node.js, React, Python | | Feature showcase | DetailIconCards | DetailIconCards Icons | OpenAI, AWS, Database | | Documentation links | DocsList | Built-in themes | Guides, API docs | | Simple navigation | DocsList | Built-in themes | Related topics | --- ## Troubleshooting ### Common issues 1. **Icon not displaying**: Check that the icon name exists in the correct system 2. **Wrong icon system**: Verify you're using the right component for your icon 3. **Missing files**: Ensure SVG files exist in the correct directories 4. **Case sensitivity**: Icon names are case-sensitive ### Testing icons To test if an icon works: 1. **TechCards**: Check if `{icon}.svg` exists in `/public/images/technology-logos/` 2. **DetailIconCards**: Check if the icon is mapped in the component code 3. **DocsList**: Use the built-in themes (default, docs, repo) ### Getting help - Review the [Component Architecture](https://neon.com/docs/community/component-architecture) for technical details - Test icons in a development environment before using in production --- ## Complete icon showcase ### TechCards Icons (Technology Logos) #### Programming Languages & Frameworks - [Bun](https://neon.com/docs/community/component-icon-guide#): JavaScript runtime (icon: bun) - [Express](https://neon.com/docs/community/component-icon-guide#): Node.js web framework (icon: express) - [Hasura](https://neon.com/docs/community/component-icon-guide#): GraphQL API engine (icon: hasura) - [Hono](https://neon.com/docs/community/component-icon-guide#): Web framework (icon: hono) - [Java](https://neon.com/docs/community/component-icon-guide#): Programming language (icon: java) - [JavaScript](https://neon.com/docs/community/component-icon-guide#): Programming language (icon: javascript) - [Kotlin](https://neon.com/docs/community/component-icon-guide#): Programming language (icon: kotlin) - [Laravel](https://neon.com/docs/community/component-icon-guide#): PHP framework (icon: laravel) - [Nest.js](https://neon.com/docs/community/component-icon-guide#): Node.js framework (icon: nest-js) - [Next.js](https://neon.com/docs/community/component-icon-guide#): React framework (icon: next-js) - [Node.js](https://neon.com/docs/community/component-icon-guide#): JavaScript runtime (icon: node-js) - [Nuxt](https://neon.com/docs/community/component-icon-guide#): Vue framework (icon: nuxt) - [Phoenix](https://neon.com/docs/community/component-icon-guide#): Elixir framework (icon: phoenix) - [Python](https://neon.com/docs/community/component-icon-guide#): Programming language (icon: python) - [Quarkus](https://neon.com/docs/community/component-icon-guide#): Java framework (icon: quarkus) - [Rails](https://neon.com/docs/community/component-icon-guide#): Ruby framework (icon: rails) - [React](https://neon.com/docs/community/component-icon-guide#): JavaScript library (icon: react) - [Redwood SDK](https://neon.com/docs/community/component-icon-guide#): Full-stack framework (icon: redwoodsdk) - [Reflex](https://neon.com/docs/community/component-icon-guide#): Python framework (icon: reflex) - [Remix](https://neon.com/docs/community/component-icon-guide#): React framework (icon: remix) - [Ruby](https://neon.com/docs/community/component-icon-guide#): Programming language (icon: ruby) - [Rust](https://neon.com/docs/community/component-icon-guide#): Programming language (icon: rust) - [Solid](https://neon.com/docs/community/component-icon-guide#): JavaScript library (icon: solid) - [Svelte](https://neon.com/docs/community/component-icon-guide#): JavaScript framework (icon: svelte) - [Symfony](https://neon.com/docs/community/component-icon-guide#): PHP framework (icon: symfony) - [Vue](https://neon.com/docs/community/component-icon-guide#): JavaScript framework (icon: vue) #### Cloud & Infrastructure - [AWS S3 Bucket](https://neon.com/docs/community/component-icon-guide#): Cloud storage service (icon: aws-s3-bucket) - [Backblaze](https://neon.com/docs/community/component-icon-guide#): Cloud storage and backup (icon: backblaze) - [Heroku](https://neon.com/docs/community/component-icon-guide#): Cloud platform (icon: heroku) - [Koyeb](https://neon.com/docs/community/component-icon-guide#): Cloud platform (icon: koyeb) - [Netlify](https://neon.com/docs/community/component-icon-guide#): Web hosting platform (icon: netlify) - [Railway](https://neon.com/docs/community/component-icon-guide#): Deployment platform (icon: railway) - [Render](https://neon.com/docs/community/component-icon-guide#): Cloud platform (icon: render) - [Vercel](https://neon.com/docs/community/component-icon-guide#): Deployment platform (icon: vercel) #### Databases & Data - [Convex](https://neon.com/docs/community/component-icon-guide#): Backend platform (icon: convex) - [Entity](https://neon.com/docs/community/component-icon-guide#): Data modeling tool (icon: entity) - [Estuary](https://neon.com/docs/community/component-icon-guide#): Data streaming platform (icon: estuary) - [Exograph](https://neon.com/docs/community/component-icon-guide#): GraphQL framework (icon: exograph) - [Ferret](https://neon.com/docs/community/component-icon-guide#): Data processing tool (icon: ferret) - [Kafka](https://neon.com/docs/community/component-icon-guide#): Stream processing platform (icon: kafka) - [Knex](https://neon.com/docs/community/component-icon-guide#): SQL query builder (icon: knex) - [Liquibase](https://neon.com/docs/community/component-icon-guide#): Database migration tool (icon: liquibase) - [Materialize](https://neon.com/docs/community/component-icon-guide#): Streaming database (icon: materialize) - [Neon](https://neon.com/docs/community/component-icon-guide#): Serverless Postgres (icon: neon) - [Outerbase](https://neon.com/docs/community/component-icon-guide#): Database interface (icon: outerbase) - [Draxlr](https://neon.com/docs/community/component-icon-guide#): Database interface (icon: draxlr) - [Polyscale](https://neon.com/docs/community/component-icon-guide#): Database proxy (icon: polyscale) - [PostgreSQL](https://neon.com/docs/community/component-icon-guide#): Database system (icon: postgresql) - [Prisma](https://neon.com/docs/community/component-icon-guide#): ORM for Node.js (icon: prisma) - [Sequelize](https://neon.com/docs/community/component-icon-guide#): ORM for Node.js (icon: sequelize) - [Sequin](https://neon.com/docs/community/component-icon-guide#): Data synchronization (icon: sequin) - [Snowflake](https://neon.com/docs/community/component-icon-guide#): Data warehouse (icon: snowflake) - [SQLAlchemy](https://neon.com/docs/community/component-icon-guide#): Python ORM (icon: sqlalchemy) - [StepZen](https://neon.com/docs/community/component-icon-guide#): GraphQL platform (icon: stepzen) - [Supabase](https://neon.com/docs/community/component-icon-guide#): Backend platform (icon: supabase) - [Tortoise ORM](https://neon.com/docs/community/component-icon-guide#): Python ORM (icon: tortoise-orm) - [TypeORM](https://neon.com/docs/community/component-icon-guide#): TypeScript ORM (icon: typeorm) - [Drizzle](https://neon.com/docs/community/component-icon-guide#): TypeScript ORM (icon: drizzle) #### Services & APIs - [Cloudinary](https://neon.com/docs/community/component-icon-guide#): Cloud media management (icon: cloudinary) - [ImageKit](https://neon.com/docs/community/component-icon-guide#): Image optimization (icon: imagekit) - [Inngest](https://neon.com/docs/community/component-icon-guide#): Background job platform (icon: inngest) - [Micronaut](https://neon.com/docs/community/component-icon-guide#): Java framework (icon: micronaut) - [Neo Tax](https://neon.com/docs/community/component-icon-guide#): Tax calculation service (icon: neo-tax) - [OAuth](https://neon.com/docs/community/component-icon-guide#): Authentication protocol (icon: oauth) - [Okta](https://neon.com/docs/community/component-icon-guide#): Identity platform (icon: okta) - [Uploadcare](https://neon.com/docs/community/component-icon-guide#): File handling service (icon: uploadcare) ### DetailIconCards Icons (Feature Icons) #### AI & Machine Learning - [LangChain](https://neon.com/docs/community/component-icon-guide#): AI framework (icon: langchain) - [LlamaIndex](https://neon.com/docs/community/component-icon-guide#): Data framework for LLMs (icon: llamaindex) - [Ollama](https://neon.com/docs/community/component-icon-guide#): Local LLM framework (icon: ollama) - [OpenAI](https://neon.com/docs/community/component-icon-guide#): AI platform (icon: openai) #### Development Tools - [Atom](https://neon.com/docs/community/component-icon-guide#): Code editor (icon: atom) - [Binary Code](https://neon.com/docs/community/component-icon-guide#): Programming and code (icon: binary-code) - [Bug](https://neon.com/docs/community/component-icon-guide#): Debugging and testing (icon: bug) - [CLI](https://neon.com/docs/community/component-icon-guide#): Command line interface (icon: cli) - [CLI Cursor](https://neon.com/docs/community/component-icon-guide#): Terminal cursor (icon: cli-cursor) - [Code](https://neon.com/docs/community/component-icon-guide#): Programming and development (icon: code) - [GitHub](https://neon.com/docs/community/component-icon-guide#): Code repository (icon: github) - [Hook](https://neon.com/docs/community/component-icon-guide#): Development hooks (icon: hook) - [Ladder](https://neon.com/docs/community/component-icon-guide#): Development progression (icon: ladder) - [Laptop](https://neon.com/docs/community/component-icon-guide#): Development machine (icon: laptop) - [Setup](https://neon.com/docs/community/component-icon-guide#): Configuration and setup (icon: setup) - [Wrench](https://neon.com/docs/community/component-icon-guide#): Tools and utilities (icon: wrench) #### Business & Analytics - [A Chart](https://neon.com/docs/community/component-icon-guide#): Analytics and charts (icon: a-chart) - [App Store](https://neon.com/docs/community/component-icon-guide#): Application marketplace (icon: app-store) - [Calendar Day](https://neon.com/docs/community/component-icon-guide#): Scheduling and time (icon: calendar-day) - [Cards](https://neon.com/docs/community/component-icon-guide#): Card-based interface (icon: cards) - [Check](https://neon.com/docs/community/component-icon-guide#): Verification and approval (icon: check) - [Cheque](https://neon.com/docs/community/component-icon-guide#): Payment processing (icon: cheque) - [Chart Bar](https://neon.com/docs/community/component-icon-guide#): Data visualization (icon: chart-bar) - [CSV](https://neon.com/docs/community/component-icon-guide#): Data format (icon: csv) - [Data](https://neon.com/docs/community/component-icon-guide#): Data and information (icon: data) - [Metrics](https://neon.com/docs/community/component-icon-guide#): Performance metrics (icon: metrics) - [Performance](https://neon.com/docs/community/component-icon-guide#): System performance (icon: performance) - [Queries](https://neon.com/docs/community/component-icon-guide#): Database queries (icon: queries) - [Research](https://neon.com/docs/community/component-icon-guide#): Development research (icon: research) - [Stopwatch](https://neon.com/docs/community/component-icon-guide#): Timing and performance (icon: stopwatch) - [Table](https://neon.com/docs/community/component-icon-guide#): Data tables (icon: table) - [Todo](https://neon.com/docs/community/component-icon-guide#): Task management (icon: todo) - [Transactions](https://neon.com/docs/community/component-icon-guide#): Database transactions (icon: transactions) - [Trend Up](https://neon.com/docs/community/component-icon-guide#): Growth and trends (icon: trend-up) #### UI & Design - [Audio Jack](https://neon.com/docs/community/component-icon-guide#): Audio connectivity (icon: audio-jack) - [Cards](https://neon.com/docs/community/component-icon-guide#): Card-based interface (icon: cards) - [Gamepad](https://neon.com/docs/community/component-icon-guide#): Gaming and interaction (icon: gamepad) - [GUI](https://neon.com/docs/community/component-icon-guide#): Graphical user interface (icon: gui) - [Screen](https://neon.com/docs/community/component-icon-guide#): Display and interface (icon: screen) - [Sparkle](https://neon.com/docs/community/component-icon-guide#): Visual effects (icon: sparkle) - [User](https://neon.com/docs/community/component-icon-guide#): User interface (icon: user) #### Infrastructure & Services - [Autoscaling](https://neon.com/docs/community/component-icon-guide#): Automatic scaling (icon: autoscaling) - [AWS](https://neon.com/docs/community/component-icon-guide#): Cloud computing platform (icon: aws) - [Branching](https://neon.com/docs/community/component-icon-guide#): Database branching (icon: branching) - [Database](https://neon.com/docs/community/component-icon-guide#): Database systems (icon: database) - [Discord](https://neon.com/docs/community/component-icon-guide#): Communication platform (icon: discord) - [Download](https://neon.com/docs/community/component-icon-guide#): File download (icon: download) - [Enable](https://neon.com/docs/community/component-icon-guide#): Feature enablement (icon: enable) - [Filter](https://neon.com/docs/community/component-icon-guide#): Data filtering (icon: filter) - [Find Replace](https://neon.com/docs/community/component-icon-guide#): Search and replace (icon: find-replace) - [Gear](https://neon.com/docs/community/component-icon-guide#): Settings and configuration (icon: gear) - [Globe](https://neon.com/docs/community/component-icon-guide#): Global connectivity (icon: globe) - [Handshake](https://neon.com/docs/community/component-icon-guide#): Partnerships and agreements (icon: handshake) - [Heroku](https://neon.com/docs/community/component-icon-guide#): Cloud platform (icon: heroku) - [Hourglass](https://neon.com/docs/community/component-icon-guide#): Time and waiting (icon: hourglass) - [Import](https://neon.com/docs/community/component-icon-guide#): Data import (icon: import) - [Invert](https://neon.com/docs/community/component-icon-guide#): Data transformation (icon: invert) - [Lock Landscape](https://neon.com/docs/community/component-icon-guide#): Security and access control (icon: lock-landscape) - [Neon](https://neon.com/docs/community/component-icon-guide#): Serverless Postgres (icon: neon) - [Network](https://neon.com/docs/community/component-icon-guide#): Network connectivity (icon: network) - [Postgres](https://neon.com/docs/community/component-icon-guide#): Database system (icon: postgres) - [Prisma](https://neon.com/docs/community/component-icon-guide#): ORM for Node.js (icon: prisma) - [Privacy](https://neon.com/docs/community/component-icon-guide#): Data privacy (icon: privacy) - [Puzzle](https://neon.com/docs/community/component-icon-guide#): Problem solving (icon: puzzle) - [Refresh](https://neon.com/docs/community/component-icon-guide#): Data refresh (icon: refresh) - [Respond Arrow](https://neon.com/docs/community/component-icon-guide#): Response and feedback (icon: respond-arrow) - [Scale Up](https://neon.com/docs/community/component-icon-guide#): Scaling and growth (icon: scale-up) - [Search](https://neon.com/docs/community/component-icon-guide#): Search functionality (icon: search) - [Split Branch](https://neon.com/docs/community/component-icon-guide#): Code branching (icon: split-branch) - [SQL](https://neon.com/docs/community/component-icon-guide#): Database queries (icon: sql) - [Unlock](https://neon.com/docs/community/component-icon-guide#): Access control (icon: unlock) - [Vercel](https://neon.com/docs/community/component-icon-guide#): Deployment platform (icon: vercel) - [Wallet](https://neon.com/docs/community/component-icon-guide#): Payment and billing (icon: wallet) - [Warning](https://neon.com/docs/community/component-icon-guide#): Alerts and warnings (icon: warning) - [X](https://neon.com/docs/community/component-icon-guide#): Close or cancel (icon: x) - [Zap](https://neon.com/docs/community/component-icon-guide#): Realtime and instant operations (icon: zap) --- ## Summary This guide provides an overview of Neon's icon systems and usage guidelines. For complete icon listings and detailed examples, refer to the [Component Guide](https://neon.com/docs/community/component-guide). ### Key takeaways - **TechCards** uses colorful technology logos from `/public/images/technology-logos/` - **DetailIconCards** uses monochrome feature icons mapped in component code - **DocsList** uses built-in themes for simple navigation - Always test icons in the target component before using - Choose the right component based on your use case, not just the icon availability --- [Document source](https://neon.com/docs/community/component-specialized.md) --- > Summary: Reference for infrequently used Neon docs MDX components. Covers ExternalCode, YoutubeIframe, Video, feature status indicators (PrivatePreview, PublicPreview, FeatureBeta), auto-generated SDK components, RequestForm, AgentSkillsTip, MCPTools, and CommunityBanner. Use this page when the main Component Guide does not cover the component you need. Each entry includes copy-paste MDX syntax, live rendering, dependency requirements, and guidance on when to choose a simpler alternative. # Component specialized guide Specialized and less common components for specific use cases Last updated: 2026-10-14 A comprehensive reference for specialized and less commonly used MDX components in Neon documentation. This guide covers components used in specific scenarios, specialized workflows, and edge cases. **Note: Component status** Some components in this guide are currently unused or may be deprecated in future updates. These are included for reference but may be removed from the codebase. **What you will learn:** - How to use specialized MDX components for specific use cases - When to choose specialized components over common ones - Technical requirements and dependencies for specialized components - Best practices for complex component implementations **Related topics** - [Component Guide](https://neon.com/docs/community/component-guide) - [Component Icon Guide](https://neon.com/docs/community/component-icon-guide) - [Component Architecture](https://neon.com/docs/community/component-architecture) - [Documentation Contribution Guide](https://neon.com/docs/community/contribution-guide) ## Quick navigation - [Code display](https://neon.com/docs/community/component-specialized#code-display) - Enhanced code blocks and external code - [Media components](https://neon.com/docs/community/component-specialized#media-components) - Video and multimedia content - [Specialized shared components](https://neon.com/docs/community/component-specialized#specialized-shared-components) - Feature status indicators - [SDK components](https://neon.com/docs/community/component-specialized#sdk-components) - Auto-generated SDK documentation - [Utility components](https://neon.com/docs/community/component-specialized#utility-components) - Forms and specialized UI elements - [Specialized components](https://neon.com/docs/community/component-specialized#specialized-components) - Complex and specialized functionality - [Community components](https://neon.com/docs/community/component-specialized#community-components) - Community engagement features --- ## Code display Enhanced code blocks and external code embedding. ### ExternalCode Embed code from external sources or files. ```mdx ``` **Live preview:** _[External code loaded from GitHub README.md with syntax highlighting]_ Example of external code loading (mocked for showcase): ```markdown # Neon Database Serverless Postgres built for the cloud. ## Key Features - **Instant provisioning**: Create databases in seconds - **Autoscaling**: Scale compute up and down automatically - **Branching**: Create database branches like Git - **Scale to zero**: Save costs when inactive ## Quick Start 1. Sign up at console.neon.tech 2. Create your first project 3. Connect using your preferred client ``` --- ## Media components Components for embedding and displaying multimedia content. ### YoutubeIframe Embedded YouTube video player. ```mdx ``` **Live preview:** [Watch on YouTube](https://youtube.com/watch?v=IcoOpnAcO1Y) --- ### Video Native video player component. ```mdx