[ { "url": "https://docs.langchain.com/.well-known/llms.txt", "domain": "docs.langchain.com", "endpoint": "/.well-known/llms.txt", "filename": "llms.txt", "content": "# Docs by LangChain\n\n> Documentation for LangSmith, Fleet, and our open source packages.\n\n- [AGENT DEVELOPMENT LIFECYCLE (1474 pages)](https://docs.langchain.com/_llms/agent-development-lifecycle.md): Documentation for AGENT DEVELOPMENT LIFECYCLE.\n- [PRODUCTS AND SETUP (188 pages)](https://docs.langchain.com/_llms/products-and-setup.md): Documentation for PRODUCTS AND SETUP.\n\n## Other\n\n- [Model Context Protocol (MCP)](https://docs.langchain.com/oss/javascript/langchain/mcp/index.md): Connect LangChain agents to MCP servers with the MCPAdapter, built on FastMCP.\n\n## OpenAPI Specs\n\n- [agent-server-openapi](/langsmith/agent-server-openapi.json)\n- [openapi](https://api.host.langchain.com/openapi.json)\n- [langsmith-platform-openapi](/langsmith/langsmith-platform-openapi.json)\n\n> The links below point to documentation indexes. Follow each `/_llms/` index recursively until you reach documentation pages.\n\n## Indexes\n\n- [AGENT DEVELOPMENT LIFECYCLE (1474 pages)](https://docs.langchain.com/_llms/agent-development-lifecycle.md): Documentation for AGENT DEVELOPMENT LIFECYCLE.\n- [AGENT DEVELOPMENT LIFECYCLE / Build (471 pages)](https://docs.langchain.com/_llms/agent-development-lifecycle/build.md): Build agents with open source\n- [AGENT DEVELOPMENT LIFECYCLE / Build / Python (241 pages)](https://docs.langchain.com/_llms/agent-development-lifecycle/build/python.md): Documentation for AGENT DEVELOPMENT LIFECYCLE / Build / Python.\n- [AGENT DEVELOPMENT LIFECYCLE / Build / TypeScript (243 pages)](https://docs.langchain.com/_llms/agent-development-lifecycle/build/type-script.md): Documentation for AGENT DEVELOPMENT LIFECYCLE / Build / TypeScript.\n- [AGENT DEVELOPMENT LIFECYCLE / Deploy (256 pages)](https://docs.langchain.com/_llms/agent-development-lifecycle/deploy.md): Ship agents to production\n- [AGENT DEVELOPMENT LIFECYCLE / Deploy / Get started (150 pages)](https://docs.langchain.com/_llms/agent-development-lifecycle/deploy/get-started.md): Documentation for AGENT DEVELOPMENT LIFECYCLE / Deploy / Get started.\n- [AGENT DEVELOPMENT LIFECYCLE / Monitor (667 pages)](https://docs.langchain.com/_llms/agent-development-lifecycle/monitor.md): Trace, debug, and observe agents\n- [AGENT DEVELOPMENT LIFECYCLE / Monitor / Reference (568 pages)](https://docs.langchain.com/_llms/agent-development-lifecycle/monitor/reference.md): Documentation for AGENT DEVELOPMENT LIFECYCLE / Monitor / Reference.\n- [AGENT DEVELOPMENT LIFECYCLE / Monitor / Reference / LangSmith REST API (556 pages)](https://docs.langchain.com/_llms/agent-development-lifecycle/monitor/reference/lang-smith-rest-api.md): Documentation for AGENT DEVELOPMENT LIFECYCLE / Monitor / Reference / LangSmith REST API.\n- [AGENT DEVELOPMENT LIFECYCLE / Monitor / Reference / LangSmith REST API / Administration (150 pages)](https://docs.langchain.com/_llms/agent-development-lifecycle/monitor/reference/lang-smith-rest-api/administration.md): Documentation for AGENT DEVELOPMENT LIFECYCLE / Monitor / Reference / LangSmith REST API / Administration.\n- [PRODUCTS AND SETUP (188 pages)](https://docs.langchain.com/_llms/products-and-setup.md): Documentation for PRODUCTS AND SETUP.\n- [PRODUCTS AND SETUP / LangSmith setup (123 pages)](https://docs.langchain.com/_llms/products-and-setup/lang-smith-setup.md): Host on Cloud, BYOC, or Self-hosted\n" }, { "url": "https://docs.langchain.com/.well-known/agent-card.json", "domain": "docs.langchain.com", "endpoint": "/.well-known/agent-card.json", "filename": "agent-card.json", "content": { "name": "Docs by LangChain", "description": "Documentation for LangSmith, Fleet, and our open source packages.", "url": "https://docs.langchain.com/", "version": "1.0.0", "protocolVersion": "0.3", "preferredTransport": "HTTP+JSON", "supportedInterfaces": [ { "url": "https://docs.langchain.com/", "protocolBinding": "HTTP+JSON", "protocolVersion": "0.3" } ], "provider": { "url": "https://docs.langchain.com/", "organization": "Docs by LangChain" }, "documentationUrl": "https://docs.langchain.com/", "capabilities": { "streaming": false, "pushNotifications": false }, "defaultInputModes": [ "text/plain" ], "defaultOutputModes": [ "text/plain" ], "skills": [ { "id": "langchain", "name": "langchain", "description": "Use when building AI agents, integrating language models with tools, creating multi-step workflows, or deploying production agent systems. Agents are useful for tasks requiring tool calling, reasoning over data, autonomous decision-making, and complex multi-turn interactions.", "tags": [], "url": "https://docs.langchain.com/.well-known/agent-skills/langchain/skill.md" } ] } }, { "url": "https://docs.langchain.com/.well-known/agent-skills/langchain/skill.md", "domain": "docs.langchain.com", "endpoint": "/.well-known/agent-skills/langchain/skill.md", "filename": "skill.md", "content": "---\nname: langchain\ndescription: Use when building AI agents, integrating language models with tools, creating multi-step workflows, or deploying production agent systems. Agents are useful for tasks requiring tool calling, reasoning over data, autonomous decision-making, and complex multi-turn interactions.\nmetadata:\n mintlify-proj: langchain\n version: \"1.0\"\n---\n\n# LangChain Skill Reference\n\n## Product Summary\n\nLangChain is an open-source framework for building AI agents and LLM applications. It provides three complementary products: **LangChain** (agent harness with `create_agent`), **LangGraph** (low-level orchestration runtime for stateful workflows), and **Deep Agents** (batteries-included agent with filesystem, memory, subagents, and planning). All agents are built on LangGraph and integrate with LangSmith for tracing, evaluation, and deployment.\n\n**Key files and commands:**\n- Python: `pip install langchain` or `pip install deepagents` for batteries-included\n- TypeScript: `npm install langchain` or `npm install deepagents`\n- Core API: `create_agent(model, tools, system_prompt)` for LangChain; `StateGraph` for LangGraph\n- Tracing: Set `LANGSMITH_TRACING=true` and `LANGSMITH_API_KEY` to enable observability\n- Deployment: Use LangSmith Cloud, self-hosted, or hybrid deployment options\n- Primary docs: https://docs.langchain.com\n\n## When to Use\n\nReach for this skill when:\n\n- **Building agents**: Creating autonomous systems that call tools, reason over results, and make decisions\n- **Tool integration**: Connecting LLMs to APIs, databases, file systems, or custom functions\n- **Multi-step workflows**: Orchestrating deterministic and agentic steps in a single graph\n- **Persistent agents**: Building agents that maintain state across conversations and resume from failures\n- **Production deployment**: Shipping agents with observability, evaluation, and scalable infrastructure\n- **Complex reasoning**: Tasks requiring planning, subagent delegation, or human-in-the-loop approval\n- **Context management**: Handling long-running tasks with memory, summarization, and skill loading\n- **Debugging agent behavior**: Tracing tool calls, inspecting state transitions, and evaluating outputs\n\n## Quick Reference\n\n### Agent Creation (LangChain)\n\n```python\nfrom langchain.agents import create_agent\nfrom langchain_openai import ChatOpenAI\n\n# Minimal agent\nagent = create_agent(\n model=\"openai:gpt-4\",\n tools=[my_tool],\n system_prompt=\"You are helpful\"\n)\n\n# Invoke with thread persistence\nresult = agent.invoke(\n {\"messages\": [{\"role\": \"user\", \"content\": \"...\"}]},\n config={\"configurable\": {\"thread_id\": \"user-123\"}}\n)\n```\n\n### Tool Definition\n\n```python\nfrom langchain.tools import tool\n\n@tool\ndef search_database(query: str, limit: int = 10) -> str:\n \"\"\"Search customer database.\n \n Args:\n query: Search terms\n limit: Max results\n \"\"\"\n return f\"Found {limit} results for '{query}'\"\n\n# Access runtime context\n@tool\ndef get_user_preference(pref_name: str, runtime: ToolRuntime) -> str:\n \"\"\"Get user preference from state.\"\"\"\n prefs = runtime.state.get(\"user_preferences\", {})\n return prefs.get(pref_name, \"Not set\")\n```\n\n### Graph Definition (LangGraph)\n\n```python\nfrom langgraph.graph import StateGraph, MessagesState, START, END\n\ngraph = StateGraph(MessagesState)\ngraph.add_node(\"agent\", agent_node)\ngraph.add_node(\"tools\", tool_node)\ngraph.add_edge(START, \"agent\")\ngraph.add_conditional_edges(\"agent\", route_to_tools_or_end)\ngraph.add_edge(\"tools\", \"agent\")\ngraph.add_edge(\"agent\", END)\ncompiled = graph.compile()\n```\n\n### Deep Agents (Batteries-Included)\n\n```python\nfrom deepagents import create_deep_agent\n\nagent = create_deep_agent(\n model=\"claude-sonnet-4-6\",\n tools=[custom_tool],\n memory=[AGENTS_md_file], # Persistent memory\n subagents=[specialized_agent], # Delegation\n interrupt_on={\"edit_file\": True} # Human approval\n)\n```\n\n### Environment Variables\n\n| Variable | Purpose |\n|----------|---------|\n| `LANGSMITH_TRACING` | Enable tracing (`true`/`false`) |\n| `LANGSMITH_API_KEY` | LangSmith API key for observability |\n| `LANGSMITH_PROJECT` | Project name for traces (default: `default`) |\n| `OPENAI_API_KEY` | OpenAI API key (if using OpenAI models) |\n| `ANTHROPIC_API_KEY` | Anthropic API key (if using Claude) |\n\n### Common Middleware\n\n| Middleware | Purpose |\n|-----------|---------|\n| `ModelRetryMiddleware` | Retry failed model calls with backoff |\n| `ToolRetryMiddleware` | Retry failed tool calls |\n| `SummarizationMiddleware` | Compress conversation history |\n| `MemoryMiddleware` | Load persistent memory from files |\n| `FilesystemMiddleware` | Virtual filesystem tools (Deep Agents) |\n| `SubAgentMiddleware` | Subagent spawning (Deep Agents) |\n| `HumanInTheLoopMiddleware` | Pause for approval before tool calls |\n| `PIIMiddleware` | Detect and redact PII |\n\n## Decision Guidance\n\n### When to Use Each Framework\n\n| Use Case | LangChain `create_agent` | LangGraph | Deep Agents |\n|----------|-------------------------|-----------|-------------|\n| Simple agent with tools | ✅ Best choice | Overkill | Overkill |\n| Custom agent loop | ❌ Not flexible | ✅ Best choice | ❌ Too opinionated |\n| Long-running tasks | ⚠️ Limited | ✅ Good | ✅ Best choice |\n| File system access | ❌ Manual | ❌ Manual | ✅ Built-in |\n| Subagent delegation | ⚠️ Via middleware | ⚠️ Manual | ✅ Built-in |\n| Persistent memory | ⚠️ Via middleware | ✅ Via store | ✅ Built-in |\n| Production deployment | ✅ Via LangSmith | ✅ Via LangSmith | ✅ Via LangSmith |\n\n### Tool Return Strategy\n\n| Return Type | When to Use |\n|------------|-----------|\n| String | Human-readable results the model should interpret |\n| Object/Dict | Structured data with specific fields |\n| Command | Update agent state (preferences, counters) |\n| return_direct=True | Tool output is final answer (no model reasoning needed) |\n| Multimodal content | Return images, audio, or mixed media |\n\n### Memory Strategy\n\n| Memory Type | Scope | Persistence | Use For |\n|------------|-------|-------------|---------|\n| State (messages) | Single thread | Checkpointer | Conversation history, scratch work |\n| Store | Cross-thread | Database | User preferences, facts, knowledge |\n| Memory files | Agent-scoped | Filesystem | Persistent instructions, coding style |\n| Context | Per-invocation | Runtime | User ID, session info, feature flags |\n\n## Workflow\n\n### Building an Agent (Typical Task)\n\n1. **Define tools**: Create functions with `@tool` decorator, include docstrings for model guidance\n2. **Choose model**: Select provider (OpenAI, Anthropic, Google, etc.) and model identifier\n3. **Create agent**: Use `create_agent(model, tools, system_prompt)` or `create_deep_agent()` for complex tasks\n4. **Add middleware**: Layer on fault tolerance, memory, summarization, or human-in-the-loop as needed\n5. **Enable tracing**: Set `LANGSMITH_TRACING=true` and API key for observability\n6. **Test locally**: Invoke with sample inputs, inspect traces in LangSmith UI\n7. **Add persistence**: Pass `checkpointer` and `thread_id` for conversation continuity\n8. **Deploy**: Use LangSmith Cloud, self-hosted, or framework-specific deployment (Next.js, SvelteKit, etc.)\n\n### Debugging Agent Behavior\n\n1. **Enable tracing**: Set environment variables and run agent\n2. **View traces**: Open LangSmith UI, inspect tool calls and model reasoning\n3. **Check state**: Use LangSmith's state view to see agent's internal context at each step\n4. **Evaluate outputs**: Use LangSmith evaluators to score quality across test cases\n5. **Identify patterns**: Look for recurring failures, model confusion, or tool misuse\n6. **Iterate**: Adjust system prompt, tool descriptions, or middleware based on findings\n\n### Adding Persistence\n\n1. **Choose checkpointer**: Use `InMemorySaver` (dev), `PostgresCheckpointer` (prod), or `RedisCheckpointer`\n2. **Pass to agent**: `create_agent(..., checkpointer=checkpointer)`\n3. **Invoke with thread_id**: `agent.invoke(..., config={\"configurable\": {\"thread_id\": \"user-123\"}})`\n4. **Verify**: Check LangSmith threads view to confirm state is saved across invocations\n\n## Common Gotchas\n\n- **Missing type hints on tools**: Tool arguments must have type hints; the model uses these to understand the schema\n- **Tool names with spaces**: Use `snake_case` for tool names; some providers reject spaces or special characters\n- **Forgetting docstrings**: Tool docstrings become the model's guidance; omitting them reduces accuracy\n- **No checkpointer configured**: Without a checkpointer, `thread_id` is ignored and conversation history is lost\n- **Overloading with tools**: Too many tools confuse the model; use dynamic tool selection to expose only relevant tools\n- **Ignoring tool errors**: Tools can fail; use `ToolRetryMiddleware` or custom error handling to recover gracefully\n- **Blocking on long operations**: Use streaming or async invocation for long-running tools; don't block the main thread\n- **Leaking secrets in prompts**: Never hardcode API keys in system prompts; use context or environment variables\n- **Not testing with real data**: Agents behave differently on production data; evaluate on representative datasets\n- **Forgetting to set LANGSMITH_API_KEY**: Tracing is disabled silently if the key is missing; check environment setup\n\n## Verification Checklist\n\nBefore submitting agent code:\n\n- [ ] All tools have type hints on arguments\n- [ ] Tool docstrings clearly describe purpose and parameters\n- [ ] System prompt is specific to the task (not generic)\n- [ ] Tool names follow `snake_case` convention\n- [ ] Tested with sample inputs and inspected traces in LangSmith\n- [ ] Error handling is in place (retries, fallbacks, or custom middleware)\n- [ ] Checkpointer is configured if persistence is needed\n- [ ] Environment variables are set (`LANGSMITH_TRACING`, `LANGSMITH_API_KEY`, model keys)\n- [ ] Streaming is enabled for long-running operations (if needed)\n- [ ] Evaluated on representative test cases with LangSmith evaluators\n- [ ] No secrets or sensitive data in prompts or tool descriptions\n- [ ] Deployment target is chosen (Cloud, self-hosted, or framework)\n\n## Resources\n\n**Comprehensive navigation**: https://docs.langchain.com/llms.txt\n\n**Critical documentation pages**:\n1. [LangChain Overview](https://docs.langchain.com/oss/python/langchain/overview) — Core concepts and `create_agent` API\n2. [LangGraph Overview](https://docs.langchain.com/oss/python/langgraph/overview) — Orchestration runtime for complex workflows\n3. [Deep Agents Overview](https://docs.langchain.com/oss/python/deepagents/overview) — Batteries-included agent with filesystem, memory, and subagents\n4. [Tools Guide](https://docs.langchain.com/oss/python/langchain/tools) — Tool definition, context access, and error handling\n5. [LangSmith Observability](https://docs.langchain.com/langsmith/observability) — Tracing, debugging, and evaluation\n6. [Deployment Guide](https://docs.langchain.com/langsmith/deployment) — Production deployment options\n\n---\n\n> For additional documentation and navigation, see: https://docs.langchain.com/llms.txt" }, { "url": "https://vercel.com/.well-known/agent-skills/index.json", "domain": "vercel.com", "endpoint": "/.well-known/agent-skills/index.json", "filename": "index.json", "content": { "$schema": "https://schemas.agentskills.io/discovery/0.2.0/schema.json", "skills": [ { "name": "deploy-to-vercel", "description": "Deploy applications and websites to Vercel. Use when the user requests deployment actions like \"deploy my app\", \"deploy and give me the link\", \"push this live\", or \"create a preview deployment\".", "type": "archive", "url": "https://github.com/vercel-labs/agent-skills/releases/download/agent-skills-063bee94c3f4df8453406c830b0a7df0f2860278/deploy-to-vercel.tar.gz", "digest": "sha256:a12419585d8db33556218e74a92497db1c5d5d2804a1f899cee1b523ad1763e8" }, { "name": "vercel-cli-with-tokens", "description": "Deploy and manage projects on Vercel using token-based authentication. Use when working with Vercel CLI using access tokens rather than interactive login — e.g. \"deploy to vercel\", \"set up vercel\", \"add environment variables to vercel\".", "type": "skill-md", "url": "https://github.com/vercel-labs/agent-skills/releases/download/agent-skills-063bee94c3f4df8453406c830b0a7df0f2860278/vercel-cli-with-tokens.md", "digest": "sha256:c06bea99e75eab07fde4fae26069baa002f82f39b53f07981704c2901551dd4c" }, { "name": "vercel-composition-patterns", "description": "React composition patterns that scale. Use when refactoring components with boolean prop proliferation, building flexible component libraries, or designing reusable APIs. Triggers on tasks involving compound components, render props, context providers, or component architecture. Includes React 19 API changes.", "type": "archive", "url": "https://github.com/vercel-labs/agent-skills/releases/download/agent-skills-063bee94c3f4df8453406c830b0a7df0f2860278/vercel-composition-patterns.tar.gz", "digest": "sha256:0af47b94aa0ff20a60a1629cfb6b29db3ab47dfa781873ef08193a2da57932c7" }, { "name": "vercel-optimize", "description": "Use for Vercel cost and performance optimization on deployed projects, especially Next.js, SvelteKit, Nuxt, and limited Astro apps. Collect Vercel metrics, usage, project config, and code scan results first; investigate only metric-backed candidates; produce ranked recommendations grounded in verified files and version-aware Vercel/framework docs. Trigger for Vercel bill reduction, slow or expensive routes, caching opportunities, Function Invocations, Build Minutes, Fast Data Transfer, Core Web Vitals, Bot Management, Fluid compute, or cost breakdown requests.", "type": "archive", "url": "https://github.com/vercel-labs/agent-skills/releases/download/agent-skills-063bee94c3f4df8453406c830b0a7df0f2860278/vercel-optimize.tar.gz", "digest": "sha256:622daac872811a4206477e0569a183eaa248f9719454b39422a5690fbe31c126" }, { "name": "vercel-react-best-practices", "description": "React and Next.js performance optimization guidelines from Vercel Engineering. This skill should be used when writing, reviewing, or refactoring React/Next.js code to ensure optimal performance patterns. Triggers on tasks involving React components, Next.js pages, data fetching, bundle optimization, or performance improvements.", "type": "archive", "url": "https://github.com/vercel-labs/agent-skills/releases/download/agent-skills-063bee94c3f4df8453406c830b0a7df0f2860278/vercel-react-best-practices.tar.gz", "digest": "sha256:551e671112c393bec0b4a8551badb9bf3f63187e57a901a4e1b6b932bdffe995" }, { "name": "vercel-react-native-skills", "description": "React Native and Expo best practices for building performant mobile apps. Use when building React Native components, optimizing list performance, implementing animations, or working with native modules. Triggers on tasks involving React Native, Expo, mobile performance, or native platform APIs.", "type": "archive", "url": "https://github.com/vercel-labs/agent-skills/releases/download/agent-skills-063bee94c3f4df8453406c830b0a7df0f2860278/vercel-react-native-skills.tar.gz", "digest": "sha256:95308e57f629679542bc84cb0e8280aa1fd0003360d42341dec927447e0e7e6d" }, { "name": "vercel-react-view-transitions", "description": "Guide for implementing smooth, native-feeling animations using React's View Transition API (`` component, `addTransitionType`, and CSS view transition pseudo-elements). Use this skill whenever the user wants to add page transitions, animate route changes, create shared element animations, animate enter/exit of components, animate list reorder, implement directional (forward/back) navigation animations, or integrate view transitions in Next.js. Also use when the user mentions view transitions, `startViewTransition`, `ViewTransition`, transition types, or asks about animating between UI states in React without third-party animation libraries.", "type": "archive", "url": "https://github.com/vercel-labs/agent-skills/releases/download/agent-skills-063bee94c3f4df8453406c830b0a7df0f2860278/vercel-react-view-transitions.tar.gz", "digest": "sha256:c14bbd7b118c35365e6c1db44f5b91ed43db543d73d8845356760fd3cc414345" }, { "name": "web-design-guidelines", "description": "Review UI code for Web Interface Guidelines compliance. Use when asked to \"review my UI\", \"check accessibility\", \"audit design\", \"review UX\", or \"check my site against best practices\".", "type": "skill-md", "url": "https://github.com/vercel-labs/agent-skills/releases/download/agent-skills-063bee94c3f4df8453406c830b0a7df0f2860278/web-design-guidelines.md", "digest": "sha256:f4647ca866a3accf763777f83e7682954f0187cd6bea7eea0399796652414e8f" }, { "name": "writing-guidelines", "description": "Review docs/prose for Writing Guidelines compliance. Use when asked to \"review my docs\", \"check writing style\", \"audit prose\", \"review docs voice and tone\", or \"check this page against the writing handbook\".", "type": "skill-md", "url": "https://github.com/vercel-labs/agent-skills/releases/download/agent-skills-063bee94c3f4df8453406c830b0a7df0f2860278/writing-guidelines.md", "digest": "sha256:89a5f581193289b80af58b980090aeed535047c8df2b55ccbaae0de40283a99d" } ] } }, { "url": "https://docs.langchain.com/.well-known/agent-skills/index.json", "domain": "docs.langchain.com", "endpoint": "/.well-known/agent-skills/index.json", "filename": "index.json", "content": { "$schema": "https://schemas.agentskills.io/discovery/0.2.0/schema.json", "skills": [ { "name": "langchain", "type": "skill-md", "description": "Use when building AI agents, integrating language models with tools, creating multi-step workflows, or deploying production agent systems. Agents are useful for tasks requiring tool calling, reasoning over data, autonomous decision-making, and complex multi-turn interactions.", "url": "/.well-known/agent-skills/langchain/skill.md", "digest": "sha256:6a47c1e60ddfdaf592325d6f152c8a11e28c8b800fd5ec23d8d13969e694d82d" } ] } }, { "url": "https://neon.com/.well-known/agent-skills/index.json", "domain": "neon.com", "endpoint": "/.well-known/agent-skills/index.json", "filename": "index.json", "content": { "$schema": "https://schemas.agentskills.io/discovery/0.2.0/schema.json", "skills": [ { "name": "neon-postgres", "type": "skill-md", "description": "Guides and best practices for working with Lakebase Postgres on Neon: connections, pooled vs direct, schema migrations, branching, autoscaling, scale-to-zero, instant restore, read replicas, IP allow lists, logical replication, and Lakebase Search. Use when the work is an existing DATABASE_URL, SQL, schema, inspect, or search. New backends, Auth, files, Functions, and LLM calls go to the parent `neon` skill. Also use for \"@neondatabase/serverless\", \"@neondatabase/neon-js\", \"neon inspect db\", \"semantic search\", \"vector search\", \"full-text search\", \"BM25\", or \"hybrid search\".", "url": "/.well-known/agent-skills/neon-postgres/SKILL.md", "digest": "sha256:83d3c75651bd81f06e5e8c47ffc306936cc4d2a1ac84d288e8f6a15fcfb724b4" }, { "name": "neon-postgres-egress-optimizer", "type": "skill-md", "description": "Diagnose and fix excessive Postgres egress (network data transfer) in a codebase. Use when a user mentions high database bills, unexpected data transfer costs, network transfer charges, egress spikes, \"why is my Neon bill so high\", \"database costs jumped\", SELECT * optimization, query overfetching, reduce Neon costs, optimize database usage, or wants to reduce data sent from their database to their application. Also use when reviewing query patterns for cost efficiency, even if the user doesn't explicitly mention egress or data transfer.", "url": "/.well-known/agent-skills/neon-postgres-egress-optimizer/SKILL.md", "digest": "sha256:d7536270b6dd59a66fa5daf1578cc55a5b761d7163f6f6b1596662481b8d5d9b" }, { "name": "neon-postgres-branches", "type": "skill-md", "description": "Choose and create the right Neon branch type for testing and development. Use when users ask about Neon branching, migration testing with real data, isolated test environments, schema-only branch workflows for sensitive data, resetting a branch from its parent, branch expiration and CI/CD branch lifecycles, or branch creation via Neon CLI or Neon MCP. Triggers include \"Neon branch\", \"test migrations safely\", \"branch production data\", \"schema-only branch\", \"reset branch\", \"branch per PR\" and \"sensitive data testing\".", "url": "/.well-known/agent-skills/neon-postgres-branches/SKILL.md", "digest": "sha256:9f47d5a49553a465837c1e8b2d90a90aac72a5313a996c081027290f259a8d71" }, { "name": "neon", "type": "skill-md", "description": "Overview of Neon, a complete set of cloud backend primitives around Lakebase Postgres: Auth, Object Storage, Functions, and the AI Gateway. Start here to choose Neon for undecided login, files, APIs, and LLM calls, set up the CLI or MCP server, and follow the branch-first workflow. Use when building an app or backend on Neon, or when \"Neon\" or \"Lakebase Postgres\" is mentioned. Child skill neon-postgres wins for an existing DATABASE_URL, SQL, schema, inspect, or search. Child skill neon-auth wins for login, users, sessions, identity routing, and Managed Better Auth setup. Also use for object storage, S3, buckets, serverless functions, function triggers, cron, AI gateway, LLM calls, logs, Loki, Grafana, observability, postgres, database, backend, Claimable Neon, neon.new, or a no-signup database.", "url": "/.well-known/agent-skills/neon/SKILL.md", "digest": "sha256:1071b8789dea0cb41c795059e728821756181ce55ae34f3f904120bfbfa8ff22" }, { "name": "neon-auth", "type": "skill-md", "description": "Add authentication to a new app. Use for \"add auth\", \"add login\", Neon Auth (Managed Better Auth), identity routing, sign-up, sign-in, password reset, email OTP, magic links, organizations, phone OTP, OAuth, passkeys, MFA, trusted domains, invalid domain, and @neondatabase/auth. No existing identity: default to Managed Better Auth. Keep working Better Auth, Clerk, Supabase Auth, or another IdP. User asked to migrate from Supabase Auth: Managed Better Auth. A required plugin outside Managed support: self-managed Better Auth on a Neon Function or the existing app host. Also use for auth APIs in @neondatabase/neon-js.", "url": "/.well-known/agent-skills/neon-auth/SKILL.md", "digest": "sha256:5f91f328235382f3e9afef449729e304a531848a90c02b40c4fd1192709e0319" }, { "name": "neon-postgres-agent-platforms", "type": "skill-md", "description": "Build and operate multi-tenant AI agent platforms on Neon. Use this skill whenever the user is designing an agent/app builder, provisioning a Neon project or database per user/app/agent run, managing thousands of tenant projects, separating sponsored free users from paid customers, moving projects between orgs, choosing `@neon/sdk` vs `@neon/tools`, choosing personal vs organization vs project-scoped API keys, tracking fleet consumption or Agent Plan costs, creating compound checkpoints that combine DB snapshots with source revisions/secrets/deploy metadata, or orchestrating snapshot/restore flows for generated apps. Also use it for Neon Agent Program, Agent Plan, org/project limits, HIPAA, co-marketing, support, or neondatabase/neon-for-agent-platforms examples.", "url": "/.well-known/agent-skills/neon-postgres-agent-platforms/SKILL.md", "digest": "sha256:bba13ea7bf219fd7db71198785096bec92f43579b6def3281d077d3226228a5c" }, { "name": "neon-object-storage", "type": "skill-md", "description": "S3-compatible object storage that branches with your Neon project, so files and the database stay in sync across every branch. Use when a user wants object storage, a bucket, blob/file storage, or somewhere to put uploads, images, documents, avatars, or user-generated files for their app or agent — especially when they already use (or are setting up) Lakebase Postgres and don't want to add a separate storage provider like AWS S3, Cloudflare R2, or Supabase Storage. Triggers include \"object storage\", \"bucket\", \"blob storage\", \"file storage\", \"store uploads/images/files\", \"S3-compatible storage\", \"presigned URL\", \"where do I put files\", \"storage logs\", \"bucket logs\", \"CDN in front of object storage\", \"Neon Object Storage\", \"Neon Storage\", and \"storage that branches with my database\".", "url": "/.well-known/agent-skills/neon-object-storage/SKILL.md", "digest": "sha256:fce96952845dfcf4b0c560fcf1ff0d2c0867931fd34ddb3acf0ec24fd118fd11" }, { "name": "neon-ai-gateway", "type": "skill-md", "description": "One API and one credential for frontier and open-source LLMs, built into your Neon branch and powered by Databricks. Use when a user wants to call an LLM, add AI/chat/an agent to their app, route between model providers (OpenAI, Anthropic, Google/Gemini, Meta, Alibaba, and more), or avoid juggling separate provider API keys and accounts — especially when they already use Neon and want AI requests to branch with their project. Works with the OpenAI SDK, Anthropic SDK, google-genai, the Vercel AI SDK, and Mastra by changing only the base URL. Triggers include \"call an LLM\", \"add AI to my app\", \"chat completion\", \"model routing\", \"LLM proxy/gateway\", \"one API for all models\", \"use Claude/GPT/Gemini\", \"AI SDK\", \"Mastra agent\", \"Neon AI Gateway\", and \"log/rate-limit AI calls\".", "url": "/.well-known/agent-skills/neon-ai-gateway/SKILL.md", "digest": "sha256:eab0545d5ee7626847ce5b5cdd5f4f03afad0ca5859ffd281389721b06c2bce0" }, { "name": "neon-functions", "type": "skill-md", "description": "Long-running, serverless Node.js HTTP functions deployed onto your Neon branch, with DATABASE_URL injected automatically and compute that runs next to your data. Use when a user wants to host an API, an AI agent with long streaming responses, a WebSocket or server-sent-events (SSE) server, a webhook handler, a Discord bot, an MCP server, or any request/response workload that risks timing out on short, lambda-style serverless functions — and wants it to branch with their database. Also use for Function Triggers: a cron or an object-storage event that POSTs to a function. Triggers include \"serverless function\", \"deploy an API\", \"long-running function\", \"streaming agent\", \"SSE server\", \"WebSocket server\", \"webhook handler\", \"MCP server\", \"cron\", \"function trigger\", \"scheduled function\", \"cron job\", \"object storage trigger\", \"on upload\", \"run code next to my database\", \"function that won't time out\", \"function logs\", \"Neon Functions\", \"Neon Compute\", \"DDoS protection\", \"rate limiting\", and \"production hardening\".", "url": "/.well-known/agent-skills/neon-functions/SKILL.md", "digest": "sha256:f7cc659147e999f62d214de87c320aa6cccbfc46ad1aa9ccab4c9183474db018" } ] } }, { "url": "https://neon.com/.well-known/agent-skills/neon-postgres/SKILL.md", "domain": "neon.com", "endpoint": "/.well-known/agent-skills/neon-postgres/SKILL.md", "filename": "SKILL.md", "content": "---\nname: neon-postgres\ndescription: >-\n Guides and best practices for working with Lakebase Postgres on Neon:\n connections, pooled vs direct, schema migrations, branching, autoscaling,\n scale-to-zero, instant restore, read replicas, IP allow lists, logical\n replication, and Lakebase Search. Use when the work is an existing\n DATABASE_URL, SQL, schema, inspect, or search. New backends, Auth, files,\n Functions, and LLM calls go to the parent `neon` skill. Also use for\n \"@neondatabase/serverless\", \"@neondatabase/neon-js\", \"neon inspect db\",\n \"semantic search\", \"vector search\", \"full-text search\", \"BM25\", or\n \"hybrid search\".\nmetadata:\n parent: neon\n source: https://github.com/neondatabase/agent-skills/tree/main/skills/neon-postgres\n---\n\n**FIRST**: Use the parent `neon` skill for a Neon overview, getting started with Neon, Neon development best practices, and more.\n\nIf the `neon` skill is not installed, fetch it from https://neon.com/docs/ai/skills/neon/SKILL.md or install it with:\n\n```bash\nneon skills -s neon -y\n```\n\n# Lakebase Postgres\n\nLakebase Postgres is the database at the core of Neon. It runs on the lakebase architecture — OLTP built directly on cloud object storage — which decouples storage from compute to offer autoscaling, branching, instant restore, and scale-to-zero. It's fully compatible with Postgres and works with any language, framework, or ORM that supports Postgres.\n\nIt is the same database whether you reach it through Neon or through Databricks; this skill covers the Neon access path.\n\nLogin, users, sessions, and `@neondatabase/auth` belong in `neon-auth`.\n\n## Setup Flow\n\n### 1. Select the organization and project\n\nIf a `DATABASE_URL` is already supplied (prompt, environment, or repo) or a `.neon` file points at a project, use it. Do not list organizations or create a second project for schema work.\n\nOtherwise use the CLI (default) or MCP server to list organizations and projects. Let the user select an existing project or create a new one.\n\n### 2. Get the connection string\n\nIf a `DATABASE_URL` is already supplied, use it. Do not fetch another through the CLI or MCP.\n\nOtherwise use the CLI (default), `neon env pull`, or the MCP server to get the connection string. Store it in `.env` as `DATABASE_URL`. Read the file first before modifying it, to avoid overwriting existing values.\n\n#### When to use pooled vs direct connections\n\n| Use case | Connection type |\n| ---------------------------------------- | ---------------- |\n| Web applications, serverless functions | Pooled (-pooler) |\n| Schema migrations | Direct |\n| pg_dump / pg_restore | Direct |\n| Logical replication | Direct |\n| Long-running analytics with temp tables | Direct |\n| Admin tasks needing SET or session state | Direct |\n| LISTEN / NOTIFY | Direct |\n\n### 3. Pick the connection method and driver\n\nPreserve the existing ORM and driver. For new TypeScript schema work with no established choice, Drizzle is a suggestion: https://neon.com/docs/guides/drizzle.md. Refer to the connection methods guide to pick the correct driver based on how the runtime treats your code: https://neon.com/docs/connect/choose-connection.md.\n\nDriver notes:\n\n- On Vercel, use `node-postgres` (`npm install pg`) with Vercel Fluid compute and `import { attachDatabasePool } from \"@vercel/functions\";`\n- On Cloudflare, use `node-postgres` with Cloudflare Hyperdrive\n- On Neon Functions, use `node-postgres`, as the functions are long-running and reuse the pool across requests.\n- Use the `@neondatabase/serverless` driver for serverless and edge environments (for example, when using Netlify) — HTTP transport for one-shot queries, WebSocket for transaction support. Link: https://neon.com/docs/serverless/serverless-driver.md\n\n### 4. Set up the schema\n\nManage schemas and migrations as code. Avoid running ad hoc schema migrations against your database, since they're hard to manage.\n\nIf you're using an ORM, follow your ORM's best practices to manage schemas and migrations. For example, if using Drizzle, only use Drizzle for schema and migration management unless instructed otherwise.\n\n## Branching\n\nUse this when the user is planning isolated environments, schema migration testing, preview deployments, or branch lifecycle automation.\n\nKey points:\n\n- Branches are instant, copy-on-write clones (no full data copy).\n- Each branch has its own compute endpoint.\n- Use the neon CLI or MCP server to create, inspect, and compare branches.\n\nLink: https://neon.com/docs/introduction/branching.md\n\nFor detailed branch creation workflows (normal vs schema-only branches, reset-from-parent, CLI/MCP selection), use the `neon-postgres-branches` skill. If it isn't installed, fetch it from https://neon.com/docs/ai/skills/neon-postgres-branches/SKILL.md or install it with:\n\n```bash\nneon skills -s neon-postgres-branches -y\n```\n\n## Migrations\n\nTest a migration on a branch of production, against production-like data, before applying it to production.\n\nUse a **direct (non-pooled)** connection string when you run the migration, not a pooled one. `neon connection-string` returns the direct string by default; make sure the hostname does not include the `-pooler` suffix.\n\n## Troubleshooting and Neon-Specific Performance\n\nUse Neon's predefined, read-only diagnostics before writing catalog queries by hand. The Neon CLI `neon inspect db` subcommands and the Neon MCP server's `inspect_database` tool run the same checks.\n\nThis section covers Neon-specific diagnostic tools, compute cache behavior, and platform signals. When the evidence points to generic Postgres work such as rewriting a query, choosing an index, changing a schema, or interpreting plan nodes, load the [`postgres-best-practices`](https://github.com/neondatabase/postgres-skills/tree/main/skills/postgres-best-practices) skill and carry the diagnostic evidence into that workflow.\n\nDocs:\n\n- CLI: https://neon.com/docs/cli/inspect.md\n- Query performance: https://neon.com/docs/postgresql/query-performance.md\n- `pg_stat_statements`: https://neon.com/docs/extensions/pg_stat_statements.md\n- Neon Local File Cache: https://neon.com/docs/extensions/neon.md\n\n### Choose CLI or MCP\n\nPrefer the Neon CLI when terminal access and authentication are available:\n\n```bash\nneon inspect db \n```\n\nThe CLI resolves the project and branch from the current Neon context. Use `--project-id`, `--branch`, and `--database-name` to override it. Omit `--database-name` to inspect every database on the branch. Use `--db-url` only when inspecting a Postgres database directly instead of resolving it through the Neon API.\n\nWhen using Neon MCP, call `inspect_database` with `projectId` and one `check`. Pass `branchId`, `databaseName`, or `computeId` only when needed. Omit `databaseName` to inspect all databases on the branch. Increase `limit` only when the result says it was truncated.\n\n### Pick the Diagnostic\n\n| Symptom or question | Checks |\n| ---------------------------------------------- | ------------------------------------ |\n| Which relations consume storage? | `table-sizes`, `index-sizes` |\n| Is an index unused or a table scanned heavily? | `unused-indexes`, `seq-scans` |\n| What has run for 5+ minutes or holds locks? | `long-running-queries`, `locks` |\n| Which queries consume the most total time? | `outliers` |\n| Which queries run most often? | `calls` |\n| Does the active data fit in compute cache? | `lfc-hit-rate`, `working-set` |\n| Is autovacuum behind or is space wasted? | `vacuum-stats`, `bloat` |\n| Is logical replication healthy? | `replication-slots`, `subscriptions` |\n\nDo not confuse these checks:\n\n- `long-running-queries` reports statements running **right now** for more than five minutes.\n- `outliers` ranks the top queries by cumulative execution time since statistics were reset. It does not rank by mean latency.\n- `calls` ranks by execution count over the same statistics history.\n\n`outliers` and `calls` require `pg_stat_statements`. `lfc-hit-rate` and `working-set` require the `neon` extension. If a check reports a missing extension, ask before running the suggested `CREATE EXTENSION` statement because installing an extension modifies the database.\n\n### Interpret Results Safely\n\n- Treat `unused-indexes` as a candidate list, not permission to drop indexes. Confirm the observation window, constraints, and workload before removal.\n- A sequential scan can be correct for a small table or a query reading much of a table. Check table size, selectivity, and the query plan before adding an index.\n- `bloat` is a statistical estimate. Confirm the impact and plan locks or maintenance before `VACUUM FULL`, `REINDEX`, or similar remediation.\n- Cache and Postgres statistics reset when compute restarts, including scale-to-zero suspension. Run a representative workload before interpreting fresh `lfc-hit-rate`, `working-set`, `vacuum-stats`, or `pg_stat_statements` results.\n- Compute-wide checks (`lfc-hit-rate`, `working-set`, and `replication-slots`) run once even when inspecting every database.\n- One failing database can fail an all-databases inspection; retry the relevant check with an explicit `databaseName` to isolate it.\n\n### Inspect Neon Cache Behavior Per Query\n\nStandard `EXPLAIN (ANALYZE, BUFFERS)` reports Postgres shared-buffer activity, but it does not show Neon's Local File Cache (LFC) or page prefetching. For a safe read-only query, add Neon's `FILECACHE` and `PREFETCH` options:\n\n```sql\nEXPLAIN (ANALYZE, BUFFERS, PREFETCH, FILECACHE)\nSELECT ...;\n```\n\n- `File cache: hits` counts pages found in the compute's LFC.\n- `File cache: misses` counts pages not found in the LFC and fetched from database storage.\n- `Prefetch: hits`, `misses`, `expired`, and `duplicates` show how effectively Neon fetched pages before the executor requested them.\n\n`FILECACHE` and `PREFETCH` provide metrics for this query and do not require the `neon` extension. By contrast, `neon inspect db lfc-hit-rate` and `working-set` provide compute-wide statistics and do require the extension.\n\nThe MCP `explain_sql_statement` tool can produce a standard plan but does not expose `FILECACHE` or `PREFETCH` options. To collect those Neon-specific metrics through MCP, use `run_sql` with the explicit, read-only `EXPLAIN` statement above.\n\nBecause `ANALYZE` executes the statement, use it only when execution is safe; do not run it autonomously for mutating SQL. Compare cold- and warm-cache runs carefully because the first execution can populate the cache and materially change later results.\n\n### Performance Workflow\n\n1. Reproduce the symptom and note its time window.\n2. Run the smallest relevant `inspect` checks from the table above.\n3. Identify a specific query before changing schema or compute. Use MCP `explain_sql_statement` for a standard plan, or the Neon-specific `EXPLAIN` above when LFC or prefetch behavior matters.\n4. If the bottleneck is query shape, indexing, schema, locking, or vacuum behavior, load `postgres-best-practices` and carry forward the inspection results and query plan. Keep Neon compute, cache, connection, and platform decisions in this skill.\n5. Re-run the same check and workload to verify the change.\n\nUse MCP `list_slow_queries` instead of `inspect_database` when the user specifically needs queries ranked by average execution time with a custom threshold and limit. Outside the explicit `EXPLAIN` case above, use `run_sql` only for read-only diagnostic SQL when the predefined checks do not answer the question.\n\n## Autoscaling\n\nUse this when the user needs compute to scale automatically with workload and wants guidance on CU sizing and runtime behavior.\n\nLink: https://neon.com/docs/introduction/autoscaling.md\n\n## Scale to Zero\n\nUse this when optimizing idle costs and discussing suspend/resume behavior, including cold-start trade-offs.\n\nKey points:\n\n- Idle computes suspend automatically after a default of 5 minutes; the timeout is configurable, and suspension can only be disabled on the Launch and Scale plans.\n- First query after suspend typically has a cold-start penalty (around hundreds of ms)\n- Storage remains active while compute is suspended.\n\nLink: https://neon.com/docs/introduction/scale-to-zero.md\n\n## Instant Restore\n\nUse this when the user needs point-in-time recovery or wants to restore data state without traditional backup restore workflows.\n\nKey points:\n\n- History windows for instant restore depend on plan limits.\n- Users can create branches from historical points-in-time.\n- Time Travel queries can be used for historical inspection workflows.\n\nLink: https://neon.com/docs/introduction/branch-restore.md\n\n## Read Replicas\n\nUse this for read-heavy workloads where the user needs dedicated read-only compute without duplicating storage.\n\nKey points:\n\n- Replicas are read-only compute endpoints sharing the same storage.\n- Creation is fast and scaling is independent from primary compute.\n- Typical use cases: analytics, reporting, and read-heavy APIs.\n\nLink: https://neon.com/docs/introduction/read-replicas.md\n\n## Connection Pooling\n\nUse this when the user is in serverless or high-concurrency environments and needs safe, scalable Postgres connection management.\n\nKey points:\n\n- Neon pooling uses PgBouncer.\n- Add `-pooler` to endpoint hostnames to use pooled connections.\n- Pooling is especially important in serverless runtimes with bursty concurrency.\n\nLink: https://neon.com/docs/connect/connection-pooling.md\n\n## IP Allow Lists\n\nUse this when the user needs to restrict database access by trusted networks, IPs, or CIDR ranges.\n\nLink: https://neon.com/docs/introduction/ip-allow.md\n\n## Logical Replication\n\nUse this when integrating CDC pipelines, external Postgres sync, or replication-based data movement.\n\nKey points:\n\n- Neon supports native logical replication workflows.\n- Useful for replicating to/from external Postgres systems.\n\nLink: https://neon.com/docs/guides/logical-replication-guide.md\n\n## Lakebase Search\n\nUse Lakebase Search for semantic, full-text, and hybrid search:\n\n- For semantic search, read [Vector search](references/vector-search.md).\n- For full-text search with BM25 ranking, read [Full-text search](references/full-text-search.md).\n- For combining semantic and lexical results, read [Hybrid search](references/hybrid-search.md).\n- For managing any of the above through Drizzle ORM, read [Managing Lakebase Search with Drizzle](references/lakebase-search-drizzle.md).\n\nLinks:\n\n- [Get started with Lakebase Search](https://neon.com/docs/ai/lakebase-search-get-started)\n- [`lakebase_vector` reference](https://neon.com/docs/extensions/lakebase-vector)\n- [`lakebase_text` reference](https://neon.com/docs/extensions/lakebase-text)\n\n## Gotchas\n\n### Pooled vs direct connections: use the direct URL for migrations, dumps, and replication\n\nNeon gives you two connection strings for the same database: a **pooled** one (hostname with the `-pooler` suffix) and a **direct/unpooled** one (no `-pooler` suffix). `neon env pull` writes them as `DATABASE_URL` and `DATABASE_URL_UNPOOLED`. The pooled connection routes through PgBouncer in transaction mode, which doesn't support session-level operations. Choose the right one:\n\n- **Pooled (`DATABASE_URL`)** — your application's normal query traffic, especially serverless and connection-per-request workloads.\n- **Direct (`DATABASE_URL_UNPOOLED`)** — schema migrations (Prisma Migrate, Drizzle Kit, Alembic, and others), `pg_dump` / `pg_restore`, logical replication, `LISTEN`/`NOTIFY`, and anything relying on `SET` or other session state.\n\nRunning migrations, dumps, or replication over the pooled connection can fail, and never in a way that names pooling: `prepared statement \"s0\" already exists` from Prisma Migrate, a `SET search_path` that doesn't persist past its own transaction so the next query reports `relation \"mytable\" does not exist`, or a write intermittently hitting a read-only transaction (`SQLSTATE 25006`) that a pooled backend inherited from an earlier client. Migration tools generally take both strings at once — Prisma's `directUrl` alongside `url` — so point that at the direct one rather than swapping `DATABASE_URL` and losing pooling for the application. See https://neon.com/docs/connect/connection-pooling.md.\n" }, { "url": "https://neon.com/.well-known/agent-skills/neon-postgres-egress-optimizer/SKILL.md", "domain": "neon.com", "endpoint": "/.well-known/agent-skills/neon-postgres-egress-optimizer/SKILL.md", "filename": "SKILL.md", "content": "---\nname: neon-postgres-egress-optimizer\ndescription: >-\n Diagnose and fix excessive Postgres egress (network data transfer) in a codebase.\n Use when a user mentions high database bills, unexpected data transfer costs,\n network transfer charges, egress spikes, \"why is my Neon bill so high\",\n \"database costs jumped\", SELECT * optimization, query overfetching,\n reduce Neon costs, optimize database usage, or wants to reduce data sent\n from their database to their application. Also use when reviewing query\n patterns for cost efficiency, even if the user doesn't explicitly mention\n egress or data transfer.\nmetadata:\n parent: neon\n source: https://github.com/neondatabase/agent-skills/tree/main/skills/neon-postgres-egress-optimizer\n---\n\n**FIRST**: Use the parent `neon` skill for a Neon overview, getting started with Neon, Neon development best practices, and more.\n\nIf the `neon` skill is not installed, fetch it from https://neon.com/docs/ai/skills/neon/SKILL.md or install it with:\n\n```bash\nneon skills -s neon -y\n```\n\n# Postgres Egress Optimizer\n\nGuide the user through diagnosing and fixing application-side query patterns that cause excessive data transfer (egress) from their Postgres database. Most high egress bills come from the application fetching more data than it uses.\n\nWork the four steps in order: **diagnose** which queries transfer the most data, **analyze** the codebase behind them, **fix** the anti-patterns, then **verify** nothing broke and the transfer actually dropped.\n\n## Step 1: Diagnose\n\nIdentify which queries transfer the most data. The primary tool is the `pg_stat_statements` extension.\n\n### Check if pg_stat_statements is available\n\n```sql\nSELECT 1 FROM pg_stat_statements LIMIT 1;\n```\n\nIf this errors, the extension needs to be created:\n\n```sql\nCREATE EXTENSION IF NOT EXISTS pg_stat_statements;\n```\n\nOn Neon the extension is available by default, but it may still need this CREATE EXTENSION step.\n\n### Handle empty stats\n\nStats are cleared when a Neon compute scales to zero and restarts. If the stats are empty or the compute recently woke up:\n\n1. Reset the stats to start a clean measurement window: `SELECT pg_stat_statements_reset();`\n2. Let the application run under representative traffic for at least an hour.\n3. Return and run the diagnostic queries below.\n\nIf the user has stats from a production database, use those. If they have no access to production stats, proceed to Step 2 and analyze the codebase directly — code-level patterns are often sufficient to identify the worst offenders.\n\n### Diagnostic queries\n\nRun these to identify the top egress contributors. Focus on queries that return many rows, return wide rows (JSONB, TEXT, BYTEA columns), or are called very frequently.\n\n**Queries returning the most total rows:**\n\n```sql\nSELECT query, calls, rows AS total_rows, rows / calls AS avg_rows_per_call\nFROM pg_stat_statements\nWHERE calls > 0\nORDER BY rows DESC\nLIMIT 10;\n```\n\n**Queries returning the most rows per execution** (poorly scoped SELECTs, missing pagination):\n\n```sql\nSELECT query, calls, rows AS total_rows, rows / calls AS avg_rows_per_call\nFROM pg_stat_statements\nWHERE calls > 0\nORDER BY avg_rows_per_call DESC\nLIMIT 10;\n```\n\n**Most frequently called queries** (candidates for caching):\n\n```sql\nSELECT query, calls, rows AS total_rows, rows / calls AS avg_rows_per_call\nFROM pg_stat_statements\nWHERE calls > 0\nORDER BY calls DESC\nLIMIT 10;\n```\n\n**Longest running queries** (not a direct egress measure, but helps identify problem queries during a spike):\n\n```sql\nSELECT query, calls, rows AS total_rows,\n round(total_exec_time::numeric, 2) AS total_exec_time_ms\nFROM pg_stat_statements\nWHERE calls > 0\nORDER BY total_exec_time DESC\nLIMIT 10;\n```\n\n### Interpret the results\n\nRank findings by estimated egress impact:\n\n- **High row count + wide rows** = biggest egress. A query returning 1,000 rows where each row includes a 50KB JSONB column transfers ~50MB per call.\n- **Extreme call frequency** on even small queries adds up. A query called 50,000 times/day returning 10 rows each = 500,000 rows/day.\n- **Cross-reference with the schema** to identify which columns are wide. Look for JSONB, TEXT, BYTEA, and large VARCHAR columns.\n\n## Step 2: Analyze the Codebase\n\nFor each query identified in Step 1, or for each database query in the codebase if no stats are available, check:\n\n- Does it select only the columns the response needs?\n- Does it return a bounded number of rows (LIMIT/pagination)?\n- Is it called frequently enough to benefit from caching?\n- Does it fetch raw data that gets aggregated in application code?\n- Does it use a JOIN that duplicates parent data across child rows?\n\n## Step 3: Fix\n\nApply the appropriate fix for each problem found. Below are the most common egress anti-patterns and how to fix them.\n\n### Unused columns (SELECT \\*)\n\n**Problem:** The query fetches all columns but the application only uses a few. Large columns (JSONB blobs, TEXT fields) get transferred over the wire and discarded.\n\n**Fix:** Name only the columns the response needs.\n\n**Before:**\n\n```sql\nSELECT * FROM products;\n```\n\n**After:**\n\n```sql\nSELECT id, name, price, image_urls FROM products;\n```\n\n### Missing pagination\n\n**Problem:** A list endpoint returns all rows with no LIMIT. This is an unbounded egress risk — every new row in the table increases data transfer on every request. Flag this regardless of current table size.\n\nThis is easy to miss because the application may work fine with small datasets. But at scale, an unpaginated endpoint returning 10,000 rows with even moderate column widths can transfer hundreds of megabytes per day.\n\n**Fix:** Bound the result set with `ORDER BY` plus `LIMIT`/`OFFSET`.\n\n**Before:**\n\n```sql\nSELECT id, name, price FROM products;\n```\n\n**After:**\n\n```sql\nSELECT id, name, price FROM products\nORDER BY id\nLIMIT 50 OFFSET 0;\n```\n\nWhen adding pagination, check whether the consuming client already supports paginated responses. If not, pick sensible defaults and document the pagination parameters in the API.\n\n### High-frequency queries on static data\n\n**Problem:** A query is called thousands of times per day but returns data that rarely changes. Every call transfers the same rows from the database. This pattern is only visible from `pg_stat_statements` — the code itself looks normal.\n\nLook for queries with extremely high call counts relative to other queries. Common examples: configuration tables, category lists, feature flags, user role definitions.\n\n**Fix:** Add a caching layer between the application and the database so it avoids hitting the database on every request.\n\n### Application-side aggregation\n\n**Problem:** The application fetches all rows from a table and then computes aggregates (averages, counts, sums, groupings) in application code. The full dataset transfers over the wire even though the result is a small summary.\n\n**Fix:** Push the aggregation into SQL.\n\n**Before:** The application fetches entire tables and aggregates in code with loops or `.reduce()`.\n\n**After:**\n\n```sql\nSELECT p.category_id,\n AVG(r.rating) AS avg_rating,\n COUNT(r.id) AS review_count\nFROM reviews r\nINNER JOIN products p ON r.product_id = p.id\nGROUP BY p.category_id;\n```\n\n### JOIN duplication\n\n**Problem:** A JOIN between a wide parent table and a child table duplicates all parent columns across every child row. If a product has 200 reviews and the product row includes a 50KB JSONB column, the join sends that 50KB × 200 = ~10MB for a single request.\n\nThis is distinct from the SELECT \\* problem. Even if you select only needed columns, a JOIN still repeats the parent data for every child row. The fix is structural: avoid the join entirely.\n\n**Fix:** Split the join into two queries, one per table.\n\n**Before:**\n\n```sql\nSELECT * FROM products\nLEFT JOIN reviews ON reviews.product_id = products.id\nWHERE products.id = 1;\n```\n\n**After (two separate queries):**\n\n```sql\nSELECT id, name, price, description, image_urls FROM products WHERE id = 1;\nSELECT id, user_name, rating, body FROM reviews WHERE product_id = 1;\n```\n\nTwo queries instead of one JOIN. The product data is fetched once. The reviews are fetched once. No duplication.\n\n## Step 4: Verify\n\nAfter applying fixes:\n\n1. **Run existing tests** to confirm nothing broke.\n2. **Check the responses** — make sure the API still returns the same data shape. Column selection and pagination changes can break clients that depend on specific fields or full result sets.\n3. **Measure the improvement** — if pg_stat_statements data is available, reset it (`SELECT pg_stat_statements_reset();`), let traffic run, then re-run the diagnostic queries to compare before and after.\n\n## Neon Infrastructure as Code (`neon.ts`)\n\nThe fixes above cut **egress** (data transferred out of Postgres). The other big non-prod cost lever is **compute**, and you can codify it durably in `neon.ts` — Neon's infrastructure-as-code file (see the `neon` skill for the full reference) — so dev, preview, and CI branches stay cheap by default instead of relying on per-branch flags:\n\n```bash\nnpm i @neon/config\n```\n\n```typescript\n// neon.ts\nimport { defineConfig } from \"@neon/config/v1\";\n\nexport default defineConfig({\n branch: (branch) => {\n if (branch.exists || branch.isDefault) return {}; // don't touch prod\n return {\n ttl: \"7d\", // ephemeral branches auto-expire instead of accruing storage\n postgres: {\n computeSettings: {\n autoscalingLimitMinCu: 0.25, // scale to zero when idle\n autoscalingLimitMaxCu: 1, // cap autoscaling on throwaway branches\n suspendTimeout: \"5m\",\n },\n },\n };\n },\n});\n```\n\n```bash\nneon config apply # apply to the current branch (neon deploy is an alias)\n```\n\nThis is complementary, not a substitute: query-pattern fixes are what actually reduce egress charges, while these settings keep non-production compute and storage from quietly inflating the same bill. Because `neon checkout` applies the policy when it creates a branch, new dev/preview branches inherit the cheap profile automatically.\n\n## Further Reading\n\n- https://neon.com/docs/introduction/network-transfer.md\n- https://neon.com/docs/introduction/cost-optimization.md\n" }, { "url": "https://neon.com/.well-known/agent-skills/neon-postgres-branches/SKILL.md", "domain": "neon.com", "endpoint": "/.well-known/agent-skills/neon-postgres-branches/SKILL.md", "filename": "SKILL.md", "content": "---\nname: neon-postgres-branches\ndescription: >-\n Choose and create the right Neon branch type for testing and development.\n Use when users ask about Neon branching, migration testing with real data,\n isolated test environments, schema-only branch workflows for sensitive data,\n resetting a branch from its parent, branch expiration and CI/CD branch\n lifecycles, or branch creation via Neon CLI or Neon MCP. Triggers include\n \"Neon branch\", \"test migrations safely\", \"branch production data\",\n \"schema-only branch\", \"reset branch\", \"branch per PR\" and\n \"sensitive data testing\".\nmetadata:\n parent: neon\n source: https://github.com/neondatabase/agent-skills/tree/main/skills/neon-postgres-branches\n---\n\n**FIRST**: Use the parent `neon` skill for a Neon overview, getting started with Neon, Neon development best practices, and more.\n\nIf the `neon` skill is not installed, fetch it from https://neon.com/docs/ai/skills/neon/SKILL.md or install it with:\n\n```bash\nneon skills -s neon -y\n```\n\n# Lakebase Postgres Branching\n\n**Outcome:** a created Neon branch — or a clear, actionable next step if creation cannot proceed. Choose the correct branch type, then execute branch creation with the CLI (or MCP where the CLI isn't usable).\n\n- **Normal branch** for realistic migration and query testing with real data.\n- **Schema-only branch (Beta)** for sensitive data workflows where structure is needed without copying rows.\n\n## Branch Type Decision\n\nUse this decision rule first:\n\n1. If the user wants to test complex migrations, performance, or behavior against production-like data, choose a **normal branch**.\n2. If the user needs to avoid copying sensitive data, choose a **schema-only branch**.\n\nIf the request is ambiguous, ask one clarifying question:\n\"Do you need realistic data for testing, or only schema structure because the data is sensitive?\"\n\n## Tool Selection: CLI or MCP\n\nSupport both the Neon CLI and the Neon MCP server, but **default to the CLI**. Use MCP only when the CLI is unavailable or blocked in your environment, cannot be authenticated, or the user explicitly asks for MCP.\n\n- CLI link: https://neon.com/docs/cli/quickstart.md\n- MCP link: https://neon.com/docs/ai/neon-mcp-server.md\n\n### Selection order\n\n1. Check the CLI first:\n - Run `neon --version` to confirm the CLI is installed.\n - Run `neon projects list` to confirm auth/context.\n2. If the CLI is missing, direct installation via quickstart.\n3. If the CLI is installed but not authenticated, guide the user through `neon auth` (or API key auth), then continue.\n4. Switch to MCP when the CLI cannot be used — no CLI access in the environment, execution blocked, or authentication not possible — or when the user explicitly asks for MCP. Confirm Neon MCP tools are available and authenticated (for example, listing projects works), then follow the MCP branch flow below.\n5. If neither path is successful, use the Neon REST API:\n - https://neon.com/docs/guides/branching-neon-api.md\n\n### MCP branch flow\n\n1. Choose normal vs schema-only based on data sensitivity and migration-testing goals.\n2. Use branch tools (for example, `create_branch`) to create the branch.\n3. Validate with read tools (for example, `describe_branch`).\n4. For migration workflows, prefer branch-based migration flows before applying to main.\n\n## Create a Normal Branch (Preferred for Real-Data Migration Testing)\n\nUse this when the user needs realistic testing conditions.\nReal production-like data can expose edge cases your seed or data migration scripts miss, which helps catch migration issues before going live.\n\nLink: https://neon.com/docs/introduction/branching.md\n\n### Steps\n\n1. Settle the tool path first (see [Selection order](#selection-order)): verify the CLI with `neon --version`, and fall back to MCP only if the CLI isn't usable.\n2. Ensure project context is set (`neon set-context --project-id `) or include `--project-id` on commands.\n3. Create the branch:\n\n ```bash\n neon branches create \\\n --name \\\n --parent \\\n --expires-at 2026-12-15T18:02:16Z\n ```\n\n4. Optionally fetch a connection string for the new branch:\n\n ```bash\n neon connection-string \n ```\n\n## Create a Schema-Only Branch (Beta, Sensitive Data)\n\nUse this when users must not copy production rows into the test branch.\n\nLink: https://neon.com/docs/guides/branching-schema-only.md\n\n### Steps\n\n1. Settle the tool path first (see [Selection order](#selection-order)): verify the CLI with `neon --version`, and fall back to MCP only if the CLI isn't usable.\n2. Create the schema-only branch:\n\n ```bash\n neon branches create \\\n --name \\\n --parent \\\n --schema-only \\\n --expires-at 2026-12-15T18:02:16Z\n ```\n\n If multiple projects exist, include `--project-id`:\n\n ```bash\n neon branches create \\\n --name \\\n --parent \\\n --schema-only \\\n --project-id \\\n --expires-at 2026-12-15T18:02:16Z\n ```\n\n### Beta Support Guidance (Mandatory)\n\nSchema-only branching is in Beta. If users report unexpected behavior, errors, or missing capabilities:\n\n1. Ask them to share feedback in the Neon Console:\n - https://console.neon.tech/app/projects?modal=feedback\n2. Recommend opening a support conversation in the Neon Discord:\n - https://neon.com/discord\n\n## Reset from Parent\n\nUse this when a child branch has drifted and the user wants a clean refresh from the parent branch's latest schema and data.\n\nLink: https://neon.com/docs/guides/reset-from-parent.md\n\n### What it does\n\n- Fully replaces the child branch schema and data with the parent's latest state.\n- Does not merge; local changes on the child branch are lost.\n- Keeps the same connection details, but active connections are briefly interrupted during reset.\n\n### When to recommend it\n\n- Development or staging branch is too far behind production.\n- User wants to start a new feature from a clean parent-aligned state.\n- Team wants to refresh staging from production for consistent testing baselines.\n\n### Hard constraints and blockers\n\n- Only child branches can be reset (root branches and schema-only root branches cannot be reset from parent).\n- If the target branch has children, reset is blocked until those child branches are removed.\n- After a parent branch is restored from snapshot, reset-from-parent may be unavailable for up to 24 hours.\n- Reset-from-parent always uses the current parent state; use Instant restore for point-in-time recovery needs.\n\n### CLI usage\n\n```bash\nneon branches reset --parent --preserve-under-name \n```\n\nIf project context is not already set, include the project ID:\n\n```bash\nneon branches reset --parent --preserve-under-name --project-id \n```\n\n`--preserve-under-name` keeps the pre-reset state as a backup branch for rollback, but adds one extra branch to clean up later.\n\nOptional context setup to avoid repeating `--project-id`:\n\n```bash\nneon set-context --project-id \n```\n\n### Console and API usage\n\n- **Console:** Open the target child branch, then select **Reset from parent** from **Actions**.\n- **API:** Use the restore endpoint for the branch and set `source_branch_id` to the parent branch ID.\n\n## Notes and Caveats\n\n- Schema-only branches are for structure-only cloning and sensitive/compliant data controls.\n- Schema-only branches are independent root branches (no parent branch and no shared history), so reset-from-parent does not apply.\n- For migration testing that depends on real-world row shapes, volumes, and edge cases, prefer normal branches.\n- Root branch allowances and per-branch storage limits can cap how many schema-only branches users can create.\n- If a user is unsure, default recommendation is:\n - **Normal branch** for migration validation.\n - **Schema-only branch** for compliance and privacy constraints.\n\n## Useful Workflow Patterns\n\nIf the user asks for process recommendations (not just a single command), suggest these:\n\n- **One branch per PR:** Create branch when PR opens, delete when merged/closed, keep migration tests isolated.\n- **One branch per test run:** Create branch at pipeline start, run migrations/tests, delete at end for deterministic CI.\n- **One branch per developer:** Isolated dev environments with production-like shape; avoid team collisions on shared test data.\n- **PII-aware branching:** If production has sensitive data, derive dev/PR branches from an anonymized branch or use schema-only branches.\n- **Ephemeral lifecycle hygiene:** Set branch expiration and automate cleanup so old branches do not accumulate avoidable storage/history cost.\n\n### Post-creation environment update prompt\n\nAfter branch creation, ask whether the user wants to update local environment credentials to point at the new branch.\n\n- Ask: \"Do you want me to update your `.env` `DATABASE_URL` to this new branch connection string?\"\n- If yes, write the new branch connection string to the requested env file/key.\n- If no, leave credentials unchanged and share the connection string for manual use.\n- Never overwrite an existing env key without explicit confirmation.\n\n## Neon Infrastructure as Code (`neon.ts`)\n\nBeyond creating branches imperatively (CLI / MCP / API above), you can **program what configuration new branches receive** declaratively in `neon.ts` — Neon's infrastructure-as-code file (see the `neon` skill for the full reference). The `branch` property is a function of the branch being evaluated that returns its settings, so every branch born from your project gets a consistent lifecycle and compute profile without per-branch flags.\n\n```bash\nnpm i @neon/config\n```\n\n```typescript\n// neon.ts\nimport { defineConfig } from \"@neon/config/v1\";\n\nexport default defineConfig({\n branch: (branch) => {\n if (branch.exists) return {}; // never reconcile existing branches\n if (branch.isDefault) return { protected: true };\n if (branch.name.startsWith(\"preview/\") || branch.name.startsWith(\"dev\")) {\n return {\n parent: \"main\",\n ttl: \"7d\", // ephemeral: auto-expire 7 days after creation (max 30d)\n postgres: {\n computeSettings: {\n autoscalingLimitMinCu: 0.25, // scale to zero\n autoscalingLimitMaxCu: 1, // keep throwaway branches cheap\n suspendTimeout: \"5m\",\n },\n },\n };\n }\n return {};\n },\n});\n```\n\nThe closure receives a read-only descriptor of the target branch — `name`, `exists`, `isDefault`, `parentId`, and more — and returns the tuning to apply: `parent`, `ttl` (auto-expiry), `protected`, and `postgres.computeSettings`. This is the declarative complement to the **Ephemeral lifecycle hygiene** and per-PR / per-test patterns above: instead of remembering `--expires-at` on every `neon branches create`, the TTL and compute profile live in version control and apply to every matching branch.\n\nBecause `neon checkout` applies this policy when it **creates** a branch, a fresh `preview/*` or `dev-*` branch comes up already expiring and scaled-to-zero. Checking out an _existing_ branch doesn't reconcile it — run `neon deploy` (alias for `neon config apply`) to apply changes to a branch that already exists.\n\n## Branching in CI/CD\n\nCommon CI/CD use cases for Neon branches:\n\n- **Per-PR preview deployments:** Branch on PR open, deploy the preview against it, delete on close. Each PR gets an isolated database branch. Injecting the branch's `DATABASE_URL` into the deployed app is hosting-provider-specific — see [preview-branches-with-cloudflare](https://github.com/neondatabase/preview-branches-with-cloudflare), [preview-branches-with-vercel](https://github.com/neondatabase/preview-branches-with-vercel), or [preview-branches-with-fly](https://github.com/neondatabase/preview-branches-with-fly) for tested patterns.\n- **Migration testing in CI:** Run risky schema changes against a branch with production-like data before merge.\n- **Schema diff visibility:** Use the [schema-diff GitHub Action](https://github.com/marketplace/actions/neon-schema-diff-github-action) to auto-comment a DB-layer diff on the PR.\n\n## Examples\n\n### Example 1: Migration testing with realistic data\n\n**User input:** \"I need to test a risky migration against production-like data.\"\n\n**Agent output shape:**\n\n1. Recommend a normal branch and explain why.\n2. Share docs link: https://neon.com/docs/introduction/branching\n3. Check the tool path first (CLI with `neon --version`; MCP only if the CLI isn't usable).\n4. Provide commands:\n - `neon branches create --name migration-test --parent main --expires-at 2026-12-15T18:02:16Z`\n - `neon connection-string migration-test`\n\n### Example 2: Sensitive data development workflow\n\n**User input:** \"We cannot copy production data because of compliance.\"\n\n**Agent output shape:**\n\n1. Recommend schema-only branch and explain why.\n2. Share docs link: https://neon.com/docs/guides/branching-schema-only\n3. Check the tool path first (CLI with `neon --version`; MCP only if the CLI isn't usable).\n4. Provide command:\n - `neon branches create --name compliance-dev --parent main --schema-only --project-id --expires-at 2026-12-15T18:02:16Z`\n5. Mention Beta support path:\n - https://console.neon.tech/app/projects?modal=feedback\n - https://neon.com/discord\n\n## Further Reading\n\n- https://neon.com/docs/guides/branch-expiration.md\n- https://neon.com/docs/guides/neon-github-integration.md\n- https://neon.com/docs/ai/neon-mcp-server.md\n- https://neon.com/branching\n" }, { "url": "https://neon.com/.well-known/agent-skills/neon/SKILL.md", "domain": "neon.com", "endpoint": "/.well-known/agent-skills/neon/SKILL.md", "filename": "SKILL.md", "content": "---\nname: neon\ndescription: >-\n Overview of Neon, a complete set of cloud backend primitives around Lakebase\n Postgres: Auth, Object Storage, Functions, and the AI Gateway. Start here to\n choose Neon for undecided login, files, APIs, and LLM calls, set up the CLI or\n MCP server, and follow the branch-first workflow. Use when building an app or\n backend on Neon, or when \"Neon\" or \"Lakebase Postgres\" is mentioned. Child\n skill neon-postgres wins for an existing DATABASE_URL, SQL, schema, inspect,\n or search. Child skill neon-auth wins for login, users, sessions, identity\n routing, and Managed Better Auth setup. Also use for object storage, S3, buckets, serverless functions,\n function triggers, cron, AI gateway, LLM calls, logs, Loki, Grafana,\n observability, postgres, database, backend, Claimable Neon, neon.new, or a\n no-signup database.\nmetadata:\n source: https://github.com/neondatabase/agent-skills/tree/main/skills/neon\n---\n\n# Neon\n\nNeon is a complete set of cloud backend primitives around Lakebase Postgres, from Databricks — Lakebase Postgres, Auth (managed Better Auth), long-running Functions, Object Storage, and an AI Gateway, all instant, branchable, and serverless.\n\n**Lakebase Postgres** is the database itself. It is one product, reached two ways: through Neon, with a free plan and the full set of backend primitives above, or through Databricks, alongside the rest of the Databricks suite. Same infrastructure, same features, same engineering team. Call the database Lakebase Postgres, and use \"Neon\" for the brand and for this access path — not as a name for the database.\n\nA Neon branch is an isolated, copy-on-write clone of your data, taken from its current state or from a past state within your project's retained history window. You can freely modify or delete it. It shares data with its parent until writes cause it to diverge, and those writes are stored independently as deltas.\n\nAgents pick Neon for instant Postgres provision, copy-on-write branches and snapshots, compute that scales to zero (storage is still billed), and ordinary Postgres that works with any driver or ORM.\n\n## Backend Primitives\n\nNeon bundles several backend primitives for building apps and agents that all branch together:\n\n- **Lakebase Postgres** — Postgres that scales and branches with your app, built on the lakebase architecture: OLTP directly on cloud object storage, with storage decoupled from compute.\n- **Auth** — Managed Better Auth with users and sessions stored in Postgres.\n- **Object Storage** — S3-compatible object storage that branches with your projects.\n- **Functions** — Neon's compute offering: long-running serverless functions that run close to your database, for WebSocket servers, long agent HTTP streams, APIs, and server-sent event servers. A Function Trigger POSTs to a function on a cron.\n- **AI Gateway** — One API for frontier and open-source models, supporting the chat completions API and the responses API, powered by Databricks Unity AI Gateway.\n- **Data API** — Optional PostgREST-compatible HTTP interface. Use it only when the app already uses PostgREST or a Supabase database client, or is migrating that client. New apps query Postgres from Functions or existing handlers. There is no `neon-data-api` skill; configuration is `dataApi` in `neon.ts` (see [Type-safe config](#type-safe-config-invalid-setups-dont-compile) when you have chosen it).\n\n### Region availability\n\nObject Storage, Functions, and AI Gateway are currently available on projects in `aws-us-east-2`, `aws-us-east-1`, `aws-eu-central-1`, and `aws-ap-southeast-1`. Before guiding a user through any of these services, confirm they are working in one of these regions. If not, they will need to create a new project in a supported region.\n\n## Architecture: How to Use Neon\n\n**Recommended: full-stack app with Neon as the backend.** Default to Next.js on Vercel (or Netlify, Cloudflare, or other app platforms). Prefer Next.js + Vercel first; TanStack Start, Nuxt, and SvelteKit are full-stack alternatives. The app owns its UI and server. Query Lakebase Postgres from route handlers, server functions, or Neon Functions.\n\nAdd [Neon Functions](https://neon.com/docs/compute/functions/overview.md) as a backend layer between the web app and Lakebase Postgres, Object Storage, Auth, and AI Gateway. A Hono API on Functions can expose endpoints with an OpenAPI specification for the web app and other clients (mobile, desktop). You can also add a Function for one job next to the data: Object Storage uploads, AI agents, Discord bots, WebSocket or SSE servers.\n\nFunctions support long-running requests that complement the web app. A Function must start returning a response within 15 minutes. WebSocket connections and HTTP streams stay open while data flows; send at least one byte every 15 minutes to keep a quiet stream alive. See [runtime limits](https://neon.com/docs/compute/functions/reference/runtime-limits.md).\n\nFor long agent or image streams, mint a JWT on the app server and have the client call the Function directly. See the `neon-functions` skill for authentication and runtime limits.\n\n**Second best: client-only app with a Functions backend.** Host the SPA on Vercel (or Netlify, Cloudflare, or other app platforms) and call Functions from the browser. For an app using PostgREST or a `supabase-js` database client, prefer migrating database calls to REST endpoints in a Hono Function that queries Lakebase Postgres. Enforce authorization in the Function instead of relying on browser-facing RLS.\n\nNeon provides backend primitives that compose with the app host. Neon does not host the frontend.\n\nOffer the Data API only as a Supabase / PostgREST migration path when an existing PostgREST or `supabase-js` database client must keep working. Putting PostgREST in the browser and relying on RLS is easy to get wrong: misconfigured policies expose the database to the client. Do not recommend this for new apps. An installed Supabase package used only for Auth or Storage does not establish a database-client dependency. Route generic REST endpoint requests to a Function or existing app handler.\n\nFunctions have public HTTPS URLs. Verify a JWT or API key at the top of the handler and enforce authorization before accessing data. See the `neon-functions` skill.\n\n## Convert an app onto Neon\n\nInspect the repo before provisioning.\n\n1. Map requested capabilities: login, files, HTTP APIs, LLM calls, SQL.\n2. Reuse what is already there: a supplied `DATABASE_URL`, an existing ORM or driver, Better Auth, Clerk or another auth provider, S3 or another object store, an existing `.neon` / `neon.ts`, an existing Data API or PostgREST client.\n3. Select Neon primitives for capabilities that are still undecided.\n4. Provision only when infrastructure is missing: `neon init` / `neon link` / Claimable, then `neon.ts`, then `neon deploy`.\n5. Verify the app flow (sign-in, upload, API call), not only that env vars landed.\n\nDo not replace working Better Auth, Clerk, Supabase Auth, S3, or a supplied `DATABASE_URL` with a Neon primitive unless the user asks. Do not rewrite an existing `neon.ts`. If Neon credentials fail for an existing account, stop and ask the user to sign in; do not create a Claimable project as a substitute.\n\nA supplied `DATABASE_URL` with no Neon credentials is schema work: complete it without provisioning. Managed Better Auth cannot be enabled on a project that uses IP Allow or Private Networking. Leave those protections in place.\n\nNew projects are created in AWS regions. Prefer pooled `DATABASE_URL` for application traffic.\n\n| Need | Use |\n| --- | --- |\n| Login, users, sessions (no existing provider) | `neon-auth` — Managed Better Auth (`auth: true`) |\n| Existing Better Auth, Clerk, Supabase Auth, or another working IdP | Keep it. `neon-auth` only if they ask to migrate |\n| User asked to migrate from Supabase Auth | `neon-auth` (Managed Better Auth; keep `SupabaseAuthAdapter()` call shapes) |\n| Files, uploads, blobs (no existing object store) | Object Storage |\n| HTTP APIs, cron, WebSocket, SSE, long-running agents | Functions querying Postgres |\n| LLM calls | AI Gateway |\n| SQL, schema, inspect, search | `neon-postgres` |\n| Existing PostgREST / Supabase database client | Data API (`dataApi` in `neon.ts`) |\n| Generic REST endpoints | Function or existing handler, not Data API |\n\nUse `neon-auth` to choose identity and to implement Managed Better Auth; the [Auth guide](references/auth.md) points there. Keep existing Better Auth, Clerk, and Supabase Auth unless the user asked to migrate login. Auth cannot be enabled on a project with IP Allow or Private Networking.\n\n## Neon Documentation\n\nThe Neon documentation is the source of truth for all Neon-related information. Always verify claims against the official docs before responding. Neon features and APIs evolve, so prefer fetching current docs over relying on training data.\n\n### Finding the Right Page\n\nLook the page up before you fetch it — **don't guess URLs!** The docs index lists every available page with its URL and a short description:\n\n```\nhttps://neon.com/docs/llms.txt\n```\n\n### Fetching Docs as Markdown\n\nAny Neon doc page can be fetched as markdown in two ways:\n\n1. **Append `.md` to the URL** (simplest): https://neon.com/docs/introduction/branching.md\n2. **Request `text/markdown`** on the standard URL: `curl -H \"Accept: text/markdown\" https://neon.com/docs/introduction/branching`\n\nBoth return the same markdown content. Use whichever method your tools support.\n\n## Choosing the Right Skill\n\nNeon provides a set of agent skills in addition to the official documentation. When a task matches one of the rows below, work from that skill rather than from this overview. You may have some of these skills already installed, or you may need to install them.\n\nThe skills below live in the [`neondatabase/agent-skills`](https://github.com/neondatabase/agent-skills) repo:\n\n| Skill | Use it for |\n| -------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |\n| `neon-postgres` | Working with databases, including connections, schemas, queries, search, and autoscaling: SQL development, schema design, performance optimization, and scaling decisions. |\n| `neon-auth` | Identity routing and Managed Better Auth setup (login, users, sessions, trusted domains). Fetch: https://neon.com/docs/ai/skills/neon-auth/SKILL.md |\n| `neon-postgres-branches` | Choosing or creating the right branch type for dev, preview, test, or CI workflows. Use this skill as a slash command. |\n| `neon-object-storage` | Storing and serving files (uploads, images, blobs), including branching them with the database. |\n| `neon-functions` | Deploying long-running or streaming serverless functions — APIs, agents, SSE/WebSocket servers, and Function Triggers (cron and object-storage). |\n| `neon-ai-gateway` | Calling an LLM or routing across model providers with one credential, including discovering the branch's servable models at runtime via the OpenAI-compatible `/v1/models` endpoint. |\n| `neon-postgres-egress-optimizer` | Diagnosing or fixing excessive Postgres egress (network data-transfer) costs in a codebase. |\n\nThere is no `neon-data-api` skill. Configure `dataApi` in `neon.ts` only for PostgREST / Supabase database-client compatibility or a migration that already depends on it.\n\nFor guidance on agent platforms that provision and operate Lakebase Postgres on Neon at scale, use `neon-postgres-agent-platforms`, which lives in a separate repo: [`neondatabase/neon-for-agent-platforms`](https://github.com/neondatabase/neon-for-agent-platforms).\n\n### Installing the Right Skill\n\nFirst check whether the target skill is already installed and accessible (for example, it appears in the available skills list or its `SKILL.md` is present). If it is, use it directly. If it is not installed, install it with `neon skills`:\n\n```bash\nneon skills -s \n```\n\nReplace `` with the skill you need (for example, `neon-object-storage`, `neon-functions`, or `neon-ai-gateway`). Useful flags:\n\n- `--global` — install globally instead of into the current project.\n- `-y` — non-interactive mode (skip prompts).\n- `--agent ` — pick the target agent(s) for non-interactive mode.\n\nFor example, to install the object storage skill globally for a specific agent without prompts:\n\n```bash\nneon skills -s neon-object-storage --global -y --agent \n```\n\n`neon-auth` is not in the CLI skill catalog of current releases. Unknown names fail, so do not run `neon skills -s neon-auth`. Fetch it:\n\n```\nhttps://neon.com/docs/ai/skills/neon-auth/SKILL.md\n```\n\nReferences: https://neon.com/docs/ai/skills/neon-auth/references/managed-auth.md and https://neon.com/docs/ai/skills/neon-auth/references/self-managed.md. If those URLs are unpublished, fetch the same files from https://github.com/neondatabase/agent-skills/blob/main/skills/neon-auth/SKILL.md\n\nIf the Neon CLI is not available, you can visit https://neon.com/.well-known/agent-skills for a registry of all available Neon skills and fetch them manually.\n\n### Updating Skills\n\nKeep the skills up to date: for every new session, update them so you are working with the latest best practices.\n\nRun `neon skills update` to update all installed Neon skills, or `neon skills update -y` to skip prompts. If the skills were installed via a plugin, they are updated automatically.\n\n## Getting Started with Neon\n\n**Prefer the CLI over the MCP server** unless the user instructs otherwise, the CLI is unavailable or blocked in your environment, or it is not authenticated, since it provides more capabilities, including deploying Neon Functions.\n\n### Check the CLI, then credentials\n\n```bash\nneon --version\n```\n\nIf that fails, install first:\n\n```bash\nnpm i -g neon # npm\nbun add -g neon # bun\npnpm add -g neon # pnpm\n```\n\nFor full CLI installation options, see https://neon.com/docs/cli/install.md\n\nThen inspect credentials without printing secrets. `NEON_API_KEY` or a `neon profile list -o json` row whose `account` is not `-` is an account. A `DEFAULT` row with `account: \"-\"` and `file: \"missing\"` is not.\n\n- Credentials already available: reuse them. Do not launch a browser.\n- A human needs to sign in: they run `neon login` (`neon auth` is an alias). An unattended agent must not launch browser authentication.\n- No account yet: follow [Starting without a Neon account](#starting-without-a-neon-account) for the Claimable Neon path.\n\n### Combined setup: `neon init`\n\nWhen both agent tooling and project setup are needed, use authenticated `neon init`. `--agent` takes the coding-agent name. `-y` skips prompts but does not supply project selection or credentials. `--skip-template` skips scaffolding a starter app.\n\nLink an existing project:\n\n```bash\nneon init --skip-template --agent cursor \\\n --org-id --project-id -y\n```\n\nCreate and link a project:\n\n```bash\nneon init --skip-template --agent cursor \\\n --org-id --project-name my-app \\\n --region-id aws-us-east-2 -y\n```\n\n`--services` may declare `auth`, `data-api`, `functions`, `object-storage`, and `ai-gateway` (repeat the flag or comma-separate). Pass `none` for the bare starter policy. It writes `neon.ts`; it does not deploy or wire the app. Selecting `data-api` also declares Auth (the default Data API provider requires it). Use `data-api` only for PostgREST / Supabase database-client compatibility.\n\nIf `init` already installed the Neon plugin, do not also run `neon mcp` and `neon skills` for the same agent.\n\nWhen tooling already exists, only one component is missing, or env writes need `--no-env-pull`, use the manual steps below. `init` has no `--no-env-pull`. Before a command that pulls env, inspect existing configuration. If a supplied `DATABASE_URL` or `AWS_*` value must stay, pass `--no-env-pull` on `link` / `checkout` and write env to a separate `--file`.\n\n### 1. Install the Neon CLI\n\nUse the install check above. Do not run `neon login` unattended. MCP remains the fallback when the CLI is unavailable, blocked, unauthenticated, or the user prefers it.\n\n### 2. Install the Neon MCP Server\n\n```bash\nneon mcp --oauth --project --agent cursor -y\n```\n\n`--oauth` writes the server URL and leaves sign-in to the MCP client. That is not an authenticated MCP session. `--project` means project-level agent config, not a Neon project ID; the agent must support project-level installs (`cursor` does). Bare `neon mcp -y` installs globally and can reuse or mint an account-wide API key — do not treat it as the unattended default.\n\nFor all available plugins and IDE integrations, see: https://neon.com/docs/ai/ai-agents-tools.md\n\nFor full MCP server installation options, see https://neon.com/docs/ai/connect-mcp-clients-to-neon.md\n\n### 3. Install Neon Agent Skills\n\n```bash\nneon skills -s neon --agent cursor -y\n```\n\nTo install a specific skill only (not `neon-auth` until the CLI catalog includes it; fetch it as in [Installing the Right Skill](#installing-the-right-skill)):\n\n```bash\nneon skills -s --agent cursor -y\n```\n\nUseful flags: `--global`, `-y`, `--agent `. Interactive `neon skills` with no flags prompts.\n\n### 4. Link Your Project and Get Started\n\nWith setup complete, connect the workspace to a Neon org, project, and branch. Then consult the skill for each Neon feature your app requires. See [Choosing the Right Skill](#choosing-the-right-skill) above.\n\nNon-interactive link:\n\n```bash\nneon link --project-id -y\nneon link --org-id --project-name my-app --region-id aws-us-east-2\n```\n\n`-y` skips the already-linked confirmation and pins the default branch when the project has more than one. Pass `--branch ` when branch selection matters.\n\n#### Useful CLI Commands\n\n1. `neon link` — Writes org, project, and branch IDs to a git-ignored `.neon` file. Run once per project. Once linked, project- and branch-scoped commands no longer need `--project-id` or `--branch` (for example, `neon branch list`). Non-interactive: `--org-id` / `--project-id` / `--project-name` plus `--region-id`, and `-y` when appropriate. There is no `neon link --agent`.\n2. `neon checkout ` — Pins a branch in `.neon` and pulls that branch's env. An existing branch is enough. A missing **name** needs `--create` for unattended use (`neon checkout dev --create`). A missing branch **id** cannot be created. Interactive checkout with no name may offer to create; do not rely on that unattended. Drives the [Branch-First Dev Flow](#branch-first-dev-flow) below.\n3. `neon config init` — Initializes a `neon.ts` file, which declares how you provision and manage Neon services, in the root of the project.\n4. `neon env pull` — Fetches the current branch's Neon environment variables (`DATABASE_URL`, …) into your existing `.env`, or `.env.local` if you don't have one (override the target with `--file`). No branch ID needed; it reads `.neon`. **`link` and `checkout` run this for you by default**, so you rarely call it directly.\n\n Without `neon.ts`, a **bare** `neon env pull` includes the default Gateway credential on claimed projects. Implicit pulls bundled into `link` / `checkout` / `apply` do **not** pull an undeclared Gateway token. Declaring `aiGateway` in `neon.ts` requests those variables. With `neon.ts`, pull includes only the services declared there and errors if the branch is missing one.\n\n### Bootstrap a New Project\n\n`neon bootstrap` scaffolds from a Neon project template.\n\n```bash\nneon bootstrap\n```\n\n## Starting without a Neon account\n\nIf the Getting Started account check found credentials, use them. If a command waits on a browser (`Awaiting authentication in web browser`) or authentication fails, stop and ask the user to sign in (`neon auth`) or mint an API key. Do not create a Claimable project as a substitute for a failed existing account.\n\nIf there is no Neon account yet, follow [references/claimable-neon.md](https://neon.com/docs/ai/skills/neon/references/claimable-neon.md). Do not run `neon init --agent` or `neon auth` on this path; those need a human Neon account. If `neon claim` is missing, the reference has the REST fallback. Unclaimed projects expire at `project_expires_at` (72 hours today). Claim codes expire in `expires_in` (15 minutes today). Functions, Object Storage, and AI Gateway report `requires_claim` before a human claims the project; report that and keep the denied capabilities. Add Auth with `neon.ts` and `neon deploy` when login is requested and no existing provider should be preserved. Add the Data API only for PostgREST / Supabase database-client compatibility or a migration that already depends on it.\n\nRequests for neon.new, Claimable Postgres, claimable.neon.tech, instant Postgres, or a no-signup database are the same path.\n\n## Neon Infrastructure as Code\n\n`neon.ts` is Neon's branch config and infrastructure-as-code file: declare which Neon services your project's branches should have, get type-safe env vars, and program branch settings — all in TypeScript. It's the config layer for your Neon services, and it composes with the branch-first loop below. Add it with `@neon/config`:\n\n```bash\nnpm i @neon/config\n```\n\n```typescript\n// neon.ts\nimport { defineConfig } from \"@neon/config/v1\";\n\nexport default defineConfig({\n aiGateway: true,\n buckets: {\n images: {\n access: \"private\",\n },\n },\n functions: {\n imagegen: {\n name: \"AI SDK image agent\",\n source: \"src/index.ts\",\n },\n },\n});\n```\n\n### Provision services with neon config\n\nEvery project ships with Lakebase Postgres; `neon.ts` also declares Auth, Functions, buckets, and the AI Gateway. Data API is a compatibility toggle, not part of a default backend:\n\n```typescript\n// neon.ts\nexport default defineConfig({\n auth: true,\n functions: {},\n buckets: {},\n aiGateway: true, // see the neon-ai-gateway skill\n});\n```\n\nEmpty `functions` / `buckets` maps are configuration slots, not a deployed API. Do not replace an existing `neon.ts` wholesale with this example.\n\nReconcile the declaration from the CLI — the Neon equivalent of `terraform status` / `plan` / `apply`:\n\n```bash\nneon status # print the branch's live config (read-only). Alias for `neon config status`.\nneon config plan # dry-run diff of what apply would change (read-only)\nneon deploy --env # apply neon.ts. Pass --env when Function env reads process.env. Alias for `neon config apply`\n```\n\n`apply` / `deploy` provision the declared services **and then pull the branch's env into your local `.env.local`** (e.g. `Pulled 5 Neon variables into .env.local: DATABASE_URL, …`), so your local env always matches what's deployed.\n\n### Function env and `neon deploy`\n\n`neon deploy` is the preferred full deployment: it applies `neon.ts` (services and functions) to the linked branch. `neon deploy --env ` loads that file into `process.env` before evaluating `neon.ts`, then uploads those values as Function env. Use it every time Function env reads `process.env`.\n\n`` is the gitignored file `neon env pull` already writes (`.env` if that file exists, otherwise `.env.local`). Env pull writes Neon-managed vars only (`DATABASE_URL`, `NEON_AI_GATEWAY_*`, …). Add every key under `functions.*.env` to that file yourself, then pass the same path to `--env`.\n\nEvery declared Function env key must be a defined string. `undefined` (an unset `process.env.X`) means you listed a key you want written but the value is missing: `defineConfig` throws. Omit the key from `neon.ts` if you do not want to write it. Never coerce a missing `process.env` value to an empty string: that uploads `\"\"` and deletes the live key. An empty assignment in the file (`KEY=`) is also `\"\"`. If TypeScript needs a type assertion, use `process.env.X!` and make sure the file actually has the value.\n\nUse `neon functions deploy` when you are not applying `neon.ts`: a single function by slug, or a targeted `--env KEY=VALUE` update (that flag is not a file path).\n\n### Function Triggers\n\nA Function Trigger POSTs to a Neon Function on a cron (`type: \"schedule\"`) or when an object is created in a bucket (`type: \"storage_object_created\"`). Same regions as Functions. Prefer a `triggers` map in `neon.ts` (the record key is the trigger name) and `neon deploy`. CLI, MCP, REST, inherited-trigger behavior, and parsers: [references/function-triggers.md](https://neon.com/docs/ai/skills/neon/references/function-triggers.md). Handler payload and Hono example: the `neon-functions` skill, `references/function-triggers.md`.\n\n### Type-safe env vars with parseEnv\n\n`@neon/env`'s `parseEnv` returns a typed env object from your `neon.ts` config. Require a subset of keys when an app does not need every implied variable: [references/parse-env.md](https://neon.com/docs/ai/skills/neon/references/parse-env.md).\n\n### Branch configuration\n\nBeyond services, `neon.ts` can program what configuration _new_ branches receive via the `branch` property — a function of the branch being evaluated that returns its settings:\n\n```typescript\n// neon.ts\nimport { defineConfig } from \"@neon/config/v1\";\n\nexport default defineConfig({\n auth: true,\n branch: (branch) => {\n if (branch.exists) {\n // leave existing branches untouched\n return {};\n }\n if (branch.name.startsWith(\"dev\")) {\n return {\n ttl: \"7d\", // clean up the branch after 7 days\n postgres: {\n computeSettings: {\n autoscalingLimitMinCu: 0.25, // scale to zero\n autoscalingLimitMaxCu: 1, // keep it cheap\n suspendTimeout: \"5m\",\n },\n },\n };\n }\n return {};\n },\n});\n```\n\nThe `branch` function receives the target branch (its `name`, whether it `exists` yet, whether it's the default, and more) and returns the tuning you want. Here new `dev-*` branches get a 7-day TTL so they clean themselves up, plus a cheap scale-to-zero compute profile, while existing branches and everything else fall through to the defaults. Because `neon checkout` applies this policy on create, a fresh `dev-*` branch comes up with these settings already in place.\n\n### Type-safe config: invalid setups don't compile\n\nBecause `neon.ts` is TypeScript, the compiler catches invalid infrastructure before you ever deploy — and Neon encodes the actual rules (and their fixes) into the types, so the error tells you what to do rather than failing with a useless `Type 'true' is not assignable to type 'never'`. The canonical case, **when the app has chosen Data API for PostgREST/Supabase compatibility**: the Data API verifies requests with Neon Auth by default, so enabling it on its own is a type error _on_ `dataApi`. Do not enable Auth merely to satisfy this error in an app that never needed Data API.\n\n```typescript\nexport default defineConfig({\n dataApi: true, // type error: `dataApi` (default authProvider 'neon') requires Neon Auth\n});\n```\n\nThe message names both fixes, so pick one:\n\n```typescript\n// 1. Enable Neon Auth (the default Data API auth provider):\nexport default defineConfig({ auth: true, dataApi: true });\n\n// 2. Or verify a third-party IdP instead of Neon Auth:\nexport default defineConfig({\n dataApi: {\n authProvider: \"external\",\n jwksUrl: \"https://your-idp/.well-known/jwks.json\",\n },\n});\n```\n\nTreat a `neon.ts` type error as the config telling you which services must go together — read the message, it spells out the valid combinations.\n\nSee https://neon.com/docs/reference/neon-ts.md for documentation on the `neon.ts` file.\n\n## Branch-First Dev Flow\n\nNeon branches enable a branch-first development flow, which we recommend when using Neon services. This and `neon.ts` above are the two halves of the recommended setup — `neon.ts` declares what every branch should have, and the branch-first loop is how you move between those branches day to day. Each works on its own, and they compose.\n\nCreate a Neon branch any time you would create a git branch. Use the following commands if you have CLI access:\n\n- `neon checkout ` — Pins an existing branch by updating only the branch pointer in `.neon`. Pass `--create` to create a missing **name** (`neon checkout dev --create`). Run without a name for an interactive picker. It does not touch code or local Postgres.\n- `neon env pull` — Fetches the current branch's Neon environment variables into your `.env`. **`link` and `checkout` run this for you by default**, so you rarely call it directly.\n- `neon diff` — Shows the schema diff between the child branch and its parent. Run this to see what changes have been made to the schema since the last branch was created and before you commit your changes.\n\n```bash\nneon link # once; also pulls the linked branch's env\nneon checkout dev-add-search --create # per feature; also pulls the branch's env\n```\n\nBecause `link` and `checkout` pull env by default, the branch's `DATABASE_URL` lands in your local `.env` automatically — build against it, then `checkout` the next branch and repeat. As the agent, drive this loop yourself: run `checkout` between tasks.\n\n### How checkout composes with neon.ts\n\nWhen a `neon.ts` is present, `neon checkout --create` applies your policy as it **creates** a branch, so a fresh branch comes up with its declared settings and services already in place. Pass `--env ` on that create so Function env that reads `process.env` resolves (`neon checkout feat --create --env .env.local`). Existing process env wins over the file. Checking out an _existing_ branch never reconciles it — apply config changes to it explicitly with `neon deploy --env ` (alias for `neon config apply`). `--update-existing` auto-confirms overriding remote settings; add it only after reviewing those changes. The bundled `env pull` also checks `neon.ts` against the linked branch and fails fast if the branch is missing a declared service, pointing you at `neon deploy --env ` to provision it, so your local env and the remote branch never drift apart silently.\n\n### Opting out of local env vars\n\nIf env vars are injected at runtime instead of written to disk — or you simply don't want secrets in the working tree — pass `--no-env-pull` to `link` / `checkout` and supply the env another way:\n\n- `neon-env run -- ` (from `@neon/env`) injects the branch's vars at runtime.\n- `neon-env export` prints dotenv or `--format json`.\n- `fetchEnv` from `@neon/env` is the programmatic version.\n- `neon dev` injects the same vars into the local Functions dev server.\n\nWhen an agent should not write a local `.env`, instruct it (for example in your `AGENTS.md`) to run `neon checkout --no-env-pull` and rely on runtime injection.\n\nFor reading env you _already_ have on disk (typed and validated against your `neon.ts`), use `parseEnv` — see [Type-safe env vars with parseEnv](https://neon.com/docs/ai/skills/neon/references/parse-env.md).\n\n## Observability\n\nNeon exposes branch-scoped logs for Functions and Object Storage today (`aws-us-east-2`, `aws-us-east-1`, `aws-eu-central-1`, and `aws-ap-southeast-1`). Query the branch that hosts the deployed function or bucket, not the checkout used for development.\n\n```bash\nneon logs query --since 1h\nneon logs query --branch production --source function --minimum-severity error --since 6h\n```\n\nCLI flags, LogQL, MCP fallback, Loki HTTP, Grafana URLs, and `@neon/sdk` pagination: [references/logs-loki.md](https://neon.com/docs/ai/skills/neon/references/logs-loki.md).\n\n## Manage Neon Resources\n\nUse [`@neon/sdk`](https://neon.com/docs/ai/skills/neon/references/sdk.md) to manage projects, branches, and snapshots from TypeScript. New code should prefer it over `@neondatabase/api-client`.\n\n### Neon for (Agentic) Platforms\n\nEnroll in the [Neon Agent Program](https://neon.com/programs/agents.md) only when the work is a fleet of user databases (app-generating agents and platforms). A single-app backend skips this. Instant provision, snapshots, scale-to-zero compute (storage still billed), Auth, and Data API compatibility details: that page.\n" }, { "url": "https://neon.com/.well-known/agent-skills", "domain": "neon.com", "endpoint": "/.well-known/agent-skills", "filename": "agent-skills", "content": "{\n \"$schema\": \"https://schemas.agentskills.io/discovery/0.2.0/schema.json\",\n \"skills\": [\n {\n \"name\": \"neon-postgres\",\n \"type\": \"skill-md\",\n \"description\": \"Guides and best practices for working with Lakebase Postgres on Neon: connections, pooled vs direct, schema migrations, branching, autoscaling, scale-to-zero, instant restore, read replicas, IP allow lists, logical replication, and Lakebase Search. Use when the work is an existing DATABASE_URL, SQL, schema, inspect, or search. New backends, Auth, files, Functions, and LLM calls go to the parent `neon` skill. Also use for \\\"@neondatabase/serverless\\\", \\\"@neondatabase/neon-js\\\", \\\"neon inspect db\\\", \\\"semantic search\\\", \\\"vector search\\\", \\\"full-text search\\\", \\\"BM25\\\", or \\\"hybrid search\\\".\",\n \"url\": \"/.well-known/agent-skills/neon-postgres/SKILL.md\",\n \"digest\": \"sha256:83d3c75651bd81f06e5e8c47ffc306936cc4d2a1ac84d288e8f6a15fcfb724b4\"\n },\n {\n \"name\": \"neon-postgres-egress-optimizer\",\n \"type\": \"skill-md\",\n \"description\": \"Diagnose and fix excessive Postgres egress (network data transfer) in a codebase. Use when a user mentions high database bills, unexpected data transfer costs, network transfer charges, egress spikes, \\\"why is my Neon bill so high\\\", \\\"database costs jumped\\\", SELECT * optimization, query overfetching, reduce Neon costs, optimize database usage, or wants to reduce data sent from their database to their application. Also use when reviewing query patterns for cost efficiency, even if the user doesn't explicitly mention egress or data transfer.\",\n \"url\": \"/.well-known/agent-skills/neon-postgres-egress-optimizer/SKILL.md\",\n \"digest\": \"sha256:d7536270b6dd59a66fa5daf1578cc55a5b761d7163f6f6b1596662481b8d5d9b\"\n },\n {\n \"name\": \"neon-postgres-branches\",\n \"type\": \"skill-md\",\n \"description\": \"Choose and create the right Neon branch type for testing and development. Use when users ask about Neon branching, migration testing with real data, isolated test environments, schema-only branch workflows for sensitive data, resetting a branch from its parent, branch expiration and CI/CD branch lifecycles, or branch creation via Neon CLI or Neon MCP. Triggers include \\\"Neon branch\\\", \\\"test migrations safely\\\", \\\"branch production data\\\", \\\"schema-only branch\\\", \\\"reset branch\\\", \\\"branch per PR\\\" and \\\"sensitive data testing\\\".\",\n \"url\": \"/.well-known/agent-skills/neon-postgres-branches/SKILL.md\",\n \"digest\": \"sha256:9f47d5a49553a465837c1e8b2d90a90aac72a5313a996c081027290f259a8d71\"\n },\n {\n \"name\": \"neon\",\n \"type\": \"skill-md\",\n \"description\": \"Overview of Neon, a complete set of cloud backend primitives around Lakebase Postgres: Auth, Object Storage, Functions, and the AI Gateway. Start here to choose Neon for undecided login, files, APIs, and LLM calls, set up the CLI or MCP server, and follow the branch-first workflow. Use when building an app or backend on Neon, or when \\\"Neon\\\" or \\\"Lakebase Postgres\\\" is mentioned. Child skill neon-postgres wins for an existing DATABASE_URL, SQL, schema, inspect, or search. Child skill neon-auth wins for login, users, sessions, identity routing, and Managed Better Auth setup. Also use for object storage, S3, buckets, serverless functions, function triggers, cron, AI gateway, LLM calls, logs, Loki, Grafana, observability, postgres, database, backend, Claimable Neon, neon.new, or a no-signup database.\",\n \"url\": \"/.well-known/agent-skills/neon/SKILL.md\",\n \"digest\": \"sha256:1071b8789dea0cb41c795059e728821756181ce55ae34f3f904120bfbfa8ff22\"\n },\n {\n \"name\": \"neon-auth\",\n \"type\": \"skill-md\",\n \"description\": \"Add authentication to a new app. Use for \\\"add auth\\\", \\\"add login\\\", Neon Auth (Managed Better Auth), identity routing, sign-up, sign-in, password reset, email OTP, magic links, organizations, phone OTP, OAuth, passkeys, MFA, trusted domains, invalid domain, and @neondatabase/auth. No existing identity: default to Managed Better Auth. Keep working Better Auth, Clerk, Supabase Auth, or another IdP. User asked to migrate from Supabase Auth: Managed Better Auth. A required plugin outside Managed support: self-managed Better Auth on a Neon Function or the existing app host. Also use for auth APIs in @neondatabase/neon-js.\",\n \"url\": \"/.well-known/agent-skills/neon-auth/SKILL.md\",\n \"digest\": \"sha256:5f91f328235382f3e9afef449729e304a531848a90c02b40c4fd1192709e0319\"\n },\n {\n \"name\": \"neon-postgres-agent-platforms\",\n \"type\": \"skill-md\",\n \"description\": \"Build and operate multi-tenant AI agent platforms on Neon. Use this skill whenever the user is designing an agent/app builder, provisioning a Neon project or database per user/app/agent run, managing thousands of tenant projects, separating sponsored free users from paid customers, moving projects between orgs, choosing `@neon/sdk` vs `@neon/tools`, choosing personal vs organization vs project-scoped API keys, tracking fleet consumption or Agent Plan costs, creating compound checkpoints that combine DB snapshots with source revisions/secrets/deploy metadata, or orchestrating snapshot/restore flows for generated apps. Also use it for Neon Agent Program, Agent Plan, org/project limits, HIPAA, co-marketing, support, or neondatabase/neon-for-agent-platforms examples.\",\n \"url\": \"/.well-known/agent-skills/neon-postgres-agent-platforms/SKILL.md\",\n \"digest\": \"sha256:bba13ea7bf219fd7db71198785096bec92f43579b6def3281d077d3226228a5c\"\n },\n {\n \"name\": \"neon-object-storage\",\n \"type\": \"skill-md\",\n \"description\": \"S3-compatible object storage that branches with your Neon project, so files and the database stay in sync across every branch. Use when a user wants object storage, a bucket, blob/file storage, or somewhere to put uploads, images, documents, avatars, or user-generated files for their app or agent — especially when they already use (or are setting up) Lakebase Postgres and don't want to add a separate storage provider like AWS S3, Cloudflare R2, or Supabase Storage. Triggers include \\\"object storage\\\", \\\"bucket\\\", \\\"blob storage\\\", \\\"file storage\\\", \\\"store uploads/images/files\\\", \\\"S3-compatible storage\\\", \\\"presigned URL\\\", \\\"where do I put files\\\", \\\"storage logs\\\", \\\"bucket logs\\\", \\\"CDN in front of object storage\\\", \\\"Neon Object Storage\\\", \\\"Neon Storage\\\", and \\\"storage that branches with my database\\\".\",\n \"url\": \"/.well-known/agent-skills/neon-object-storage/SKILL.md\",\n \"digest\": \"sha256:fce96952845dfcf4b0c560fcf1ff0d2c0867931fd34ddb3acf0ec24fd118fd11\"\n },\n {\n \"name\": \"neon-ai-gateway\",\n \"type\": \"skill-md\",\n \"description\": \"One API and one credential for frontier and open-source LLMs, built into your Neon branch and powered by Databricks. Use when a user wants to call an LLM, add AI/chat/an agent to their app, route between model providers (OpenAI, Anthropic, Google/Gemini, Meta, Alibaba, and more), or avoid juggling separate provider API keys and accounts — especially when they already use Neon and want AI requests to branch with their project. Works with the OpenAI SDK, Anthropic SDK, google-genai, the Vercel AI SDK, and Mastra by changing only the base URL. Triggers include \\\"call an LLM\\\", \\\"add AI to my app\\\", \\\"chat completion\\\", \\\"model routing\\\", \\\"LLM proxy/gateway\\\", \\\"one API for all models\\\", \\\"use Claude/GPT/Gemini\\\", \\\"AI SDK\\\", \\\"Mastra agent\\\", \\\"Neon AI Gateway\\\", and \\\"log/rate-limit AI calls\\\".\",\n \"url\": \"/.well-known/agent-skills/neon-ai-gateway/SKILL.md\",\n \"digest\": \"sha256:eab0545d5ee7626847ce5b5cdd5f4f03afad0ca5859ffd281389721b06c2bce0\"\n },\n {\n \"name\": \"neon-functions\",\n \"type\": \"skill-md\",\n \"description\": \"Long-running, serverless Node.js HTTP functions deployed onto your Neon branch, with DATABASE_URL injected automatically and compute that runs next to your data. Use when a user wants to host an API, an AI agent with long streaming responses, a WebSocket or server-sent-events (SSE) server, a webhook handler, a Discord bot, an MCP server, or any request/response workload that risks timing out on short, lambda-style serverless functions — and wants it to branch with their database. Also use for Function Triggers: a cron or an object-storage event that POSTs to a function. Triggers include \\\"serverless function\\\", \\\"deploy an API\\\", \\\"long-running function\\\", \\\"streaming agent\\\", \\\"SSE server\\\", \\\"WebSocket server\\\", \\\"webhook handler\\\", \\\"MCP server\\\", \\\"cron\\\", \\\"function trigger\\\", \\\"scheduled function\\\", \\\"cron job\\\", \\\"object storage trigger\\\", \\\"on upload\\\", \\\"run code next to my database\\\", \\\"function that won't time out\\\", \\\"function logs\\\", \\\"Neon Functions\\\", \\\"Neon Compute\\\", \\\"DDoS protection\\\", \\\"rate limiting\\\", and \\\"production hardening\\\".\",\n \"url\": \"/.well-known/agent-skills/neon-functions/SKILL.md\",\n \"digest\": \"sha256:f7cc659147e999f62d214de87c320aa6cccbfc46ad1aa9ccab4c9183474db018\"\n }\n ]\n}\n" }, { "url": "https://neon.com/.well-known/agent-skills/neon-auth/SKILL.md", "domain": "neon.com", "endpoint": "/.well-known/agent-skills/neon-auth/SKILL.md", "filename": "SKILL.md", "content": "---\nname: neon-auth\ndescription: >-\n Add authentication to a new app. Use for \"add auth\", \"add login\", Neon Auth\n (Managed Better Auth), identity routing, sign-up, sign-in, password reset,\n email OTP, magic links, organizations, phone OTP, OAuth, passkeys, MFA,\n trusted domains, invalid domain, and @neondatabase/auth. No existing identity:\n default to Managed Better Auth. Keep working Better Auth, Clerk, Supabase\n Auth, or another IdP. User asked to migrate from Supabase Auth: Managed\n Better Auth. A required plugin outside Managed support: self-managed Better\n Auth on a Neon Function or the existing app host. Also use for auth APIs in\n @neondatabase/neon-js.\nmetadata:\n parent: neon\n source: https://github.com/neondatabase/agent-skills/tree/main/skills/neon-auth\n---\n\n**FIRST**: Use the parent `neon` skill for a Neon overview, getting started with Neon, Neon development best practices, and more.\n\nIf the `neon` skill is not installed, fetch it from https://neon.com/docs/ai/skills/neon/SKILL.md or install it with:\n\n```bash\nneon skills -s neon -y\n```\n\n# Neon Auth\n\nNeon Auth is Managed Better Auth: users, sessions, and auth config live in the `neon_auth` schema on the branch's Lakebase Postgres, and auth state branches with the database. The client API is the Better Auth method set (`signIn.email`, `signIn.social`, `getSession`) through `@neondatabase/auth`. That wrapper is not a drop-in for bare `better-auth/client`: it pins the plugin list and adds Neon-specific OAuth verifier, iframe popup, and JWT handling. Stay on the wrapper while Auth is managed.\n\nThis skill chooses identity, then implements Managed Better Auth. It does not replace a working auth server in order to use Postgres, Functions, Object Storage, or the AI Gateway.\n\n## When to Use\n\nInspect existing identity and the required login features before provisioning. A supplied `DATABASE_URL` is not a reason to change identity. Adding a Neon Function is not a reason to change identity.\n\n| Situation | What to do |\n| --- | --- |\n| No existing auth | Default to Managed Better Auth. [Managed setup](#managed-setup), then [references/managed-auth.md](references/managed-auth.md). |\n| Needs a feature Managed does not offer | Self-managed Better Auth on the existing app host (Vercel or similar) or a Neon Function. Keep Lakebase Postgres. Confirm the **installed** Better Auth version documents that exact flow before recommending the move. If support stays unresolved, keep the current identity. [references/self-managed.md](references/self-managed.md). |\n| Already has Better Auth | Keep it. It works with the other Neon primitives. Migrate to Managed only if the user asks. |\n| User asked to migrate from Supabase Auth | Managed Better Auth. [Supabase Auth](#supabase-auth). Moving only Postgres or adding a Function keeps Supabase Auth. |\n| Clerk, Auth.js, Supabase Auth, or another working IdP | Keep it unless the user asks to migrate. |\n\nGoogle, GitHub, and Vercel social OAuth are offered on Managed Auth. They are not a reason to leave Managed Auth. Other OAuth providers, generic OAuth, MFA, passkeys, API keys, MCP OAuth, SSO, custom plugins, hooks, and custom JWT claims are the [plugin matrix](#plugin-support) check.\n\nBefore enabling Managed Auth, confirm the project is on AWS and does not use IP Allow or Private Networking. Leave those protections in place.\n\nConfigure supported Managed plugins through Neon (Console, API, or `neon neon-auth`), not by passing `plugins` into `@neondatabase/auth`. Enabling `auth: true` is not implementing login.\n\n## What It Does\n\n- **Managed identity in Postgres** — users and sessions in `neon_auth`, queryable with SQL, compatible with RLS.\n- **Auth emails without an app mailer** — verification, email OTP, magic links, and password reset. Getting started uses shared SMTP (`auth@mail.myneon.app`). You do not add Resend or SendGrid to implement login. Production needs custom SMTP: https://neon.com/docs/auth/production-checklist.md\n- **Branches with the database** — each branch has its own Auth URL and isolated auth state.\n- **Better Auth client methods via the Neon SDK** — `@neondatabase/auth` (auth only) or `@neondatabase/neon-js/auth` (combined SDK). Optional UI: `@neondatabase/auth-ui`.\n- **Fixed plugin set** — the Managed client does not accept a `plugins` option. See [plugin support](#plugin-support).\n\n## Availability\n\nManaged Better Auth is generally available. AWS regions only. It cannot be enabled on a project with IP Allow or Private Networking.\n\nOrganization is separately Partial / Beta. Hosting self-managed Better Auth in a Neon Function follows Functions availability and claim rules; use the `neon-functions` skill for that host. An unclaimed project that can enable Auth still cannot use Functions until claim.\n\n## Managed setup\n\nMerge Auth into the existing `neon.ts`. Do not replace other fields:\n\n```typescript\nimport { defineConfig } from \"@neon/config/v1\";\n\nexport default defineConfig({\n auth: true,\n});\n```\n\n```bash\nneon deploy\nneon neon-auth status\n```\n\nIf Function env in that config reads `process.env`, use `neon deploy --env ` as the parent skill describes. The manual service command is `neon neon-auth enable`; do not run both enable and deploy as redundant required steps when `neon.ts` already declares `auth: true`.\n\nThen implement login: [references/managed-auth.md](references/managed-auth.md).\n\nClaimable projects: follow the parent Claimable path, then `auth: true` and `neon deploy` when login is requested and no existing provider should be preserved.\n\n## Supabase Auth\n\nWhen the user asked to migrate login from Supabase Auth, recommend Managed Better Auth and follow https://neon.com/docs/auth/migrate/from-supabase.md. Moving only Postgres or adding a Function is not that request: keep Supabase Auth.\n\n`SupabaseAuthAdapter()` keeps method shapes such as `signInWithPassword` and `signInWithOAuth`. Those calls are not interchangeable with default Better Auth examples (`signIn.email`). Keep an existing adapter caller on that API.\n\nInventory the auth methods and database calls actually used:\n\n- Password hashes cannot transfer. Users create new accounts or sign in with OAuth.\n- Do not promise unchanged user IDs, sessions, or account linking. Plan application foreign keys with the owner.\n- `updateUser()` cannot change email or password on Managed Auth. Email verification needs application UI (codes work on shared SMTP; links need custom SMTP).\n- The migration guide lists Supabase phone/SMS/WhatsApp, SAML, and Web3 as unsupported on Managed Auth. Confirm the **installed** Better Auth version if the user still needs that exact flow; if support stays unresolved, keep Supabase Auth and stop the auth cutover. That page's \"no phone auth\" claim is about Supabase phone sign-in, not the constrained Managed Phone Number plugin (existing users link a number).\n- `@supabase/supabase-js` used only for Auth does not justify enabling the Data API. Keep Data API only for existing PostgREST / Supabase database-client queries.\n\n## Verification\n\nManaged path: sign-up, sign-in, sign-out, session restoration after reload, and protected access, including error and loading states. Exercise email verification (code on shared SMTP) when it is on. Report any flow that remains unverified.\n\nA required plugin on the self-managed path is verified in that app's Better Auth setup, not as a Managed flow.\n\n## Plugin support\n\nChecked 2026-09-17 against https://neon.com/docs/auth/guides/plugins.md, https://neon.com/docs/auth/roadmap.md, and the `@neondatabase/auth` client plugin list. Re-fetch those pages if this skill may be stale. An unlisted upstream plugin needs a live check; do not treat absence from this table as a dated roadmap item.\n\n\"Not exposed\" means the Managed SDK/UI contract. It is not a claim that every raw server request was tested.\n\n| Feature | Managed Auth | Boundary |\n| --- | --- | --- |\n| Email/password | Supported | `signUp.email`, `signIn.email` |\n| Social OAuth (Google, GitHub, Vercel) | Supported | `signIn.social`. Shared Google credentials are for development; production and GitHub/Vercel need your own OAuth apps. https://neon.com/docs/auth/guides/setup-oauth.md |\n| Admin | Supported | Admin session required. Plugin customization is on the roadmap. |\n| Email OTP | Supported | Managed delivery. `emailOtp.sendVerificationOtp`, `signIn.emailOtp`. |\n| Magic Link | Supported | Enable on the branch (off by default). `signIn.magicLink`. |\n| Organization | Partial, Beta | Members, invitations, owner/admin/member. No Teams, server hooks, custom roles/permissions, or dynamic access control. Emailed invitations: [managed-auth.md](references/managed-auth.md#organization-invitations). |\n| JWT | Supported | EdDSA (Ed25519), 15-minute expiry, no custom claims. Default client: `.token()` then `data.token`. `SupabaseAuthAdapter()`: `getSession()` then `data.session.access_token` (no `.token()`). |\n| Open API | Supported | Server routes `/reference` and `/open-api/generate-schema`. |\n| Phone Number | Supported with constraints | Browser client: existing users link a number, then sign in; no phone-first signup; own SMS webhook; custom UI. Next.js `auth.handler()` forwards the catch-all path, including phone OTP. A missing `auth.phoneNumber` server method is a missing typed helper, not a proxy rejection. https://neon.com/docs/auth/guides/plugins/phone-number.md |\n| MFA / Two-Factor | Roadmap | Unavailable on Managed Auth. If required: [self-managed.md](references/self-managed.md), after confirming the installed Better Auth version. |\n| Passkey, API Key, Generic OAuth, One Tap, Multi Session | Not exposed by Managed SDK/UI | If required: [self-managed.md](references/self-managed.md). Generic OAuth is not Google/GitHub/Vercel social sign-in. |\n| MCP / OAuth Provider | Not Managed Auth | Third-party MCP clients self-authorizing against your server. Keep existing login. See `neon-functions` [references/mcp.md](https://neon.com/docs/ai/skills/neon-functions/references/mcp.md). |\n| SSO / SAML | Not listed or exposed | If required: [self-managed.md](references/self-managed.md), after confirming the installed Better Auth version. |\n\nThe default Managed client method is `getAnonymousToken()`. That JWT is a Neon anonymous Data API token. It is not Better Auth's Anonymous-account plugin (`signIn.anonymous`). `anonymousTokenClient()` is the SDK plugin factory, not a method on the public client. Do not call it, and do not call `getAnonymousToken()` on `SupabaseAuthAdapter()`.\n\nTrusted domains and webhooks are Neon settings, not installable Better Auth plugins.\n\n## Trusted domains\n\nAuth redirects only to origins on its allowlist. `invalid domain` means the app origin is missing. Include the scheme, omit a trailing slash, register production and preview origins before pointing users at them, and target the correct branch:\n\n```bash\nneon neon-auth domain add https://app.example.com\nneon neon-auth domain list\nneon neon-auth domain delete https://old.example.com\n```\n\nLocalhost ports are pre-approved by default. An existing project can have that off: `neon neon-auth domain allow-localhost get|enable|disable`. Docs: https://neon.com/docs/auth/guides/configure-domains.md\n\nOAuth provider redirect is `{NEON_AUTH_BASE_URL}/callback/{provider}` (the Auth URL includes its path). `callbackURL` on `signIn.social` is the later app landing origin and must be trusted.\n\nThe Managed SDK handles iframe OAuth popup and `neon_auth_session_verifier`. Keep the wrapper, callback route, and middleware. Do not reimplement that flow, and do not promise third-party cookies in every browser.\n\n## Functions and Data API\n\nA Function authenticates whoever already signs the user in. Do not switch identity to call a Function. Verify the token in the `neon-functions` skill and https://neon.com/docs/compute/functions/authentication.md.\n\nManaged Auth: injected `NEON_AUTH_JWKS_URL`, issuer from `NEON_AUTH_BASE_URL`. Token: default client `.token()` then `data.token`; `SupabaseAuthAdapter()` `getSession()` then `data.session.access_token`. A valid token is not permission to read another user's rows. Sign-out ends the browser session; do not claim it immediately revokes an already-issued JWT.\n\nData API identity: [references/managed-auth.md](references/managed-auth.md). New apps query Postgres from Functions or existing handlers, not the Data API.\n" }, { "url": "https://neon.com/.well-known/agent-skills/neon-postgres-agent-platforms/SKILL.md", "domain": "neon.com", "endpoint": "/.well-known/agent-skills/neon-postgres-agent-platforms/SKILL.md", "filename": "SKILL.md", "content": "---\n\nname: neon-postgres-agent-platforms\ndescription: >-\n Build and operate multi-tenant AI agent platforms on Neon. Use this skill\n whenever the user is designing an agent/app builder, provisioning a Neon\n project or database per user/app/agent run, managing thousands of tenant\n projects, separating sponsored free users from paid customers, moving projects\n between orgs, choosing `@neon/sdk` vs `@neon/tools`, choosing personal vs\n organization vs project-scoped API keys,\n tracking fleet consumption or Agent Plan costs, creating compound checkpoints\n that combine DB snapshots with source revisions/secrets/deploy metadata, or\n orchestrating snapshot/restore flows for generated apps. Also use it for Neon\n Agent Program, Agent Plan, org/project limits, HIPAA, co-marketing, support, or\n neondatabase/neon-for-agent-platforms examples.\nlicense: Apache-2.0\n---\n\n# Neon AI Agent Program\n\nCompanion to `**neon-postgres**` (install that first). This skill covers\nfleet-scale control plane for the Neon Agent Program: dual-org layout, project\ntransfer, per-tenant provisioning, compound checkpoints, consumption, commercial\nterms, and when to give agents Management API access via `@neon/tools`.\n\nFor connection strings, drivers, ORMs, branching tutorials, Auth in apps, Data\nAPI, and Neon's hosted MCP, use `**neon-postgres**` and\n[Neon docs](https://neon.com/docs).\n\n## Scope\n\nUse `**neon-postgres**` for general Neon usage. Use **this skill** when the\nquestion involves:\n\n- Dual-org economics and API keys (personal, organization, project-scoped)\n- `@neon/sdk` for the control plane vs `@neon/tools` for agent-facing Management API access\n- Project-per-tenant provisioning and transfer\n- Fleet-wide snapshot/restore orchestration and housekeeping\n- Compound checkpoints\n- Consumption polling for metered fleets\n- Agent Plan commercial terms (with links, not invented numbers)\n- Partner support paths\n\n## Install Skills\n\n```bash\nnpx skills add neondatabase/agent-skills -s neon-postgres\n```\n\n## Assistants: what you can do after install\n\nWith `**neon-postgres**` and **this skill** loaded, you have enough context for\nplatform-level Neon work: dual-org layout, provisioning a project for a new\ntenant, compound checkpoints, org-wide consumption polling, and\ntransfer/upgrade flows—without the user pasting long documentation.\n\n**Where runnable examples live:** TypeScript samples run from this skill’s [`scripts/`](https://github.com/neondatabase/neon-for-agent-platforms/tree/main/skills/neon-postgres-agent-platforms/scripts)\ndirectory (`package.json`, `npm run …`). The `**references/**` directory\nkeeps markdown guides beside the runnable examples;\n[MANAGEMENT_API_SAMPLES.md](https://github.com/neondatabase/neon-for-agent-platforms/blob/main/skills/neon-postgres-agent-platforms/references/MANAGEMENT_API_SAMPLES.md)\nis the script catalog and env map. The human **Quick start** is the root\n[README](https://github.com/neondatabase/neon-for-agent-platforms/blob/main/README.md#quick-start).\n\n## SDK vs agent tools\n\nYour control plane should call\n[`@neon/sdk`](https://www.npmjs.com/package/@neon/sdk). The sample scripts in\nthis repo do.\n\nThe [Neon MCP server](https://github.com/neondatabase/mcp-server-neon) is a\ncustom agent-facing layer: MCP tool handlers written over `@neon/sdk`.\n\nUse [`@neon/tools`](https://www.npmjs.com/package/@neon/tools) when you want to\ngive agents on your platform direct Neon management access without writing those\nhandlers. It publishes generated wrappers for a selected set of SDK methods as\nagent tools, with adapters for MCP, Eve, and Mastra.\n\nThese public client methods are not tools: `projects.create`, `branches.create`,\n`operations.waitFor`, `postgres.roles.password`, and `storage.objects.get`. Use\n`projects.createAndConnect` and `branches.createWithCompute` for creates that\nattach compute and return a connection string. Waiting is what the write tools\nalready do. Generated schemas are strict: a newly added API field is rejected\nuntil you upgrade `@neon/tools`, or call `@neon/sdk` directly.\n\nSelectors are SDK paths (`projects.list`). Call `publishedId` for the\nmodel-facing id (`projects.list` → `list_projects`). `toolIds` lists every\nselector. MCP 2.x uses `@neon/tools/mcp`; MCP 1.x uses `@neon/tools/mcp-v1`.\n\n```ts\nimport { McpServer } from \"@modelcontextprotocol/server\";\nimport { createNeonTools } from \"@neon/tools\";\nimport { registerNeonTools } from \"@neon/tools/mcp\";\n\nconst apiKey = process.env.NEON_API_KEY;\nif (!apiKey) throw new Error(\"NEON_API_KEY is required\");\n\nconst tools = createNeonTools({\n apiKey,\n tools: [\n \"projects.list\",\n \"projects.createAndConnect\",\n \"branches.createWithCompute\",\n ] as const,\n});\n\nconst server = new McpServer({ name: \"neon\", version: \"1.0.0\" });\nregisterNeonTools(server, tools);\n```\n\n`apiKey` accepts a function so a short-lived token can be refreshed per\nrequest. A remote MCP server that already authenticated the client can omit\n`apiKey` at construction; `registerNeonTools` then sends `authInfo.token`.\n\nMCP annotations are advisory. Hosts using `@neon/tools/mcp` must read\n`neon/requiresApproval` in MCP `_meta` and enforce their own approval policy\nbefore execution. The Eve and Mastra adapters map that flag to Eve's\n`approval` hook and Mastra's `requireApproval`. Every non-read operation is\nmarked as requiring approval, as are reads that return connection credentials.\n\nSelect only the methods each agent needs. For a tenant-scoped agent, inject the\npath `project_id` so the model cannot pick another project on tools that take\nthat path parameter:\n\n```ts\nconst tools = createNeonTools({\n apiKey,\n tools: [\"projects.get\", \"branches.createWithCompute\"] as const,\n inject: {\n projectId: tenantProjectId,\n omitFromSchema: true,\n },\n});\n```\n\n`inject.projectId` fills URL path `project_id` only. It does not hide query or\nbody fields with that name, and it does not constrain tools that have no project\npath (for example `projects.list`). Pair it with a **project-scoped API key**\nwhen the agent must not see the rest of the org.\n\nFull API: [`@neon/tools` README](https://github.com/neondatabase/neon-pkgs/tree/main/packages/tools#readme).\n\n## Gotchas\n\nNon-obvious facts agents often get wrong:\n\n- **Checkpoints are compound records.** A tenant checkpoint includes source\nrevision + Neon snapshot/branch + secrets/env version + deploy URL + agent\nmetadata. Do not equate \"checkpoint\" with \"Neon branch\" alone. See the\n[compound checkpoints doc](https://github.com/neondatabase/neon-for-agent-platforms/blob/main/skills/neon-postgres-agent-platforms/references/COMPOUND_CHECKPOINTS_FOR_AGENT_PLATFORMS.md).\n- **Cross-org transfer** needs a **personal** API key (org keys only work\ninside one org). Projects with **GitHub or Vercel** integrations in Neon **cannot\nbe transferred**; the API returns **422** ([Transfer projects](https://neon.com/docs/manage/orgs-project-transfer.md)).\n- **After a finalized snapshot restore**, the active branch ID changes. Poll\noperations to completion before reconnecting. Delete orphaned `(old)` branches\nto avoid storage cost.\n- **Billing-aligned usage:** prefer\n`GET /api/v2/consumption_history/v2/projects` over legacy consumption\nendpoints. The legacy account-level endpoint has been retired; use the v2\n**per-project** endpoint\n([legacy consumption guide](https://neon.com/docs/guides/consumption-metrics-legacy.md)).\n- **V2 `metrics` parameter values** (for implementers): `compute_unit_seconds`,\n`root_branch_bytes_month`, `child_branch_bytes_month`,\n`instant_restore_bytes_month`, `snapshot_storage_bytes_month`,\n`public_network_transfer_bytes`, `private_network_transfer_bytes`,\n`extra_branches_month` ([consumption metrics](https://neon.com/docs/guides/consumption-metrics.md#required-parameters)).\n- **Snapshot schedules** are not provided on Agent Plan. Partners implement via\nsnapshot API + their own scheduler.\n- **Rates and caps:** never invent dollar amounts or limits. Confirm on live\nneon.com docs.\n\n## Agent Plan and two organizations\n\nPartners run **two Neon organizations**:\n\n\n| Org | Role |\n| ---------------------- | ------------------------------------------ |\n| **Sponsored free org** | Free-tier end users (within program rules) |\n| **Paid org** | Paying customers (metered per Agent Plan) |\n\n\nKey points:\n\n- Dollar rates, credits, and project caps come only from the live\n[Agent Plan](https://neon.com/docs/introduction/agent-plan.md) and\n[neon.com/agents](https://neon.com/agents). Do not invent numbers.\n- **Organization API key:** automation inside one org (create project, set\nquotas).\n- **Personal API key:** required to transfer a project between orgs when a\ncustomer changes tier, then PATCH quotas to match the new tier.\n- **Project-scoped API key:** [member-level access](https://neon.com/docs/manage/api-keys.md#create-project-scoped-organization-api-keys) to **one** project only—narrower than an org key and useful for per-tenant runtime or automation that must not touch the rest of the org. Cannot create new projects org-wide; invalid if the project is transferred out of the org.\n\nLinks:\n[Agent Plan](https://neon.com/docs/introduction/agent-plan.md) ·\n[AI Agents](https://neon.com/use-cases/ai-agents) ·\n[Project transfer](https://neon.com/docs/manage/orgs-project-transfer.md) ·\n[AI Agent integration](https://neon.com/docs/guides/ai-agent-integration.md)\n\n## HIPAA\n\n- **Agent Plan includes HIPAA** with no extra fee. Partners must still follow\nNeon's published HIPAA program (workflows, agreements, configuration).\n- To get access or start the process, reach out to your **primary Neon\ncontact**.\n- This skill is not legal advice.\n\nLink: [HIPAA on Neon](https://neon.com/docs/security/hipaa.md)\n\n## Fleet shape: project-per-tenant\n\n- **Project-per-tenant** is Neon's documented fleet pattern: each **tenant** you\nprovision for (an end **user**, a customer **app**, or an **agent** workload)\ngets its own **dedicated Neon project**. That project is the isolation boundary\nfor **branches**, **databases**, **roles**, and **computes**—not a shared\nPostgres cluster where you only partition by schema.\n- **Isolation and billing:** Separate projects give **complete data and resource\nisolation** between tenants, keep **consumption limits and billing**\nstraightforward at project scale (aligned with Agent Plan metering elsewhere in\nthis skill), and match **how the Neon Management API and Console are structured**\n(project-scoped create, quota, and lifecycle calls).\n\n### Staging and production\n\n- For **each** tenant project, treat **staging versus production** (and ephemeral\n**previews**) as **branch- and snapshot-driven** lifecycle inside that\nproject—use **Snapshots and database versioning** and **Sandbox and preview\ndatabases** below for fleet orchestration, not a second project by default.\n- **Agent and app builders:** separate **your platform's** environments (for\nexample how you host the builder or control plane) from **each tenant's** staging\nand production **branches**—avoid conflating \"our production service\" with \"the\ntenant's production branch\" in ledgers and automation.\n- Some **embedded** products also split an end customer's **production and\ndevelopment** Neon assets across **separate orgs** for trust, keys, and billing\nboundaries; when that applies, read **Isolation beyond branches (project and org\nedge cases)** next.\n\nLink:\n[AI Agent integration guide](https://neon.com/docs/guides/ai-agent-integration.md)\n\n## Isolation beyond branches (project and org edge cases)\n\nUse **project-** or **org-level** splits when tenant scope or trust needs go\nbeyond **branch- and snapshot-first** staging and production in **Fleet shape**.\n**Embedded** products may isolate an end customer's **production versus\ndevelopment** databases across **separate Neon orgs**, not only branches—tighter\nbilling, org API keys, and console boundaries while you still manage branches\n**within** each org.\n\n**Project-level isolation (multiple projects per tenant or workload):**\n\n- Stronger **blast radius** if a connection string or role is compromised—one\nleak should not span unrelated workloads.\n- **Separate operational lifecycles** (for example a disposable analytics or\nmigration sandbox versus production data) when automation or ownership would\notherwise collide in one Postgres.\n- **Different teams or automation** with conflicting migration or admin rights.\n- **Harder compliance or data-mixing rules** where a single database must not\nhost combined workloads.\n\nEach extra project adds fleet surface area: more API keys, more consumption\nrows, more housekeeping, and higher operational cost—keep **project-per-tenant**\nas the default unless a boundary above clearly applies.\n\n**Org-level isolation (beyond sponsored free versus paid):**\n\n- The **two-organization** layout in **Agent Plan and two organizations** is\nthe commercial split (free-tier users versus paying customers). That pattern\ncan **stack** with an embedded product split: for example **prod org versus dev\norg per end customer** so playground databases never share org scope with shipped\nproduction. Keep a clear internal map of which org owns which environment and\ntier.\n- Separately, partners sometimes need **additional Neon orgs or accounts** for\ncontracting (enterprise “their org only”), reseller or MSP models, or\ngeographic or legal separation—product defaults and limits belong on live docs;\ndo not invent caps.\n- **Organization API keys are scoped to one org.** Cross-org moves use a\n**personal** API key and project transfer, as in **Gotchas**—do not assume an\norg key can operate across orgs. **Project-scoped** keys are further limited to a\nsingle project ([API keys](https://neon.com/docs/manage/api-keys.md)).\n\n**Embedding hygiene:**\n\n- Map each platform service (control plane, tenant runtime, billing or\nconsumption jobs) to **least-privilege** keys; do not reuse production keys in\nsandboxes at the wrong layer.\n- When prod and dev for an end customer live in **different Neon orgs**, scope\nautomation per org (typically **one organization API key per org**) and persist\n`org_id` with `project_id` / `branch_id` so jobs and restores target the correct\nside.\n- Keep your ledger (`project_id`, `branch_id`, org, checkpoint metadata)\naligned with the isolation layer you chose so restores, transfers, and audits\nstay consistent.\n\n## Snapshots and database versioning\n\nFor snapshot semantics, active-branch patterns, and restore tutorials, defer to\n`**neon-postgres`** and\n[AI database versioning](https://neon.com/docs/ai/ai-database-versioning.md).\nHere, emphasize tenant fleets:\n\n- Persist snapshot and branch IDs per tenant in your ledger. Tie each to\nnon-Neon state via\n[compound checkpoints](https://github.com/neondatabase/neon-for-agent-platforms/blob/main/skills/neon-postgres-agent-platforms/references/COMPOUND_CHECKPOINTS_FOR_AGENT_PLATFORMS.md).\n- After finalized restores, branch IDs change and orphaned `(old)` branches\naccumulate. Automate cleanup and update stored IDs.\n- Poll operations to completion before reconnecting tenant apps.\n- Product semantics (snapshot counts per tier, Beta pricing dates) change.\nConfirm on [Agent Plan](https://neon.com/docs/introduction/agent-plan.md) docs.\n\nTypical platform-level checkpoint triggers:\n\n- Before promoting generated schema changes for a tenant\n- Start or end of an agent run that mutates a tenant's database\n- Before destructive migrations or customer-visible restore actions\n\nLinks:\n[AI database versioning](https://neon.com/docs/ai/ai-database-versioning.md) ·\n[Backup and restore](https://neon.com/docs/guides/backup-restore.md) ·\n[Snapshots-as-checkpoints demo](https://github.com/neondatabase-labs/snapshots-as-checkpoints-demo)\n\n## Sandbox and preview databases\n\nUse this when a partner needs per-tenant preview or sandbox databases for\ngenerated apps. (\"How do I create a branch?\" for a single app goes to\n`**neon-postgres**`.)\n\n- Track `project_id` / `branch_id` per customer / agent run when spinning\npreviews via the Management API.\n- Branch and storage counts scale with fleet size. Monitor caps and\ngarbage-collect idle previews.\n- Short `suspend_timeout_seconds` on preview computes reduces cost.\n- Pair branch/snapshot lifecycle with secrets rotation and deploy URLs via\ncompound checkpoints.\n\nLink:\n[AI Agent integration guide](https://neon.com/docs/guides/ai-agent-integration.md)\n\n## Cost, consumption, and entitlements\n\n- **Never invent** pricing, quotas, or limits. Confirm on\n[Agent Plan](https://neon.com/docs/introduction/agent-plan.md) and\n[consumption metrics](https://neon.com/docs/guides/consumption-metrics.md).\n- Use `GET /api/v2/consumption_history/v2/projects` for billing-aligned fields.\nLegacy endpoints differ. The legacy account-level endpoint has been retired;\nuse v2 per-project metrics instead\n([legacy guide](https://neon.com/docs/guides/consumption-metrics-legacy.md)).\n- V2 `metrics` query strings are exactly: `compute_unit_seconds`,\n`root_branch_bytes_month`, `child_branch_bytes_month`,\n`instant_restore_bytes_month`, `snapshot_storage_bytes_month`,\n`public_network_transfer_bytes`, `private_network_transfer_bytes`,\n`extra_branches_month`.\n- Poll consumption roughly every 15 minutes. Polling does not wake suspended\ncomputes.\n- Run `auth-users.ts meta` from\n[scripts/](https://github.com/neondatabase/neon-for-agent-platforms/tree/main/skills/neon-postgres-agent-platforms/scripts)\nfor a routing map (Neon Auth REST vs Postgres roles vs consumption APIs).\n\nLinks:\n[Agent Plan](https://neon.com/docs/introduction/agent-plan.md) ·\n[Consumption metrics](https://neon.com/docs/guides/consumption-metrics.md) ·\n[Consumption limits](https://neon.com/docs/guides/consumption-limits.md) ·\n[Cost optimization](https://neon.com/docs/introduction/cost-optimization.md) ·\n[Plans](https://neon.com/docs/introduction/plans.md)\n\n## Organization and project limit increases\n\n- Current defaults and ceilings are on\n[Agent Plan](https://neon.com/docs/introduction/agent-plan.md) and\n[AI Agent integration](https://neon.com/docs/guides/ai-agent-integration.md).\nDo not invent limits.\n- For project increase requests, email\n[agents@neon.tech](mailto:agents@neon.tech) with org ID(s), growth context,\nand timeline. Also flag in shared Slack if available.\n\n## Co-marketing\n\n- Co-marketing is an included Agent Plan benefit.\n- Available: joint blog posts, social promotion, hackathon sponsorship, case\nstudies, landing page features.\n- Reach out via shared Slack or your Neon representative with context on what\nyou're building.\n\nLink: [Agent Plan](https://neon.com/docs/introduction/agent-plan.md)\n\n## Support\n\n- **Shared Slack channel:** fastest path for technical questions and urgent\nissues.\n- **Neon representative:** account-level requests, custom configuration,\nescalations.\n- **Limit increases:** email\n[agents@neon.tech](mailto:agents@neon.tech) with org ID(s), growth context,\nand timeline.\n- **Billing:** raise via Slack or your Neon representative. Credit balances and\ninvoices are in the Neon Console under Billing.\n- **Community:** [Neon Discord](https://discord.gg/92vNTzKDGp) ·\n[Docs](https://neon.com/docs) ·\n[API reference](https://neon.com/docs/reference/api)\n\n## Repository samples\n\nRunnable Management API automation from\n[neondatabase/neon-for-agent-platforms](https://github.com/neondatabase/neon-for-agent-platforms).\n\n- **Quick start:**\n[README](https://github.com/neondatabase/neon-for-agent-platforms/blob/main/README.md#quick-start)\n- **Script catalog:**\n[MANAGEMENT_API_SAMPLES.md](https://github.com/neondatabase/neon-for-agent-platforms/blob/main/skills/neon-postgres-agent-platforms/references/MANAGEMENT_API_SAMPLES.md)\n- **Compound checkpoints:**\n[COMPOUND_CHECKPOINTS_FOR_AGENT_PLATFORMS.md](https://github.com/neondatabase/neon-for-agent-platforms/blob/main/skills/neon-postgres-agent-platforms/references/COMPOUND_CHECKPOINTS_FOR_AGENT_PLATFORMS.md)\n- **Checkpoint orchestration:**\n[CHECKPOINT_ORCHESTRATION_PATTERN.md](https://github.com/neondatabase/neon-for-agent-platforms/blob/main/skills/neon-postgres-agent-platforms/references/CHECKPOINT_ORCHESTRATION_PATTERN.md)\n- **Doc index:**\n[SCRIPT-OVERVIEW.md](https://github.com/neondatabase/neon-for-agent-platforms/blob/main/skills/neon-postgres-agent-platforms/references/SCRIPT-OVERVIEW.md)\n\nThese scripts use `@neon/sdk` only. Shared\n[utils.ts](https://github.com/neondatabase/neon-for-agent-platforms/blob/main/skills/neon-postgres-agent-platforms/scripts/utils.ts)\nbuilds the client and resolves the default branch; the SDK polls async\noperations (readiness) for you. For agent-facing Management API tools, see\n**SDK vs agent tools** above. For SQL access from app code (drivers, pooling,\nORMs), use `**neon-postgres`**.\n" }, { "url": "https://neon.com/.well-known/agent-skills/neon-object-storage/SKILL.md", "domain": "neon.com", "endpoint": "/.well-known/agent-skills/neon-object-storage/SKILL.md", "filename": "SKILL.md", "content": "---\nname: neon-object-storage\ndescription: >-\n S3-compatible object storage that branches with your Neon project, so files\n and the database stay in sync across every branch. Use when a user wants\n object storage, a bucket, blob/file storage, or somewhere to put uploads,\n images, documents, avatars, or user-generated files for their app or agent —\n especially when they already use (or are setting up) Lakebase Postgres and don't\n want to add a separate storage provider like AWS S3, Cloudflare R2, or\n Supabase Storage. Triggers include \"object storage\", \"bucket\", \"blob\n storage\", \"file storage\", \"store uploads/images/files\", \"S3-compatible\n storage\", \"presigned URL\", \"where do I put files\", \"storage logs\",\n \"bucket logs\", \"CDN in front of object storage\", \"Neon Object Storage\",\n \"Neon Storage\", and \"storage that branches with my database\".\nmetadata:\n parent: neon\n source: https://github.com/neondatabase/agent-skills/tree/main/skills/neon-object-storage\n---\n\n**FIRST**: Use the parent `neon` skill for a Neon overview, getting started with Neon, Neon development best practices, and more.\n\nIf the `neon` skill is not installed, fetch it from https://neon.com/docs/ai/skills/neon/SKILL.md or install it with:\n\n```bash\nneon skills -s neon -y\n```\n\n# Neon Object Storage\n\nCurrently available in `aws-us-east-2`, `aws-us-east-1`, `aws-eu-central-1`, and `aws-ap-southeast-1`.\n\nNeon Object Storage is S3-compatible object storage that branches with your projects: every branch gets its own isolated storage state, so files and database rows stay in sync across dev, preview, staging, and production.\n\nUse this skill to help the user store and serve files that branch alongside their database. Deliver a working bucket and upload/download flow, a branch-aware S3 client wired to the injected env vars, or a precise answer from the official Neon docs.\n\n## When to Use\n\nReach for Neon Object Storage for the files an app and its users produce — uploads, attachments, avatars, images, documents, generated assets, backups. It is the default place to put them when the app is already on Neon:\n\n- **They already use Lakebase Postgres and don't want a second provider.** One backend, one bill, one CLI, one set of branches — instead of standing up and wiring a separate AWS S3 / R2 / Supabase Storage account. The same Neon credential that backs the database backs storage.\n- **Files must stay in sync with the database across environments.** Storage branches _together with_ your Postgres data. Fork a branch and the child instantly inherits the parent's buckets and objects at that point in time — copy-on-write, so no data is duplicated. This is what makes agent, dev, preview, and test environments seamless: a preview branch gets a consistent snapshot of _both_ the rows and the files they reference, and writes on the child never touch the parent.\n- **They want safe, throwaway environments.** Upload, overwrite, and delete files in a preview/CI branch without any risk to production data, then drop the branch.\n- **They want standard S3 tooling.** It's built on S3 semantics and speaks the S3 API, so the AWS SDKs, `boto3`, the AWS CLI, and presigned URLs all work — reliable and familiar, with no proprietary client.\n\nIf the files in question ship with the app itself — HTML, JS bundles, CSS, the images in `public/` — that's static web hosting and belongs on Vercel, Netlify, or Cloudflare instead. Public assets that are served from a bucket want a CDN in front of them (see [Architecture: Where Object Storage Fits](#architecture-where-object-storage-fits)).\n\n## What It Does\n\n- **S3-compatible** — Works with existing S3 SDKs, `boto3`, the AWS CLI, and presigned URLs. Path-style addressing and SigV4 only.\n- **Branches with your database** — Every Neon branch gets its own isolated, copy-on-write storage state. Forking copies no data.\n- **Two access modes** — `private` buckets require a credential for every operation; `public_read` buckets allow anonymous reads with authenticated writes.\n- **One credential system** — The same Neon credential system used by Functions and the AI Gateway.\n\n## Availability\n\nCheck this precondition before setting anything up: Neon Object Storage is currently available in `aws-us-east-2`, `aws-us-east-1`, `aws-eu-central-1`, and `aws-ap-southeast-1`. Confirm the user's Neon project is in one of these regions before proceeding. Region coverage: https://neon.com/docs/get-started/backend-overview.md\n\n## Architecture: Where Object Storage Fits\n\nNeon (Object Storage included) is **backend primitives, not full-stack app hosting**. Object Storage holds the files the app and its users produce — uploads, attachments, avatars, documents, generated images, backups — keyed from Postgres rows on the same branch. Two boundaries follow from that:\n\n- **Put a CDN in front of public assets.** A `public_read` object is read anonymously at `${AWS_ENDPOINT_URL_S3}//` — the branch's storage endpoint, injected as an env var (see [Environment Variables](#environment-variables)). For assets a browser loads on every page view — avatars, product images, anything hot — use that as the origin for a Cloudflare or Vercel CDN, and set `Cache-Control` on `PutObject` so the edge knows how long to hold each object. A cached object is only as fresh as its key, so write each version to a new key (`avatars//.jpg`) and repoint the key stored in Postgres, rather than overwriting one key and waiting out the TTL. The endpoint is branch-scoped, so a production CDN points at the production branch while preview branches read their own endpoint directly rather than sharing a cache. Private buckets stay on presigned URLs instead, which carry their signature in the query string.\n- **Host the app itself elsewhere.** Anything checked into the repo — HTML, JS bundles, CSS, and the images and fonts that ship in `public/` — belongs on Vercel, Netlify, or Cloudflare, along with the index documents, SPA fallbacks, and custom domains that go with them. Neon has no website mode to serve them through: `PutBucketWebsite` returns `501 Not Implemented`.\n\n## Setup\n\nObject storage is part of the `neon.ts` infrastructure-as-code config (see the `neon` skill for the branch-first workflow, `link`/`checkout`, and `neon.ts` basics). Declare buckets under `buckets`, keyed by bucket name:\n\n```typescript\n// neon.ts\nimport { defineConfig } from \"@neon/config/v1\";\n\nexport default defineConfig({\n buckets: {\n images: {}, // private by default\n \"public-assets\": { access: \"public_read\" },\n },\n});\n```\n\nProvision the declared buckets on the linked branch:\n\n```bash\nneon deploy # alias for `neon config apply`\n```\n\n## Neon Infrastructure as Code (`neon.ts`)\n\nThe `buckets` block above is part of `neon.ts`, Neon's infrastructure-as-code file — one TypeScript file declares your buckets alongside every other service the branch should have (see the `neon` skill for the full reference). Reconcile the declaration against a branch the Terraform way:\n\n```bash\nneon config status # print the branch's live config (which buckets exist)\nneon config plan # dry-run diff of what apply would change\nneon config apply # create the declared buckets (neon deploy is an alias)\n```\n\nBuckets are **branch-scoped**: when a `neon.ts` is present, `neon checkout` applies the policy as it _creates_ a branch, so a fresh preview/CI branch comes up with its buckets already provisioned (and copy-on-write objects inherited from the parent). Checking out an _existing_ branch doesn't reconcile it — run `neon deploy` to apply changes. Provisioning (`config apply` / `deploy`), `link`, and `checkout` also pull the branch's S3 credentials into your local `.env.local`, so the same `env pull` step shown below happens for you on those commands.\n\n## Environment Variables\n\nWhen `buckets` is declared, Neon injects **AWS-standard** S3 env vars so the AWS SDKs work from the environment with zero extra config. Inside a deployed Neon Function these are injected automatically; locally, pull them onto disk (or inject them at runtime) via the CLI:\n\n```bash\nneon env pull # writes the branch's vars into .env (or .env.local)\n# or, without writing a file, inject at runtime:\nneon-env run -- \n```\n\n| Variable | Meaning |\n| ----------------------- | --------------------------------------------------- |\n| `AWS_ACCESS_KEY_ID` | S3 Access Key ID (the branch credential's token id) |\n| `AWS_SECRET_ACCESS_KEY` | S3 Secret Access Key |\n| `AWS_ENDPOINT_URL_S3` | Branch S3 endpoint URL |\n| `AWS_REGION` | Region, e.g. `us-east-2` |\n\nBecause the names are AWS-standard, the AWS SDK picks up the credentials, endpoint, and region from the environment automatically. Credentials are branch-scoped and valid for that branch and all its descendants.\n\nFor typed, validated access to these credentials instead of reading `process.env` directly, pass the same `neon.ts` config object to `parseEnv` from `@neon/env` — it returns an `env.storage` namespace (`accessKeyId`, `secretAccessKey`, `endpoint`, `region`) derived from your config. See the `neon` skill.\n\n## Working with Objects: the Files SDK (Recommended)\n\nThe simplest, most portable way to read and write objects is the [Files SDK](https://files-sdk.dev) with its `neon` adapter — a small, unified storage API (`upload`, `download`, `url`, `list`, `exists`, `copy`, `delete`, `signedUploadUrl`) over web-standard I/O. It uses the AWS S3 client under the hood, configured appropriately for Neon, and relabels errors as `Neon error` — so there's nothing to misconfigure. Reach for this first.\n\nInstall it alongside the AWS S3 peer dependencies the adapter uses internally:\n\n```bash\nnpm install files-sdk @aws-sdk/client-s3 @aws-sdk/s3-presigned-post @aws-sdk/s3-request-presigner\n```\n\nThe adapter resolves its endpoint, region, and credentials from the same injected `AWS_*` env vars — pass only the bucket name:\n\n```typescript\nimport { Files } from \"files-sdk\";\nimport { neon } from \"files-sdk/neon\";\n\nconst files = new Files({ adapter: neon({ bucket: \"images\" }) });\n\n// Upload — body may be a Buffer, Uint8Array, Blob, File, ReadableStream, or string\nawait files.upload(\"generated/cat.jpg\", fileBuffer, { contentType: \"image/jpeg\" });\n\n// Download\nconst file = await files.download(\"generated/cat.jpg\");\nconst bytes = new Uint8Array(await file.arrayBuffer());\n\n// Presigned GET — share without exposing credentials (defaults to a 1h expiry)\nconst url = await files.url(\"generated/cat.jpg\", { expiresIn: 3600 });\n\n// Plus: files.exists(), files.list({ prefix }), files.copy(), files.delete(), files.signedUploadUrl()\n```\n\nSwap the adapter import (`files-sdk/s3`, `files-sdk/r2`, `files-sdk/gcs`, …) and the rest of your code is unchanged.\n\n## Working with Objects: the AWS S3 Client (Alternative)\n\nNeon speaks the S3 API directly, so you can drop down to the AWS SDK whenever you prefer the native client or already depend on it. The credentials, endpoint, and region are read from the standard AWS env chain, so the only setting you pass is `forcePathStyle: true` — Neon requires path-style addressing, so the S3 client **must** set it:\n\n```typescript\nimport { S3Client } from \"@aws-sdk/client-s3\";\n\nconst s3 = new S3Client({\n forcePathStyle: true, // required: Neon uses path-style addressing\n});\n```\n\nThen upload, download, and presign with the raw command objects:\n\n```typescript\nimport { PutObjectCommand, GetObjectCommand } from \"@aws-sdk/client-s3\";\nimport { getSignedUrl } from \"@aws-sdk/s3-request-presigner\";\n\nconst BUCKET = \"images\";\n\n// Upload\nawait s3.send(\n new PutObjectCommand({\n Bucket: BUCKET,\n Key: \"generated/cat.jpg\",\n Body: fileBuffer,\n ContentType: \"image/jpeg\",\n }),\n);\n\n// Download\nconst res = await s3.send(\n new GetObjectCommand({ Bucket: BUCKET, Key: \"generated/cat.jpg\" }),\n);\nconst bytes = await res.Body?.transformToByteArray();\n\n// Presigned GET — share without exposing credentials\nconst url = await getSignedUrl(\n s3,\n new GetObjectCommand({ Bucket: BUCKET, Key: \"generated/cat.jpg\" }),\n { expiresIn: 3600 },\n);\n```\n\n## Pairing Storage with the Database on a Branch\n\nThe canonical pattern: an agent generates an image → `PutObject` into the `images` bucket → a row is inserted in Postgres → a presigned URL is returned on read. Store the bucket **key** (not the bytes) in a Postgres column, and presign on read. Because both the row and the object live on the same branch, they branch together and never drift.\n\n## CLI Bucket and Object Commands\n\n`neon` also has first-class bucket/object commands (`neon bucket create|list|delete`, `neon bucket object put|get|list|delete`) for scripting and one-off operations.\n\n## Built-in Branch Logs\n\n```bash\nneon logs query --branch production --source storage --since 1h\n```\n\nStorage is one of the two sources branch logs cover today, alongside Neon Functions. Logs are scoped to a single branch, so pass `--branch` when the bucket you're debugging isn't on the branch you're checked out on. Everything else about logs — the required CLI version, filters, the SDK, and the Loki-compatible read API — is in the parent `neon` skill's **Observability** section.\n\n## Neon Documentation\n\nThe Neon documentation is the source of truth and Object Storage is evolving rapidly, so always verify against the official docs. Any doc page can be fetched as markdown by appending `.md` to the URL or by requesting `Accept: text/markdown`. Find the right page from the docs index (https://neon.com/docs/llms.txt) and the changelog announcements.\n\n## Further Reading\n\n- https://neon.com/docs/get-started/backend-overview.md\n- https://neon.com/docs/storage/overview.md\n- https://neon.com/docs/storage/get-started.md\n- https://neon.com/docs/storage/buckets.md\n- https://neon.com/docs/storage/objects.md\n- https://neon.com/docs/storage/authentication.md\n- https://neon.com/docs/storage/s3-compatibility.md\n- https://neon.com/docs/storage/troubleshooting.md\n- https://files-sdk.dev — Files SDK docs (the `neon` adapter)\n" }, { "url": "https://neon.com/.well-known/agent-skills/neon-ai-gateway/SKILL.md", "domain": "neon.com", "endpoint": "/.well-known/agent-skills/neon-ai-gateway/SKILL.md", "filename": "SKILL.md", "content": "---\nname: neon-ai-gateway\ndescription: >-\n One API and one credential for frontier and open-source LLMs, built into your\n Neon branch and powered by Databricks. Use when a user wants to call an LLM,\n add AI/chat/an agent to their app, route between model providers (OpenAI,\n Anthropic, Google/Gemini, Meta, Alibaba, and more), or avoid juggling\n separate provider API keys and accounts — especially when they already use\n Neon and want AI requests to branch with their project. Works with the OpenAI\n SDK, Anthropic SDK, google-genai, the Vercel AI SDK, and Mastra by changing\n only the base URL. Triggers include \"call an LLM\", \"add AI to my app\",\n \"chat completion\", \"model routing\", \"LLM proxy/gateway\", \"one API for all\n models\", \"use Claude/GPT/Gemini\", \"AI SDK\", \"Mastra agent\", \"Neon AI\n Gateway\", and \"log/rate-limit AI calls\".\nmetadata:\n parent: neon\n source: https://github.com/neondatabase/agent-skills/tree/main/skills/neon-ai-gateway\n---\n\n**FIRST**: Use the parent `neon` skill for a Neon overview, getting started with Neon, Neon development best practices, and more.\n\nIf the `neon` skill is not installed, fetch it from https://neon.com/docs/ai/skills/neon/SKILL.md or install it with:\n\n```bash\nneon skills -s neon -y\n```\n\n# Neon AI Gateway\n\nCurrently available in `aws-us-east-2`, `aws-us-east-1`, `aws-eu-central-1`, and `aws-ap-southeast-1`.\n\nThe Neon AI Gateway is the LLM inference layer built into your Neon branch: one API and one Neon credential give you access to frontier and open-source models from many providers (Anthropic, OpenAI, Google, Meta, and more), all hosted and powered by Databricks. The catalog shifts over time, so treat `/v1/models` and the [models.dev Neon page](https://models.dev/providers/neon) as the source of truth rather than a fixed provider list. Your existing OpenAI/Anthropic/Gemini SDK works by changing only the base URL.\n\nUse this skill to help the user send model calls through the gateway, wire it into the AI SDK or Mastra, and switch providers without rewiring code. Deliver a working inference request, a configured agent, or a precise answer from the official Neon docs.\n\n## When to Use\n\nReach for the AI Gateway whenever an app or agent needs to call an LLM and the user would rather not manage model providers themselves:\n\n- **One credential instead of many provider accounts.** A single Neon credential reaches the entire model catalog across every provider Databricks hosts. No separate OpenAI / Anthropic / Google billing, keys, or signups to provision and rotate.\n- **Switch models without rewiring.** The unified endpoint is OpenAI-compatible and works with every model in the catalog — change one `model` field to move between Claude, GPT, and Gemini. Standard SDKs (OpenAI, Anthropic, google-genai) work with just a base-URL change.\n- **AI follows your branches.** Each branch has its own gateway endpoint, scoped with the same lineage as your database. AI requests from a preview/feature branch are isolated to that branch — the same isolation your data already gets — which makes preview, CI, and agent environments self-contained.\n- **No extra infrastructure, and it's already next to your data.** The gateway lives inside your Neon project (and is injected into Neon Functions automatically), runs on the same Databricks infrastructure that serves trillions of tokens a month, and supports streaming (SSE) out of the box.\n\nIf the user already has a deep, single-provider integration and no interest in Neon branching or multi-model routing, a direct provider SDK is fine — but the moment they want one credential, model portability, or branch-scoped AI, this is the reason to use it.\n\n## What It Does\n\n- **One API for all models** — Frontier and open-source models behind a single endpoint, addressed by their catalog ID (e.g. `claude-sonnet-4-6`, `gpt-5-mini`, `gemini-3-flash`).\n- **Standard SDKs, one URL change** — OpenAI SDK and AI SDK (OpenAI-compatible MLflow/Responses routes), Anthropic SDK (native Messages), google-genai (native Gemini).\n- **Branch-scoped** — Each branch gets its own gateway host; the Neon credential authorizes requests for that branch and its descendants.\n- **Streaming** — Server-sent events work on all endpoints with no extra configuration.\n\n## Availability\n\nCheck these preconditions before setting anything up:\n\nThe AI Gateway is currently available in `aws-us-east-2`, `aws-us-east-1`, `aws-eu-central-1`, and `aws-ap-southeast-1`. Foundation model access requires a paid Neon plan. Confirm the user's project is in one of these regions.\n\n### Enabling the gateway: plan and model-catalog gating\n\nThe AI Gateway is credential-gated rather than a provisioning step, but two plan limits gate it — one blocks provisioning, the other only trims the catalog — and the CLI surfaces each:\n\n- **Free plan → provisioning is blocked.** `neon config apply` / `deploy` and `neon checkout` **refuse** to enable the gateway on a Free plan (the gateway can't serve requests there), with a friendly \"upgrade to a paid plan, or remove `aiGateway`\" error. A dry-run `neon config plan` and `neon env pull` don't provision, so they only **warn**. So: to use the gateway the project's account must be on a paid Neon plan.\n- **Paid plan with a reduced model catalog.** On a paid plan the gateway provisions and serves, but an account can start with a trimmed catalog — some flagship models (e.g. Anthropic Opus, OpenAI Codex / `*-pro`) are missing from `GET /v1/models`. This is expected; `neon env pull` (and the env pull bundled into `apply` / `deploy` / `checkout`) warns and links the user to their branch's AI Gateway page in the Neon Console (`https://console.neon.tech/app/projects//branches//ai-gateway`) to request access to more models. Verify what's actually available for the branch by reading `/v1/models` (see the models section below) rather than assuming the full catalog.\n\nWhen helping a user debug \"the gateway isn't working\" or \"a model is missing\", use `/v1/models` plus the account's plan to distinguish these two cases — a Free plan blocks provisioning entirely, while a reduced catalog on a paid plan just needs a model-access request.\n\n## Setup\n\nThe gateway is part of `neon.ts` (see the `neon` skill for the branch-first workflow and `neon.ts` basics). Enable it with `aiGateway`:\n\n```typescript\n// neon.ts\nimport { defineConfig } from \"@neon/config/v1\";\n\nexport default defineConfig({\n aiGateway: true,\n});\n```\n\n```bash\nneon deploy # provisions the gateway on the linked branch\n```\n\n## Neon Infrastructure as Code (`neon.ts`)\n\nThe `aiGateway` toggle above is part of `neon.ts`, Neon's infrastructure-as-code file — one TypeScript file declares the gateway alongside every other branch service, in version control (see the `neon` skill for the full reference). Reconcile it against a branch the Terraform way:\n\n```bash\nneon config status # print the branch's live config (is the gateway on?)\nneon config plan # dry-run diff of what apply would change\nneon config apply # enable the gateway on the branch (neon deploy is an alias)\n```\n\nThe gateway is **branch-scoped**: each branch gets its own gateway host. When a `neon.ts` is present, `neon checkout` applies the policy as it _creates_ a branch, so a fresh preview/CI branch comes up with the gateway already enabled. Checking out an _existing_ branch doesn't reconcile it — run `neon deploy` to apply changes. Provisioning (`config apply` / `deploy`), `link`, and `checkout` also pull the branch's gateway credentials into your local `.env.local`, so local runs hit the same branch gateway as the deployed function (no manual `env pull` needed).\n\n## Environment Variables\n\nWhen `aiGateway` is enabled, Neon injects the gateway credentials as **Neon-branded** env vars. Inside a deployed Neon Function these are injected automatically; locally, `neon env pull` writes them to `.env`/`.env.local` (or use `neon-env run -- ` to inject at runtime without a file):\n\n| Variable | Meaning |\n| -------------------------- | ----------------------------------------------------------------------------------------------------------------------------------- |\n| `NEON_AI_GATEWAY_TOKEN` | Gateway bearer token (a Neon credential, `nt_live_...`) |\n| `NEON_AI_GATEWAY_BASE_URL` | **Bare branch gateway host** (`scheme://host`, **no path** — no `/ai-gateway`): `https://-api.ai..aws.neon.tech` |\n\n> Neon injects **only** these two vars — it does **not** set `OPENAI_API_KEY` / `OPENAI_BASE_URL`. The `@neon/ai-sdk-provider` and Mastra's `neon/` read `NEON_AI_GATEWAY_*` directly (zero config); for the plain OpenAI SDK / `@ai-sdk/openai`, build the client's `apiKey` + `baseURL` from them (shown below), or set your own `OPENAI_*` by hand (`env pull` leaves user-set vars untouched).\n\n`NEON_AI_GATEWAY_BASE_URL` is the **bare host** — you append the dialect path yourself (which is exactly what the `@neon/ai-sdk-provider` does for you). The routes under the host are:\n\n- `/v1` — unified, OpenAI **Chat Completions**-compatible; recommended default, works with every provider (`/v1/chat/completions`).\n- `/openai/v1` — OpenAI **Responses** API (required for `gpt-5-…-codex` variants and `gpt-5-5-pro`); the `@ai-sdk/openai` provider uses the Responses API by default (`/openai/v1/responses`).\n- `/anthropic` — native Anthropic Messages (extended thinking, prompt caching). Give the Anthropic SDK this as its base URL and it appends `/v1/messages` itself, so the full request path is `/anthropic/v1/messages`.\n- `/gemini` — native Gemini `generateContent`. Give google-genai this as its base URL and it appends `/v1beta/models/:generateContent` itself, so the full request path is `/gemini/v1beta/models/:generateContent`.\n\nSo `${NEON_AI_GATEWAY_BASE_URL}/v1` is the chat-completions endpoint and `${NEON_AI_GATEWAY_BASE_URL}/openai/v1` the OpenAI Responses endpoint (both appended by you); for the native Anthropic and Gemini dialects you hand the SDK the shorter `/anthropic` or `/gemini` base and it appends the rest. See [Use with Plain SDKs](#use-with-plain-sdks-lower-level) below.\n\nFor typed, validated access to the injected credentials, pass the same `neon.ts` config object to `parseEnv` from `@neon/env` — it returns an `env.aiGateway` namespace (`apiKey`, `baseUrl`) derived from your config.\n\n## Build Agents with the Vercel AI SDK (Recommended)\n\nThe [Vercel AI SDK](https://ai-sdk.dev) is the recommended way to call the gateway and build agents from TypeScript: one set of primitives (`generateText`, `streamText`, tool calling, structured output) over every catalog model, with first-class streaming for the long agent responses Neon Functions are built to host.\n\nThe dedicated `@neon/ai-sdk-provider` reads `NEON_AI_GATEWAY_BASE_URL` + `NEON_AI_GATEWAY_TOKEN` from the injected env with **zero config** and routes each model to the best endpoint (Anthropic → Messages, OpenAI/Codex → Responses, everything else → MLflow). On a Neon Function that streams text and generates images, just pick a catalog model:\n\n```typescript\nimport { neon } from \"@neon/ai-sdk-provider\";\nimport { streamText } from \"ai\";\n\nconst result = streamText({\n model: neon(\"gpt-5-mini\"), // or claude-sonnet-4-6, gemini-3-flash, ...\n messages,\n tools: {\n image_generation: neon.tools.imageGeneration({\n outputFormat: \"jpeg\",\n size: \"1024x1024\",\n }),\n },\n});\nreturn result.toUIMessageStreamResponse();\n```\n\nA single completion is the same provider with `generateText`:\n\n```typescript\nimport { neon } from \"@neon/ai-sdk-provider\";\nimport { generateText } from \"ai\";\n\nconst { text } = await generateText({\n model: neon(\"claude-haiku-4-5\"), // or gpt-5-3-codex, gemini-3-flash, ...\n prompt: \"Summarize Postgres for me.\",\n});\n```\n\n> Prefer `@neon/ai-sdk-provider` over the bare `@ai-sdk/openai` `openai()`: Neon injects only `NEON_AI_GATEWAY_*`, not `OPENAI_*`, so `openai()` won't pick up the gateway from the env on its own. If you do use `@ai-sdk/openai`, configure it explicitly with `createOpenAI({ apiKey: process.env.NEON_AI_GATEWAY_TOKEN, baseURL: `${process.env.NEON_AI_GATEWAY_BASE_URL}/openai/v1` })`.\n\nTo build an **agent** — a model that calls tools in a loop and then answers — add `tools` and a `stopWhen` budget. The loop runs in-process, so on a Neon Function it isn't cut off by lambda-style timeouts:\n\n```typescript\nimport { neon } from \"@neon/ai-sdk-provider\";\nimport { generateText, tool, stepCountIs } from \"ai\";\nimport { z } from \"zod\";\n\nconst { text } = await generateText({\n model: neon(\"claude-sonnet-4-6\"),\n prompt: \"How many open todos do I have, and what's the oldest one?\",\n tools: {\n listTodos: tool({\n description: \"List the user's open todos.\",\n inputSchema: z.object({}), // AI SDK v5+: `inputSchema`, not `parameters`\n execute: async () => db.select().from(todos),\n }),\n },\n stopWhen: stepCountIs(5), // let the model call tools, then summarize\n});\n```\n\nFor a full AI SDK agent deployed as a Neon Function (streaming, tool calling, image generation, persistence), see the `neon-functions` skill's [references/ai-sdk.md](https://neon.com/docs/ai/skills/neon-functions/references/ai-sdk.md).\n\n## Build Agents with Mastra (Recommended)\n\n[Mastra](https://mastra.ai) is the recommended framework when you want batteries-included agents — built-in memory, tools, workflows, and tracing — with the model still pointed at the gateway. With `@mastra/core` 1.47+, use a `neon/` magic string; Mastra reads `NEON_AI_GATEWAY_BASE_URL` and `NEON_AI_GATEWAY_TOKEN` from the environment (injected by `neon deploy` when `aiGateway` is enabled). Use `parseEnv` only for other declared services (e.g. `env.postgres.databaseUrl` for `@mastra/pg` memory):\n\n```typescript\nimport { Agent } from \"@mastra/core/agent\";\nimport { parseEnv } from \"@neon/env\";\nimport config from \"../neon\";\n\nconst env = parseEnv(config);\n\nexport const personalAssistant = new Agent({\n id: \"personal-assistant\",\n name: \"personal-assistant\",\n instructions:\n \"You are a warm, concise personal assistant with long-term memory.\",\n model: \"neon/claude-haiku-4-5\",\n memory, // your Mastra memory store, e.g. @mastra/pg on env.postgres.databaseUrl\n});\n```\n\n## Use with Plain SDKs (Lower-Level)\n\nWhen you don't need an agent framework — a single completion, an existing provider-SDK integration, or native provider features — call the gateway with the plain SDKs. Neon injects the `NEON_AI_GATEWAY_*` vars (not `OPENAI_*`), so set the client's `apiKey` + `baseURL` from them. For the OpenAI **Responses** dialect (`/openai/v1`):\n\n```typescript\nimport OpenAI from \"openai\";\n\nconst client = new OpenAI({\n apiKey: process.env.NEON_AI_GATEWAY_TOKEN,\n baseURL: `${process.env.NEON_AI_GATEWAY_BASE_URL}/openai/v1`,\n});\n\nconst res = await client.responses.create({\n model: \"gpt-5-mini\", // swap to claude-sonnet-4-6, gemini-3-flash, ...\n input: \"What is Neon?\",\n});\n```\n\nFor the unified **chat-completions** dialect, point `baseURL` at `/v1` instead:\n\n```typescript\nconst client = new OpenAI({\n apiKey: process.env.NEON_AI_GATEWAY_TOKEN,\n baseURL: `${process.env.NEON_AI_GATEWAY_BASE_URL}/v1`,\n});\n\nconst res = await client.chat.completions.create({\n model: \"claude-sonnet-4-6\",\n messages: [{ role: \"user\", content: \"What is Neon?\" }],\n});\n```\n\nThe Anthropic SDK and google-genai work the same way for native provider features — point the Anthropic SDK at `${NEON_AI_GATEWAY_BASE_URL}/anthropic` (it appends `/v1/messages` itself) and google-genai at `${NEON_AI_GATEWAY_BASE_URL}/gemini` (it appends `/v1beta/models/...`).\n\n## Model Identifiers\n\nUse a model's catalog ID directly in the `model` field — e.g. `claude-sonnet-4-6`, `gpt-5-mini`, `gemini-3-flash`. No provider prefix is needed. To look up the exact identifiers the gateway serves, which underlying model each maps to, and their context windows, pricing, and capabilities, use any of:\n\n- **models.dev Neon provider page: https://models.dev/providers/neon** — the canonical, always-current list of the Neon provider's model IDs and their underlying models. The machine-readable catalog is at https://models.dev/api.json (the `neon` key).\n- **Models doc:** see Further Reading.\n\n## List Available Models at Runtime (`/v1/models`)\n\nThe gateway also exposes the model catalog **live from your own branch endpoint**, so an app or agent can discover exactly which models this branch serves without hard-coding the list. It is an OpenAI-compatible list endpoint, served **only on the unified dialect** (`/v1`):\n\n```bash\ncurl \"$NEON_AI_GATEWAY_BASE_URL/v1/models\" \\\n -H \"Authorization: Bearer $NEON_AI_GATEWAY_TOKEN\"\n```\n\n- `GET ${NEON_AI_GATEWAY_BASE_URL}/v1/models` → **200**\n- `GET ${NEON_AI_GATEWAY_BASE_URL}/openai/v1/models` → **404** (not served on the Responses dialect — use `/v1`)\n\n**Getting the credentials for the request.** Both values come from the same branch-scoped Neon credential the gateway uses everywhere else — you never manage a provider key:\n\n- **Provision via `neon.ts` (recommended).** Enable `aiGateway` in `neon.ts` and run `neon deploy` (or `neon config apply`). Provisioning, `neon link`, and `neon checkout` pull `NEON_AI_GATEWAY_TOKEN` + `NEON_AI_GATEWAY_BASE_URL` into your local `.env.local`; inside a deployed Neon Function they're injected automatically. See **Setup** and **Environment Variables** above.\n- **Pull into the environment via CLI.** `neon env pull` writes the two vars to `.env`/`.env.local`, or `neon-env run -- ` injects them at runtime without a file — but only when `neon.ts` declares `aiGateway`; the vars are never pulled off branch state alone.\n- **Provision via the Console UI.** Enable the AI Gateway on the branch in the Neon Console and copy the branch's gateway base URL and a Neon credential (token) from the project's connection/credentials view.\n\nAny Neon credential (`nt_live_...`) valid for the branch works as the bearer token; `NEON_AI_GATEWAY_BASE_URL` is the bare branch host (no path).\n\n**Response shape** — OpenAI/OpenRouter-compatible list:\n\n```jsonc\n{\n \"object\": \"list\",\n \"data\": [\n {\n \"id\": \"claude-sonnet-4-6\", // catalog model ID — use directly in the `model` field\n \"canonical_slug\": \"claude-sonnet-4-6\",\n \"name\": \"Claude Sonnet 4.6\", // human-readable display name\n \"object\": \"model\",\n \"owned_by\": \"anthropic\", // provider slug, e.g. anthropic | openai | google | meta | alibaba | databricks | ... (non-exhaustive; read live)\n \"created\": 0,\n \"enabled\": true,\n \"context_length\": null,\n \"architecture\": {\n \"modality\": \"text->text\",\n \"input_modalities\": [\"text\"],\n \"output_modalities\": [\"text\"],\n \"tokenizer\": \"Claude\", // Claude | Gemini | GPT | \"\" (empty for open-source)\n \"instruct_type\": null\n },\n \"top_provider\": {\n \"is_moderated\": false,\n \"context_length\": null,\n \"max_completion_tokens\": null\n },\n \"pricing\": null,\n \"per_request_limits\": null\n }\n // ... one entry per model in the branch's catalog\n ]\n}\n```\n\n> Note: `context_length`, `pricing`, and `per_request_limits` are currently `null` and `created` is `0` for every entry — for context windows, pricing, and capabilities use the models.dev catalog above. Use `/v1/models` when you need the live, branch-scoped list of servable model IDs (e.g. to populate a model picker or validate a `model` before a request).\n\n## Neon Documentation\n\nThe Neon documentation is the source of truth and the AI Gateway is evolving rapidly, so always verify against the official docs. Any doc page can be fetched as markdown by appending `.md` to the URL or by requesting `Accept: text/markdown`. Find the right page from the docs index (https://neon.com/docs/llms.txt) and the changelog announcements.\n\n## Further Reading\n\n- https://neon.com/docs/ai-gateway/overview.md\n- https://neon.com/docs/ai-gateway/get-started.md\n- https://neon.com/docs/ai-gateway/models.md\n- https://neon.com/docs/ai-gateway/chat-completions.md\n- https://neon.com/docs/ai-gateway/anthropic-messages.md\n- https://neon.com/docs/ai-gateway/openai-responses.md\n- https://neon.com/docs/ai-gateway/gemini.md\n- https://neon.com/docs/ai-gateway/authentication.md\n- https://neon.com/docs/ai-gateway/troubleshooting.md\n" }, { "url": "https://neon.com/.well-known/agent-skills/neon-functions/SKILL.md", "domain": "neon.com", "endpoint": "/.well-known/agent-skills/neon-functions/SKILL.md", "filename": "SKILL.md", "content": "---\nname: neon-functions\ndescription: >-\n Long-running, serverless Node.js HTTP functions deployed onto your Neon\n branch, with DATABASE_URL injected automatically and compute that runs next\n to your data. Use when a user wants to host an API, an AI agent with long\n streaming responses, a WebSocket or server-sent-events (SSE) server, a\n webhook handler, a Discord bot, an MCP server, or any request/response\n workload that risks timing out on short, lambda-style serverless functions —\n and wants it to branch with their database. Also use for Function Triggers:\n a cron or an object-storage event that POSTs to a function. Triggers include\n \"serverless function\", \"deploy an API\", \"long-running function\",\n \"streaming agent\", \"SSE server\", \"WebSocket server\", \"webhook handler\",\n \"MCP server\", \"cron\", \"function trigger\", \"scheduled function\", \"cron job\",\n \"object storage trigger\", \"on upload\", \"run code next to my database\",\n \"function that won't time out\", \"function logs\", \"Neon Functions\",\n \"Neon Compute\", \"DDoS protection\", \"rate limiting\", and\n \"production hardening\".\nmetadata:\n parent: neon\n source: https://github.com/neondatabase/agent-skills/tree/main/skills/neon-functions\n---\n\n**FIRST**: Use the parent `neon` skill for a Neon overview, getting started with Neon, Neon development best practices, and more.\n\nIf the `neon` skill is not installed, fetch it from https://neon.com/docs/ai/skills/neon/SKILL.md or install it with:\n\n```bash\nneon skills -s neon -y\n```\n\n# Neon Functions\n\nCurrently available in `aws-us-east-2`, `aws-us-east-1`, `aws-eu-central-1`, and `aws-ap-southeast-1`.\n\nNeon Functions are long-running Node.js HTTP handlers deployed onto a Neon branch. Each function gets a public HTTPS URL, runs in the same region as your database, and — if the branch has Postgres — gets `DATABASE_URL` injected automatically. You deploy and manage them through the same Neon CLI, `neon.ts`, and API you already use.\n\nUse this skill to help the user define, run locally, deploy, and manage functions next to their database. Deliver a deployed function with its invocation URL, a working local `neon dev` loop, or a precise answer from the official Neon docs.\n\n## When to Use\n\nReach for Neon Functions when the workload is a request/response handler that benefits from staying alive and staying close to the data:\n\n- **Long-running request/response flows that outlast lambda-style limits.** Agents that make several LLM calls and tool invocations per request, or image/video generation, routinely blow past the ~10–60s execution caps and short streaming windows of traditional serverless functions. Neon Functions are long-running: the handler just needs to _start_ responding within 15 minutes, and an open stream stays alive as long as bytes keep flowing. That's enough headroom for real agent workloads.\n- **Stateful streaming without bolting on Redis.** Because a function stays alive across a request, it can host an SSE endpoint or a WebSocket server and hold the connection open in-process — no external state store (Redis, etc.) needed just to keep a stream coherent. Module-scope state (a `pg` pool, an in-memory counter) persists across requests on the same isolate.\n- **Compute that must sit next to Postgres.** The function runs in the same region as the branch's database, so there are no cross-region round trips on every query. `DATABASE_URL` is injected for you.\n- **A backend that branches with your data.** Each branch runs its own version of the function at its own URL, against its own isolated database (and storage, and gateway) state. Preview deployments, CI, and dev environments each get a self-contained backend — deploying to a child never affects the parent.\n- **Query Postgres from the Function (or an existing framework handler).** Prefer that over the Data API. Use the Data API when the application already uses PostgREST or Supabase-js database calls, or is migrating that client.\n- **Webhooks, bots, and post-response work.** Webhook handlers that fan out into multiple DB writes, Discord/WebSocket bots, and fire-and-forget follow-ups via `waitUntil` (analytics, audit logs) all fit.\n- **Recurring HTTP work.** A Function Trigger POSTs to the function on a cron (`type: \"schedule\"`) or when an object is created in Object Storage (`type: \"storage_object_created\"`). Same `fetch` handler, same 15-minute time-to-first-byte limit. See [Function Triggers](#function-triggers).\n\nIf the workload is a pure static site, or something that must run outside the supported regions (`aws-us-east-2`, `aws-us-east-1`, `aws-eu-central-1`, and `aws-ap-southeast-1`) today, this isn't the right tool yet (see [Timeouts and Runtime Limits](#timeouts-and-runtime-limits) and [Availability](#availability)).\n\n## What It Does\n\n- **Long-running & serverless** — Built for WebSocket servers (see [WebSocket Servers](#websocket-servers)), SSE endpoints (see [Server-Sent Events (SSE)](#server-sent-events-sse)), long agent HTTP streams, and APIs. Still scales to zero when idle.\n- **Web-standard handler** — A function is any default export with a `fetch(request)` method returning a `Response` (Workers/WinterTC-compatible). A Hono app exports exactly that shape, so `export default app` just works. Runs on Node.js 24, so all Node APIs are available.\n- **Close to your database** — Runs in the branch's region; `DATABASE_URL` injected automatically when the branch has Postgres.\n- **Branchable** — Each branch runs its own function version at its own URL against its own isolated state.\n- **Same CLI/API** — Deploy and manage via `neon`, `neon.ts`, or the Neon API.\n- **Function Triggers** — Neon POSTs to the function on a cron or an object-storage upload. See [Function Triggers](#function-triggers).\n\n## Availability\n\nCheck this precondition before setting anything up: Neon Functions is currently available in `aws-us-east-2`, `aws-us-east-1`, `aws-eu-central-1`, and `aws-ap-southeast-1`. Confirm the user's Neon project is in one of these regions.\n\n## Architecture: Where Functions Fit\n\nNeon (Functions included) is **backend primitives, not full-stack app hosting**. Host your app on **Vercel** (or Netlify, or another frontend/app host); Functions are the long-running, stateful slice of your backend that lives next to your data. They compose with that platform in two ways:\n\n- **Add a Function to a full-stack app.** Your Next.js / TanStack Start app on Vercel (or Netlify) owns UI, auth (Managed Auth, Better Auth, Clerk, or another IdP), and talks directly to Lakebase Postgres and Object Storage. Add a Function as a Hono API layer for the web app and other clients, or for one job next to the data: Object Storage uploads, AI agents, Discord bots, WebSocket or SSE servers. (See [Functions as an Agent Backend](#functions-as-an-agent-backend-nextjs-and-similar-frameworks) for the client-direct pattern.)\n- **Run the whole backend control plane on Functions.** Especially when the frontend is **client-only** — TanStack Router, React Router in client mode, and similar SPAs hosted on Vercel or Netlify — the client calls Functions **directly**. Build REST APIs and request/response agents, host **MCP servers**, and run anything stateful or that belongs close to Postgres and Object Storage.\n\nEither way, authenticate by caller: JWT or API key for app and public HTTP (see the WARNING under [Functions as an Agent Backend](#functions-as-an-agent-backend-nextjs-and-similar-frameworks)); `parseTriggerDelivery` for Function Trigger routes; production hardening in [Production hardening](references/production-hardening.md). Because a Function is just your backend, you can **move pieces between your host and Neon** — relocate an agent or a stateful WebSocket server onto a Function when it needs more runtime, and back if needed.\n\nPrefer a Function, or an existing framework handler, that queries Postgres. Use Data API when the application already uses PostgREST/Supabase-js database calls or is migrating that client.\n\n## Production hardening\n\nBefore exposing production routes, read [Production hardening](references/production-hardening.md).\n\nPick by caller: trusted app server, Function Trigger, or public consumer. Keep long browser streams on the client-direct JWT path unless a verified streaming-compatible proxy is required. Authentication rejects application work; requests to the native URL still reach the Function.\n\n## Setup\n\nFunctions are declared in `neon.ts` (see the `neon` skill for the branch-first workflow and `neon.ts` basics). Add `@neon/config` and declare functions under `functions`, keyed by **slug**:\n\n```typescript\n// neon.ts\nimport { defineConfig } from \"@neon/config/v1\";\n\nexport default defineConfig({\n functions: {\n todos: {\n // slug: ^[a-z0-9]{1,20}$ — lowercase letters/digits, no hyphens\n name: \"todo api\", // display label only\n source: \"src/index.ts\", // entry file, relative to neon.ts\n },\n },\n});\n```\n\nThe slug is the function's permanent identity (it appears in the invocation URL and CLI commands) and can't be changed after the first deploy. Use `name` for a human-readable label.\n\nA minimal function — a Hono app that queries the branch's Postgres via the injected `DATABASE_URL`:\n\n```typescript\n// src/index.ts\nimport { Hono } from \"hono\";\nimport { drizzle } from \"drizzle-orm/node-postgres\";\nimport { Pool } from \"pg\";\nimport { parseEnv } from \"@neon/env\";\nimport { attachDatabasePool } from \"@neon/functions\";\nimport config from \"../neon\";\nimport { todos } from \"./db/schema\";\n\nconst env = parseEnv(config);\nconst pool = new Pool({ connectionString: env.postgres.databaseUrl, max: 5 });\nattachDatabasePool(pool);\nconst db = drizzle(pool);\n\nconst app = new Hono();\napp.get(\"/\", (c) => c.text(\"Neon + Hono + Drizzle\"));\napp.post(\"/todos\", async (c) => {\n const { text } = await c.req.json<{ text: string }>();\n const [row] = await db.insert(todos).values({ text }).returning();\n return c.json(row, 201);\n});\napp.get(\"/todos\", async (c) => c.json(await db.select().from(todos)));\n\nexport default app;\n```\n\nCreate the `pg` pool at module scope (reused across requests on the same isolate) and keep `max` small (e.g. 5), since each isolate keeps its own pool. Call `attachDatabasePool(pool)` so an idle disconnect is not an `uncaughtException` — see [Connecting to Postgres](#connecting-to-postgres).\n\n`parseEnv(config)` requires _every_ variable the config implies. A function that only talks to Postgres over the pooled URL can scope it to just that key — `parseEnv` then validates and returns only what you asked for (the keys autocomplete from your `neon.ts`):\n\n```typescript\nconst { postgres } = parseEnv(config, [\"DATABASE_URL\"]); // not the unpooled URL, auth, etc.\nconst pool = new Pool({ connectionString: postgres.databaseUrl, max: 5 });\nattachDatabasePool(pool);\n```\n\n## Develop Locally and Deploy\n\n```bash\nneon dev # serves every function in neon.ts with hot reload; injects DATABASE_URL & friends\nneon deploy --env # preferred full deploy from neon.ts; --env is the file Function env is read from\n```\n\nKeep `.env` or `.env.local` up to date with every key under `functions.*.env`. `neon env pull` writes Neon-managed vars only; add Function secrets to that file, then pass it as `--env`. `neon deploy --env ` loads that file into `process.env` each time, then uploads those values. A missing value is `undefined` and `defineConfig` throws. Omit the key from `neon.ts` if you do not want to write it. Never coerce a missing `process.env` value to an empty string (that uploads `\"\"` and deletes the live key). An empty assignment (`KEY=`) is also `\"\"`. Use `process.env.X!` when TypeScript needs an assertion.\n\nTo deploy a single function without applying `neon.ts`: `neon functions deploy --src src/index.ts` (`--src` takes either the entry file or a directory containing `index.ts`, `index.mjs`, or `index.js`). That command's `--env` is `KEY=VALUE` (repeatable), not a file path. Use it for a targeted env update. Retrieve the public URL with `neon functions get ` (the `invocation_url` field, of the form `https://-.compute..us-east-2.aws.neon.tech`). Manage with `neon functions list|get|delete`.\n\nWhen `neon checkout` _creates_ a new branch and a `neon.ts` is present, it applies the policy automatically. Pass `--env ` on that create so Function env that reads `process.env` resolves (`neon checkout feat --create --env .env.local`). Existing process env wins over the file. Checking out an existing branch never reconciles it — apply config changes with `neon deploy --env ` (add `--update-existing` only after reviewing those changes).\n\n## Neon Infrastructure as Code (`neon.ts`)\n\nThe `functions` block from [Setup](#setup) is part of `neon.ts`, Neon's infrastructure-as-code file — one TypeScript file declares every function (its `source`, display `name`, and `env`) alongside any other branch services, in version control (see the `neon` skill for the full reference). Treat it like Terraform for your branch:\n\n```bash\nneon config status # print the branch's live config (deployed functions)\nneon config plan # dry-run diff of what apply would change\nneon config apply --env # bundle + deploy the declared functions (neon deploy is an alias; pass --env when Function env reads process.env)\n```\n\nFunctions are **branch-scoped**: each branch runs its own deployment at its own URL. When a `neon.ts` is present, `neon checkout` applies the policy as it _creates_ a branch. Pass `--env ` on that create when Function env reads `process.env`. Checking out an _existing_ branch doesn't redeploy — run `neon deploy --env ` to apply changes.\n\nPer-branch deploy tuning (e.g. `runtime`) lives in the `branch` closure, keyed by slug, so it can vary by branch without changing which functions exist:\n\n```typescript\nexport default defineConfig({\n functions: { todos: { name: \"todo api\", source: \"src/index.ts\" } },\n branch: (branch) => ({\n functions: { todos: { runtime: \"nodejs24\" } },\n }),\n});\n```\n\n## Environment Variables\n\nNeon injects branch-scoped connection strings and service URLs at runtime — you don't declare these or pass them at deploy time:\n\n| Variable | Notes |\n| ----------------------- | -------------------------------------------------------------------------------------------------- |\n| `NEON_BRANCH` | The branch **name** (e.g. `main`, `preview/foo`). Injected on every branch, including the default. |\n| `DATABASE_URL` | Pooled connection string. Use for most queries. Present only if the branch has Postgres. |\n| `DATABASE_URL_UNPOOLED` | Direct connection. Use for migrations, `LISTEN`/`NOTIFY`, multi-round-trip transactions. |\n| `NEON_AUTH_BASE_URL` | Present when Neon Auth is enabled on the branch. |\n| `NEON_AUTH_JWKS_URL` | Present when Neon Auth is enabled on the branch. JWKS for verifying Managed Auth JWTs. |\n| `NEON_DATA_API_URL` | Present when the Data API is enabled on the branch. |\n\nObject storage (`AWS_*`) and AI Gateway (`NEON_AI_GATEWAY_*`) vars are also injected when those services are declared — see the `neon-object-storage` and `neon-ai-gateway` skills.\n\n`neon env pull` / `neon-env run` / `neon dev` emit `NEON_BRANCH` (and the connection strings) into your local dev environment too, so local runs mirror the deployed runtime.\n\n**Your own secrets** are per-deployment. Preferred path: declare them in `neon.ts` and run `neon deploy --env `. `` is the gitignored file env pull already writes (`.env` if that file exists, otherwise `.env.local`). Env pull writes Neon-managed vars only; add Function secrets to that file. All declared Function env keys must be present. Omit a key from `neon.ts` if you do not want to write it. `undefined` means you asked to write the key and the value is missing (`defineConfig` throws). Never coerce a missing `process.env` value to an empty string: that uploads `\"\"` and deletes the live key. An empty assignment in the file (`KEY=`) is also `\"\"`. If TypeScript needs an assertion, use `process.env.X!` and make sure the file has the value:\n\n```typescript\nfunctions: {\n todos: {\n name: \"todo api\",\n source: \"src/index.ts\",\n env: { RESEND_API_KEY: process.env.RESEND_API_KEY! },\n },\n}\n```\n\n`neon functions deploy --env KEY=VALUE` is the manual path (repeatable; `--env KEY=` deletes a key; unmentioned keys carry over). Use it for a targeted env update, not a full `neon.ts` apply.\n\nLoad Function secrets into the same file env pull wrote, then `neon deploy --env `. Pull the branch's Neon-managed vars onto disk for local dev with `neon env pull` (`link`/`checkout` do this automatically; pass `--no-env-pull` to skip and use `neon-env run -- ` for runtime injection). Limits: ≤1,000 vars, ≤64 KiB total, and the `NEON_` prefix is reserved.\n\n## Connecting to Postgres\n\nWhen the branch has Postgres, Neon **injects the connection strings at runtime** — you don't declare them, pass them at deploy time, or hardcode anything. The two you'll use:\n\n- `DATABASE_URL` — **pooled** connection string (routed through Neon's connection pooler). Use it for normal request/response query traffic. Kept un-prefixed because every Postgres ORM (Drizzle, Prisma, Knex, …) reads `DATABASE_URL` by default.\n- `DATABASE_URL_UNPOOLED` — **direct** connection string to the same database. Use it for migrations, `LISTEN`/`NOTIFY`, and long multi-statement transactions.\n\n**Use Drizzle (or another ORM) on top of node-postgres (`pg`)** for queries and schema management — not Neon's serverless driver. Functions are long-running and reuse an isolate across many requests, so a persistent `pg` pool is the right fit; the serverless driver's HTTP transport is meant for fully isolated, lambda-style runtimes.\n\nCreate the connection pool **once at module scope** and reuse it across requests — don't open a connection per request:\n\n```typescript\nimport { attachDatabasePool } from \"@neon/functions\";\nimport { drizzle } from \"drizzle-orm/node-postgres\";\nimport { Pool } from \"pg\";\n\nconst pool = new Pool({ connectionString: process.env.DATABASE_URL, max: 5 });\nattachDatabasePool(pool);\nconst db = drizzle(pool);\n```\n\nnode-postgres emits idle-client failures as `error` on the pool. With no listener that is an `uncaughtException` and Node exits the isolate. Call `attachDatabasePool(pool)` once after `new Pool`. Requires `@neon/functions` ≥ 0.8.0. Expected idle disconnects (`ECONNRESET`, `EPIPE`, `ETIMEDOUT`, Postgres `57P01`, node-postgres's `Connection terminated unexpectedly`) are silent. Anything else is `console.error`, or `onUnexpectedError` if you pass it on the first call. The first call wins; a later call that passes `onUnexpectedError` is ignored and warns. This does not close the pool.\n\n**Pooling is recommended because an isolate is reused across many requests** (and several requests can be in flight on the same isolate at once — see [Timeouts and Runtime Limits](#timeouts-and-runtime-limits)). A module-scope pool is opened once on cold start and then shared by every subsequent request that isolate serves, so you amortize connection setup instead of paying it on every request and you avoid exhausting Postgres connections under load.\n\nKeep `max` small (e.g. `5`): each isolate keeps its own pool, so total connections to Postgres scale with the number of live isolates. You don't need to close the pool on shutdown — when the runtime evicts an isolate it sends `SIGINT`/`SIGTERM`, and Neon's pooler reclaims those connections for you, so an explicit drain handler is redundant.\n\n> Reading `process.env.DATABASE_URL` directly works everywhere. The function in [Setup](#setup) instead uses `@neon/env`'s `parseEnv(config)` to read the same value in a typed, validated way — either is fine.\n\n## Timeouts and Runtime Limits\n\nFunctions are long-running but **still serverless** — they are a request/response runtime, not a background job runner. The hard limits:\n\n- **Time to first byte: 15 minutes.** Your handler must _begin_ returning a response within 15 minutes of receiving a request. Most handlers finish in seconds; the 15-minute ceiling exists so agent workloads like image/video generation have room.\n- **Heartbeat: 15 minutes.** Open WebSocket/SSE connections stay alive as long as data flows. The timeout only fires when a connection goes silent — send at least one byte every 15 minutes to keep a quiet stream alive.\n- **`waitUntil`: 15 minutes.** Work registered with `waitUntil` (from `@neon/functions`) keeps the invocation alive after the response is sent, up to 15 minutes — for cleanup like analytics writes and audit logs, **not** a background job runner. Off the Neon runtime (local `neon dev`, tests) it's a no-op: the promise still runs but isn't tracked.\n- **Idle eviction.** With no active connections Neon shuts the function down; it may also evict/restart for operational reasons — e.g. maintenance, or moving the function to a different compute node (active functions can run for hours first). Treat eviction like a process restart — WebSocket/SSE clients must reconnect. Neon sends `SIGINT` before evicting, so a `process.on(\"SIGINT\", ...)` handler lets you detect that the function is about to be evicted and run any last-minute cleanup. You don't need one just to close Postgres connections — Neon's pooler reclaims those on its own.\n- **Runtime:** Node.js 24, memory fixed at 2048 MiB. Slugs must match `^[a-z0-9]{1,20}$`. **An isolate is reused across many requests** — multiple requests can be in flight on the same isolate at once (interleaved on Node's single-threaded event loop), and under load the runtime runs several isolates in parallel, each with its own copy of module state. State held in module scope is therefore per-isolate (shared by every request that isolate handles) and in-memory only — persist anything that must survive eviction in Postgres. This reuse is exactly why you create a connection pool once at module scope rather than per request (see [Connecting to Postgres](#connecting-to-postgres)).\n\n## Functions as an Agent Backend (Next.js and Similar Frameworks)\n\nA Neon Function is a great home for an AI agent precisely because it **doesn't time out** the way lambda-style serverless does (15-minute budget, see [Timeouts and Runtime Limits](#timeouts-and-runtime-limits)). Proxying that stream through a Next.js route handler, Remix/SvelteKit/Nuxt action, or similar hosted on Vercel, Netlify, and the like **cuts the stream when it exceeds that host's configured duration or transport limits**, even though the Function would keep going. Keep the client-direct JWT path below as the default. A streaming-compatible proxy (HTTP-triggered Cloudflare Worker, after you verify the stream) is the public-consumer exception in [Production hardening](references/production-hardening.md).\n\n**Building the agent itself.** The [Vercel AI SDK](https://ai-sdk.dev) and [Mastra](https://mastra.ai) are the recommended ways to build the agent — point either at the Neon AI Gateway (see the `neon-ai-gateway` skill) for one credential across every model, with no extra provider keys. For a complete AI SDK agent running as a Function (streaming `toUIMessageStreamResponse`, multi-step tool calling next to Postgres, and persisting generated images to Object Storage), see [references/ai-sdk.md](https://neon.com/docs/ai/skills/neon-functions/references/ai-sdk.md); for the Mastra equivalent with built-in tracing, see [references/mastra-studio.md](https://neon.com/docs/ai/skills/neon-functions/references/mastra-studio.md).\n\n**The fix: call the function directly from the client.** Don't route the long request through your app server.\n\n```\nBrowser ──(Authorization: Bearer )──▶ Neon Function (agent) ✅ no host timeout\nBrowser ──▶ your app backend ──▶ Neon Function ❌ host cuts the stream\n```\n\n- Get a **short-lived bearer token** from the identity the app already uses. Do not switch Clerk, Better Auth, Auth.js, Supabase Auth, or Managed Auth in order to call a Function.\n - Managed Auth, default client (`createAuthClient` / Next wrapper): `authClient.token()`, then `data.token`. Verify with injected `NEON_AUTH_JWKS_URL` and issuer `new URL(process.env.NEON_AUTH_BASE_URL!).origin`.\n - Managed Auth with `SupabaseAuthAdapter()`: that client has no `.token()`. Use `getSession()`, then `data.session.access_token`. Same JWKS/issuer as above.\n - Existing Better Auth / Auth.js / other signer that already publishes JWKS: use that JWKS URL, issuer, and audience. Inspect the installed contract; cookie or database sessions are not a JWKS.\n - Cookie/database sessions only: mint a short token on the existing app backend (that call is fast and stays within host limits), then the browser calls the Function **directly** with `Authorization: Bearer`. The Function stream must not go through the app host.\n- Hand the token to the client, e.g. with the Vercel AI SDK: `new DefaultChatTransport({ api: NEON_FUNCTION_URL, fetch })` where `fetch` attaches `Authorization: Bearer `. Your app server is never in the path of the long stream.\n- Add **CORS** so the browser can reach it (handle `OPTIONS`, set `Access-Control-Allow-Origin`/`-Headers`).\n\n> [!WARNING]\n> A Neon Function has a **public HTTPS URL — it is reachable by anyone.** A direct client→function call means there is no app backend in front of it to gate access, so **you must authenticate the function yourself.** Verify a JWT against the caller's JWKS, check a shared secret / API key, or reject the request. Never deploy an unauthenticated agent. Browser callers use short-lived user tokens. Server or proxy origin secrets (`X-Secret`) stay server-side; see [Production hardening](references/production-hardening.md).\n\n```typescript\n// src/index.ts — verify the caller before doing any work\nimport { createRemoteJWKSet, jwtVerify } from \"jose\";\n\nconst jwks = createRemoteJWKSet(new URL(process.env.NEON_AUTH_JWKS_URL!));\nconst issuer = new URL(process.env.NEON_AUTH_BASE_URL!).origin;\n\nexport default {\n async fetch(request: Request) {\n if (request.method === \"OPTIONS\")\n return new Response(null, { status: 204, headers: cors(request) });\n\n const auth = request.headers.get(\"authorization\");\n if (!auth?.toLowerCase().startsWith(\"bearer \")) {\n return new Response(\"Unauthorized\", {\n status: 401,\n headers: cors(request),\n });\n }\n let userId: string;\n try {\n const { payload } = await jwtVerify(auth.slice(7), jwks, { issuer });\n if (!payload.sub) {\n return new Response(\"Unauthorized\", {\n status: 401,\n headers: cors(request),\n });\n }\n userId = payload.sub;\n } catch {\n return new Response(\"Unauthorized\", {\n status: 401,\n headers: cors(request),\n });\n }\n // Authorize resource access by userId, then run the agent scoped to that user.\n // ... return result.toUIMessageStreamResponse({ headers: cors(request) })\n },\n};\n```\n\nThat snippet is Managed Auth verification. Mint the bearer token with `.token()` (`data.token`) on the default client, or `getSession()` then `data.session.access_token` on `SupabaseAuthAdapter()`. For another identity, pass that app's JWKS URL and issuer through Function `env` (see [Environment Variables](#environment-variables)) and include `audience` only when that token contract requires it. https://neon.com/docs/compute/functions/authentication.md\n\nA valid token is not permission to read another user's rows. Exercise two users: each can access their own data; cross-user access is denied. Repeat after restarting the Function against stored rows. A request-supplied owner id cannot grant access.\n\nPersist anything you need to keep (generated images, history) in Postgres — module state doesn't survive eviction.\n\n## WebSocket Servers\n\nA WebSocket server is the canonical Functions workload: a long-running handler holds connections open in-process, with no external state store needed to keep a stream coherent. The connection stays alive as long as bytes flow (15-minute heartbeat, see [Timeouts](#timeouts-and-runtime-limits)).\n\n**Upgrade from inside `fetch`.** Call `upgradeWebSocket(request)` from [`@neon/functions`](https://www.npmjs.com/package/@neon/functions) and return the response it gives you. Hono apps use the same primitive via `@neon/functions/hono` (see [Hono](#hono) below). There is one entrypoint and no WebSocket dependency to install:\n\n```typescript\nimport { upgradeWebSocket } from \"@neon/functions\";\n\nexport default {\n async fetch(req: Request): Promise {\n if (req.headers.get(\"upgrade\")?.toLowerCase() !== \"websocket\") {\n return new Response(\"expected a websocket upgrade\", { status: 426 });\n }\n\n const { socket, response } = upgradeWebSocket(req);\n socket.addEventListener(\"message\", (event) => socket.send(event.data));\n return response;\n },\n};\n```\n\n`socket` is a standard [`WebSocket`](https://developer.mozilla.org/en-US/docs/Web/API/WebSocket), so `addEventListener` and the `onopen`/`onmessage`/`onclose`/`onerror` properties both work. It is still `CONNECTING` when you get it — the runtime writes the `101` only once your handler returns `response`, and the socket opens then.\n\nThree rules that matter:\n\n- **Return `response` unchanged.** A `101` can't be built as a plain `Response` (the fetch spec caps constructed responses at 200–599), so the runtime hands back an object carrying the pending upgrade. `clone()`, or rebuilding it with `new Response(res.body, res)` as response-rewriting middleware does, discards the upgrade and fails the request.\n- **Refuse a handshake by returning an ordinary `Response`.** Return a `401`, `403`, or `404` from `fetch`, before you upgrade, to gate a socket. A browser client can't read why a handshake was refused; it sees only a generic connection failure, not your status or body. Refuse to keep clients out, but send any detail the client needs over a separate authenticated request.\n- **`binaryType` defaults to `\"arraybuffer\"`**, not the browser's `\"blob\"`. `event.data` is a `string` for text frames and an `ArrayBuffer` for binary ones, so branch on `typeof`.\n\n**With auth.** Browsers can't set headers on a WebSocket, so authenticate with a `?token=` query param (verify it the same way as the [agent backend](#functions-as-an-agent-backend-nextjs-and-similar-frameworks): `jwtVerify` against your JWKS) and refuse before upgrading:\n\n```typescript\n// src/index.ts\nimport { upgradeWebSocket } from \"@neon/functions\";\n\nconst clients = new Set();\n\nexport default {\n async fetch(request: Request): Promise {\n if (request.headers.get(\"upgrade\")?.toLowerCase() !== \"websocket\") {\n return new Response(\"WebSocket endpoint — connect with ?token=\");\n }\n\n const url = new URL(request.url);\n const identity = await verifyToken(url.searchParams.get(\"token\"));\n if (!identity) return new Response(\"unauthorized\", { status: 401 });\n\n const { socket, response } = upgradeWebSocket(request);\n clients.add(socket);\n socket.addEventListener(\"close\", () => clients.delete(socket));\n socket.addEventListener(\"message\", (event) => {\n if (typeof event.data !== \"string\") return;\n persist(identity.id, event.data); // fan out to every isolate — see below\n });\n return response;\n },\n};\n```\n\n**Subprotocols.** Pass `{ protocol }` to select one the client offered; it is echoed in `Sec-WebSocket-Protocol` and exposed as `socket.protocol`. Selecting one the client did not offer throws a `TypeError`. Omit it and no protocol is negotiated. No extensions are negotiated either — `socket.extensions` is always `\"\"` and `permessage-deflate` is not available.\n\n**Hono.** Use `upgradeWebSocket` from `@neon/functions/hono` — the same primitive as Hono's own WebSocket helper, with no `ws` dependency and not the deprecated `@hono/node-ws`. Auth is ordinary middleware; gate upgrade requests before `next()`:\n\n```typescript\n// src/index.ts\nimport { Hono } from \"hono\";\nimport { upgradeWebSocket } from \"@neon/functions/hono\";\n\nconst clients = new Set();\n\nconst app = new Hono<{ Variables: { userId: string } }>();\n\napp.use(\"/ws\", async (c, next) => {\n const identity = await verifyToken(c.req.query(\"token\"));\n if (!identity) return c.text(\"Unauthorized\", 401);\n c.set(\"userId\", identity.id);\n await next();\n});\n\napp.get(\n \"/ws\",\n upgradeWebSocket((c) => ({\n onOpen(_event, ws) {\n clients.add(ws.raw);\n ws.send(\"welcome\");\n },\n onClose(_event, ws) {\n clients.delete(ws.raw);\n },\n onMessage(event, ws) {\n ws.send(`echo: ${event.data}`);\n },\n })),\n);\n\nexport default app;\n```\n\nConnect from the browser with the function's `wss://` URL (from `neon functions get `), for example `new WebSocket(\"wss://-.compute..aws.neon.tech/ws?token=\")`. Reconnect on close — isolates are evictable and idle connections may be terminated after 15 minutes.\n\nDo not put `cors()` on the upgrade route, and do not read `c.res` before `await next()` or call `c.header()` after it — both rebuild the `101` and break the upgrade. See `@neon/functions` README for the full middleware table.\n\n### Heartbeat (keep the socket alive)\n\nA connection stays open **only while bytes flow**: Neon evicts a silent stream after 15 minutes ([Timeouts and Runtime Limits](#timeouts-and-runtime-limits)), and intermediary proxies / load balancers are usually far stricter (often tens of seconds). Don't rely on the app being chatty enough — send a periodic keepalive from the server so the socket never goes quiet.\n\nThe standard `WebSocket` interface has no `ping()`, so send an application-level message the client filters out:\n\n```typescript\nconst HEARTBEAT_MS = 25_000; // comfortably under proxy idle timeouts\n\nconst beat = setInterval(() => {\n for (const socket of clients) {\n if (socket.readyState === socket.OPEN) socket.send('{\"type\":\"ping\"}');\n }\n}, HEARTBEAT_MS);\nbeat.unref?.();\n```\n\nThe client skips these when handling messages. There is no protocol-level shortcut here: the standard `WebSocket` from `upgradeWebSocket` has no `ping()`, and a browser can't send ping frames from JavaScript, so an application-level message is the only keepalive a browser client can use. (A Node `ws` client can send ping frames, and the server auto-replies with a pong, but a browser can't.)\n\n### Keeping clients in sync across isolates (do not skip this)\n\nUnder load the runtime runs **several isolates in parallel, each with its own copy of module state** — so each isolate has its own `clients` set. Broadcasting only to that local set means a client on isolate A never sees an event produced on isolate B, and the feed silently fractures. It's easy to miss: `neon dev` runs a single process (one isolate), so in-process broadcast always _looks_ fine locally but breaks in production, where concurrent connections spread across many isolates.\n\nModule state doesn't survive eviction anyway, so **Postgres is the shared source of truth**. Pick a fan-out strategy. In every snippet below, `pool` is a pooled `pg` client and `clients` is this isolate's `Set` of live connections.\n\n**1. Poll Postgres — the default, and the only option that keeps Scale to Zero.** Each isolate re-reads the shared state (or rows past a cursor) on a short interval and pushes changes to its own clients. One query per isolate per tick (not per client), and none when the isolate has no clients — so an idle compute still suspends.\n\n```typescript\nlet lastId = \"0\"; // bigint id, so a string\nlet polling = false;\n\nasync function poll() {\n if (polling || clients.size === 0) return; // guard overlap; no clients → no query → compute can scale to zero\n polling = true;\n try {\n const { rows } = await pool.query(\n \"SELECT id, payload FROM events WHERE id > $1 ORDER BY id\",\n [lastId],\n );\n for (const { id, payload } of rows) {\n lastId = id;\n for (const socket of clients) {\n if (socket.readyState === socket.OPEN) socket.send(payload);\n }\n }\n } catch (err) {\n console.error(\"[poll]\", err);\n } finally {\n polling = false;\n }\n}\n\n// Seed from the latest id so a fresh isolate sends only new rows, not the whole table, then poll.\npool\n .query(\"SELECT coalesce(max(id), 0)::text AS id FROM events\")\n .then((seed) => {\n lastId = seed.rows[0].id;\n })\n .catch((err) => console.error(\"[seed]\", err))\n .finally(() => setInterval(poll, 1000).unref?.());\n```\n\n- **Latency:** up to the interval (~1s) — fine for counters, chat, and dashboards.\n- **Scaling:** database load grows with the number of live isolates, not clients. Keep the cursor on an indexed `serial`/`bigserial` PK and the interval sane.\n- **Scale to Zero:** ✅ preserved — polling stops when no clients are connected, so the compute suspends on its normal timer.\n- **Ordering:** `WHERE id > cursor` can skip a row that commits out of sequence: a transaction that took a lower id but commits after a higher one is already behind the cursor, so the poll never returns it. For a broadcast feed occasional loss is usually fine; when you need every row, use `LISTEN`/`NOTIFY` or poll by `created_at` with a small overlap window and dedupe by id.\n\n**2. `LISTEN`/`NOTIFY` — lowest latency, but requires disabling Scale to Zero.** Each isolate `LISTEN`s on a channel over a dedicated **unpooled** connection; broadcasting is `NOTIFY`, so every isolate (including the sender's) re-pushes to its sockets. Near-instant — but the listener holds an idle connection that **does not count as active**, so [Scale to Zero](https://neon.com/docs/introduction/scale-to-zero) suspends the compute and drops it, silently killing the feed. Only use it on an **always-on** compute (Scale to Zero disabled — a paid-plan setting).\n\n```typescript\nimport { attachDatabasePool } from \"@neon/functions\";\nimport { Pool, Client } from \"pg\";\n\nconst pool = new Pool({ connectionString: process.env.DATABASE_URL, max: 5 });\nattachDatabasePool(pool);\nconst CHANNEL = \"chat_events\";\n\n// One dedicated DIRECT connection per isolate, just to receive events.\n// Use DATABASE_URL_UNPOOLED — LISTEN needs a real session, not a pooled one.\n// Don't call attachDatabasePool here: it would silence the idle drop that killed the feed.\n// The error listener keeps the process alive; reconnect the client on error in production (omitted here).\nconst listener = new Client({\n connectionString: process.env.DATABASE_URL_UNPOOLED,\n});\nlistener.on(\"error\", (err) => {\n console.error(err);\n});\nlistener.connect().then(() => listener.query(`LISTEN ${CHANNEL}`));\nlistener.on(\"notification\", (msg) => {\n if (!msg.payload) return;\n for (const socket of clients) {\n if (socket.readyState === socket.OPEN) socket.send(msg.payload);\n }\n});\n\n// Broadcast by NOTIFYing through the pool — every isolate's listener fires.\nfunction broadcast(event: unknown) {\n return pool.query(\"SELECT pg_notify($1, $2)\", [\n CHANNEL,\n JSON.stringify(event),\n ]);\n}\n```\n\n**3. External pub/sub (e.g. [Upstash](https://upstash.com) Redis) — best at scale.** For high fan-out, sub-second latency at large connection counts, or multi-region, publish/subscribe through a dedicated broker. Highest throughput, and it doesn't touch Postgres or block Scale to Zero — at the cost of another service to run.\n\n**Rule of thumb:** start with **polling** (works with Scale to Zero, no extra infra); switch to `LISTEN`/`NOTIFY` only on always-on compute that needs sub-second latency; move to Redis when fan-out outgrows Postgres.\n\n### Client must reconnect\n\nIdle functions are evicted (and isolates restart for operational reasons), so a client's socket **will** drop — treat reconnection as normal, not exceptional. Reconnect with exponential backoff, capped, and **re-mint a fresh token on every attempt** (tokens are short-lived, so a stale one fails the `upgrade` auth check):\n\n```typescript\nlet closed = false,\n retry = 0,\n timer: ReturnType;\n\nasync function connect() {\n if (closed) return;\n const token = await getToken(); // re-mint each attempt; short-lived\n const ws = new WebSocket(`${WS_URL}?token=${encodeURIComponent(token)}`);\n ws.onopen = () => {\n retry = 0; // reset backoff on success\n };\n ws.onmessage = (e) => {\n /* apply the event */\n };\n ws.onclose = () => {\n if (!closed)\n timer = setTimeout(connect, Math.min(1000 * 2 ** retry++, 15000));\n };\n ws.onerror = () => ws.close(); // let onclose drive the retry\n}\nconnect();\n```\n\nTogether — `upgradeWebSocket` inside `fetch`, JWT auth over `?token=`, cross-isolate fan-out, and client backoff — these compose into a complete realtime chat backend on a single function.\n\n## Server-Sent Events (SSE)\n\nWhen you only need **server → client** streaming (live counters, notifications, progress, token streams), SSE is simpler than a WebSocket and needs no upgrade at all: a plain `fetch` handler returns a `Response` whose body is a `ReadableStream` with `Content-Type: text/event-stream`, and the runtime holds it open as long as bytes flow. The browser consumes it with `EventSource`, which **reconnects on its own** — so there's no client backoff to write.\n\n```typescript\n// src/index.ts — minimal SSE endpoint\nconst encoder = new TextEncoder();\nexport default {\n fetch: () => {\n let t: ReturnType;\n return new Response(\n new ReadableStream({\n start(controller) {\n controller.enqueue(encoder.encode(\"data: hello\\n\\n\"));\n t = setInterval(\n () => controller.enqueue(encoder.encode(\": ping\\n\\n\")),\n 25_000,\n );\n },\n cancel() {\n clearInterval(t); // fires when the client disconnects\n },\n }),\n {\n headers: {\n \"Content-Type\": \"text/event-stream\",\n \"Cache-Control\": \"no-cache, no-transform\",\n },\n },\n );\n },\n};\n```\n\nThe same rules as WebSockets apply. **Heartbeat:** a stream stays open only while bytes flow — Neon's window is 15 minutes ([Timeouts and Runtime Limits](#timeouts-and-runtime-limits)) but proxies are usually far stricter, so emit a `: ping\\n\\n` comment every ~25–30s (shown above) to keep idle streams from being dropped. Keep state in Postgres, and fan out across isolates using one of the [sync strategies](#keeping-clients-in-sync-across-isolates-do-not-skip-this) (hold a `Set` of stream controllers and `enqueue` to each). `EventSource` is GET-only and can't set headers, so authenticate with a `?token=` query param or cookie, exactly like the WebSocket case. [references/sse.md](https://neon.com/docs/ai/skills/neon-functions/references/sse.md) has the full pattern — Hono variant, cross-isolate fan-out, wire format, client, and caveats.\n\n## Function Triggers\n\nA Function Trigger POSTs JSON to your function on a cron (`schedule`) or when an object is created in Object Storage (`storage_object_created`). Declare it in `neon.ts`, apply with `neon deploy`, and authenticate the delivery with `parseTriggerDelivery` (`@neon/functions/triggers`). `parseTrigger` (Hono) and `parseTriggerInvocation` stay schedule-only. Prefer `neon.ts`; CLI and the Neon MCP trigger tools (`list_triggers`, `create_trigger`, …) are the backup.\n\nTrigger routes must not require a user JWT or `X-Secret`; Neon POSTs to the native URL without those. Production caller shapes: [references/production-hardening.md](references/production-hardening.md). Full field list, CLI, MCP, payload, inheritance, and both handler shapes: [references/function-triggers.md](references/function-triggers.md).\n\n## MCP Servers\n\nAn [MCP](https://modelcontextprotocol.io) server is a natural Functions workload: a long-running HTTP handler that exposes tools to AI clients (Cursor, Claude, ChatGPT, agents), with those tools reading and writing the branch's Postgres right next to the compute. MCP's **streamable HTTP transport** is a plain `POST`/`GET` on a single endpoint (conventionally `/mcp`), so it maps onto a function's `fetch` handler with no `upgrade` method or extra protocol.\n\nThe simplest host is a Hono app using the official [`@modelcontextprotocol/sdk`](https://github.com/modelcontextprotocol/typescript-sdk) plus [`@hono/mcp`](https://github.com/honojs/middleware/tree/main/packages/mcp), which bridges the transport to a route. Build the server, register its tools, and create the transport once at module scope, then hand every `/mcp` request to it:\n\n```typescript\nconst transport = new StreamableHTTPTransport();\napp.all(\"/mcp\", async (c) => {\n if (!mcpServer.isConnected()) await mcpServer.connect(transport);\n return transport.handleRequest(c);\n});\n```\n\nBecause the function's URL is public, **authenticate before connecting the transport** — [Better Auth](https://better-auth.com) covers both OAuth (its MCP plugin makes your app the authorization server so third-party clients self-authorize per the MCP spec) and a simpler API-key / session-JWT check for your own callers. Public-consumer edge protection: [references/production-hardening.md](references/production-hardening.md). [references/mcp.md](https://neon.com/docs/ai/skills/neon-functions/references/mcp.md) has the full pattern — server with Postgres-backed tools via Drizzle, both Better Auth auth options, and testing with `mcporter` / `add-mcp`.\n\n## Integrations and Observability\n\n### Built-in branch logs\n\n```bash\nneon logs query --branch production --source function --since 1h\n```\n\nFunctions is one of the two sources branch logs cover today, alongside Object Storage. Logs are scoped to a single branch, so pass `--branch` when the deployed function isn't on the branch you're checked out on. Everything else about logs — the required CLI version, filters, the SDK, and the Loki-compatible read API — is in the parent `neon` skill's **Observability** section.\n\n### Application instrumentation\n\nA function is a long-lived Node.js process running a web-standard request/response handler, so standard Node integration SDKs work unchanged. Initialize them once at module load, gated on an env var so local dev and unconfigured branches stay a no-op, and pass secrets via `--env` or `neon.ts` `env`.\n\n- **Sentry** — error monitoring across the HTTP framework, the function runtime, and an agent's own caught/fallback failures (the long-running case Functions target): see [references/sentry.md](https://neon.com/docs/ai/skills/neon-functions/references/sentry.md).\n- **Mastra Studio (Mastra Cloud)** — run a Mastra agent on a function and ship its traces to a Studio project for observability: see [references/mastra-studio.md](https://neon.com/docs/ai/skills/neon-functions/references/mastra-studio.md).\n\n## Neon Documentation\n\nThe Neon documentation is the source of truth and Functions is evolving rapidly, so always verify against the official docs. Any doc page can be fetched as markdown by appending `.md` to the URL or by requesting `Accept: text/markdown`. Find the right page from the docs index (https://neon.com/docs/llms.txt) and the changelog announcements.\n\n## Further Reading\n\n- https://neon.com/docs/compute/functions/overview.md\n- https://neon.com/docs/compute/functions/get-started.md\n- https://neon.com/docs/compute/functions/deploy.md\n- https://neon.com/docs/compute/functions/environment-variables.md\n- https://neon.com/docs/compute/functions/reference/neon-ts.md\n- https://neon.com/docs/compute/functions/reference/runtime-limits.md\n- https://neon.com/docs/compute/functions/authentication.md\n- https://neon.com/docs/compute/functions/custom-domains.md\n- https://neon.com/docs/cli/triggers.md\n- [references/function-triggers.md](references/function-triggers.md)\n- [references/production-hardening.md](references/production-hardening.md)\n" }, { "url": "https://hyperframes.heygen.com/.well-known/llms.txt", "domain": "hyperframes.heygen.com", "endpoint": "/.well-known/llms.txt", "filename": "llms.txt", "content": "# HyperFrames\n\n## Guides\n\n### Start here\n\n- [What is HyperFrames?](https://hyperframes.heygen.com/introduction.md): See what an AI agent can make with ordinary web technology.\n- [Make your first video](https://hyperframes.heygen.com/quickstart.md): Install the HyperFrames skills, make one short request, and continue with your agent, Studio, or the CLI.\n- [Go further with HyperFrames](https://hyperframes.heygen.com/go-further.md): Take more control of an existing project through your agent, Studio, richer composition tools, and a reliable finish.\n- [Build on HyperFrames](https://hyperframes.heygen.com/developers/index.md): Choose the smallest HyperFrames surface for automation, editing, playback, rendering, or generated compositions.\n\n### Explore\n\n- [Examples](https://hyperframes.heygen.com/examples.md): Watch finished HyperFrames videos, inspect real production projects, or start from a working template.\n- [30 Days of HyperFrames](https://hyperframes.heygen.com/thirty-days.md): The official 30 Days of HyperFrames lessons, collected in one place as the series is published.\n- [Product updates](https://hyperframes.heygen.com/product-updates.md): The HyperFrames changes that matter when you create, edit, and render projects.\n- [Weekly updates](https://hyperframes.heygen.com/weekly-updates.md): Curated weekly highlights for HyperFrames.\n- [Changelog](https://hyperframes.heygen.com/changelog.md): Release notes for HyperFrames.\n\n### Choose where to create\n\n- [Choose how to create](https://hyperframes.heygen.com/guides/choose-creation-path.md): Four places to make a HyperFrames video, and how to tell which one is yours.\n- [Create through an AI chat](https://hyperframes.heygen.com/guides/mcp.md): Use the hosted HyperFrames MCP connector to create and render without installing the local CLI.\n- [Bring a design into a project](https://hyperframes.heygen.com/guides/design-tools.md): Start from a Figma file or a design-tool draft. Keep the look, rebuild only what has to move.\n\n### Prompt Guide\n\n- [Prompt Guide](https://hyperframes.heygen.com/prompting/overview.md): How to prompt AI agents to author HyperFrames videos — setup, the two prompt shapes, and the map of this guide.\n\n#### Level 1 — Your first video\n\n- [Product launch videos](https://hyperframes.heygen.com/prompting/product-launch.md): What to say to turn a product URL, a script, or a brief into a launch or promo video — and when to reach for a site tour instead.\n- [Explainers](https://hyperframes.heygen.com/prompting/explainers.md): What to say to turn an article, notes, or a topic into a faceless explainer — where every visual is invented, not captured.\n- [Code changes and PRs](https://hyperframes.heygen.com/prompting/code-and-prs.md): What to say to turn a GitHub pull request into a code-change explainer — changelog, feature reveal, fix, or refactor walkthrough.\n- [Captions and talking-head footage](https://hyperframes.heygen.com/prompting/captions-and-talking-heads.md): Two ways to dress an existing talking-head clip — readable captions or designed graphic overlays — both leaving the footage itself untouched.\n- [Music videos and slideshows](https://hyperframes.heygen.com/prompting/music-and-slideshows.md): Two music- and slide-driven outputs that look alike in a brief but ship differently — a beat-synced MP4 versus a navigable deck — and how to route to the right one.\n- [Motion graphics](https://hyperframes.heygen.com/prompting/motion-graphics.md): Short, design-led pieces where motion is the message — kinetic type, a stat hit, a logo sting — and the knobs that decide MP4 versus transparent overlay.\n\n#### Level 2 — Control\n\n- [Anatomy of a one-shot prompt](https://hyperframes.heygen.com/prompting/anatomy.md): The six-part skeleton — route, spec, beats, copy, technique, negatives — that removes the decisions agents most often get wrong.\n- [The specification dial](https://hyperframes.heygen.com/prompting/specification-dial.md): Spec density controls how far the result drifts from what you imagined — not whether it works.\n- [Vocabulary that changes output](https://hyperframes.heygen.com/prompting/vocabulary.md): Natural-language adjectives the skills map to specific framework settings — easing, captions, transitions, audio, voices.\n- [High-fidelity looks](https://hyperframes.heygen.com/prompting/visual-specs.md): Write a visual spec that names, places, colors, and times every element, so words alone carry a specific look.\n- [Verified example prompts](https://hyperframes.heygen.com/prompting/examples.md): Prompts that produced the videos on this page, plus the shared motion preamble each one was run with.\n\n#### Level 3 — Life\n\n- [Motion that reads premium](https://hyperframes.heygen.com/prompting/motion.md): Eight rules for motion that reads as premium: nothing stops, the camera acts, action overlaps, and imperfection stays reproducible.\n- [Transitions](https://hyperframes.heygen.com/prompting/transitions.md): Map energy and mood to named shader and CSS transition blocks, and prompt them per seam.\n\n#### Level 4 — Substance\n\n- [Code animations](https://hyperframes.heygen.com/prompting/code-blocks.md): Prompt code walkthroughs — typing, diffing, highlighting, scrolling — and pick a terminal or editor theme by name.\n- [Data and maps](https://hyperframes.heygen.com/prompting/data-and-maps.md): Prompt animated charts, count-up stats, and maps — highlight regions, draw flows, size bubbles — or hand-draw a chart for full control.\n- [Overlays and lower thirds](https://hyperframes.heygen.com/prompting/overlays-and-lower-thirds.md): Prompt named lower-third and social-post overlay blocks with timing, copy, and brand tone.\n- [Caption styles](https://hyperframes.heygen.com/prompting/captions-catalog.md): Map caption tone to named caption components, and prompt per-word emphasis for composed videos.\n- [When to generate artwork](https://hyperframes.heygen.com/prompting/generated-artwork.md): Code-drawn wins for UI, type, geometry, and 3D. Illustration-led hero art comes from an image model, animated as layers.\n- [Color grading and film effects](https://hyperframes.heygen.com/prompting/color-grading.md): Grade media with a fixed-order pipeline — tonal work, hue keys, print and analogue treatments — and know why the source matters more than the payload.\n- [VFX and liquid glass](https://hyperframes.heygen.com/prompting/vfx-and-liquid-glass.md): Prompt device mockups, liquid-glass UI, shatter/portal/magnetic moments, and ambient polish — and know which effects need the canvas pipeline.\n- [Runtimes and 3D](https://hyperframes.heygen.com/prompting/runtimes-and-3d.md): GSAP is the default and you rarely name it. Real 3D, existing animation files, and scene transitions each have a runtime worth pinning in the prompt.\n\n#### Level 5 — Voice and sound\n\n- [Media and audio](https://hyperframes.heygen.com/prompting/media-and-audio.md): Ask for the voiceover, music, sound, captions, cutouts, and assets a composition needs, in phrasing the media pipeline acts on.\n- [Audio effects and mixing](https://hyperframes.heygen.com/prompting/audio-effects.md): Ask for a mix in symptoms rather than in filters — make music step out of the way of narration, clean a voice, and know which requests have no honest answer.\n\n#### Level 6 — Scale\n\n- [Design systems and brand](https://hyperframes.heygen.com/prompting/design-systems.md): Point the agent at a source of brand truth — a design spec, a site, or a Figma file — instead of asking for 'on-brand', and let it compose the frame.\n- [Variables and templating](https://hyperframes.heygen.com/prompting/variables-and-templating.md): Ask for the parts that should change to become named slots, then re-render the same composition with different values — one output per record.\n- [Storyboards](https://hyperframes.heygen.com/prompting/storyboards.md): For multi-scene work, don't prompt the scenes one by one — prompt the plan: the arc, the per-frame beats, and the pacing rule the build follows to fill them in.\n- [Editing existing videos](https://hyperframes.heygen.com/prompting/editing-existing-videos.md): Direct the agent like an editor — trim, move, retime, swap, restyle — with the NLE verb you already know mapped to the prompt that lands it in one pass.\n- [Iterating](https://hyperframes.heygen.com/prompting/iterating.md): Talk to the agent like a video editor — small targeted edits beat re-specification.\n- [Recreating something you saw](https://hyperframes.heygen.com/prompting/recreating-references.md): Transcribe motion, iterate with absolute targets, distill the constants — and know where the text-only ceiling is.\n- [Rendering and output](https://hyperframes.heygen.com/prompting/rendering-and-output.md): What to say to get the right file out — quality tier, format, resolution, framerate, and cloud rendering — without over-speccing a render that slows to no benefit.\n- [Porting from Remotion](https://hyperframes.heygen.com/prompting/remotion-migration.md): What to say to migrate an existing Remotion (React) composition's source into HyperFrames HTML — and what to expect the agent to refuse.\n\n#### Level 7 — Capstone\n\n- [Capstone — every technique, one journey](https://hyperframes.heygen.com/prompting/capstone.md): One prompt, one unbroken camera move, and every technique in this guide joined into a single 62-second film.\n\n#### Appendix\n\n- [Rules and anti-patterns](https://hyperframes.heygen.com/prompting/rules-and-anti-patterns.md): The technical rules that keep renders correct, and the prompt patterns that cause friction.\n\n### Workflows\n\n- [Choose a workflow](https://hyperframes.heygen.com/workflows.md): Start from the material you already have.\n- [Create a product or website video](https://hyperframes.heygen.com/guides/product-launch-video.md): Turn a product URL or launch brief into a promo, product tour, or social video.\n- [Create a faceless explainer](https://hyperframes.heygen.com/guides/faceless-explainer.md): Turn notes, an article, or a difficult idea into a visual explanation without product footage.\n- [Turn a pull request into a video](https://hyperframes.heygen.com/guides/pr-to-video.md): Show what changed, why it matters, and what happens next.\n- [Add captions or repackage talking-head footage](https://hyperframes.heygen.com/guides/captions-and-recuts.md): Add captions, add designed overlays, or change the spoken edit.\n- [Create a motion graphic](https://hyperframes.heygen.com/guides/motion-graphics.md): Make a short, motion-led title, statistic, chart, logo sting, or overlay.\n- [Create a music-driven video](https://hyperframes.heygen.com/guides/music-to-video.md): Cut footage, images, lyrics, and motion to a track’s beat grid.\n- [Create an interactive presentation](https://hyperframes.heygen.com/guides/slideshow.md): Build a navigable deck with reveals, notes, optional branches, hotspots, and presenter mode.\n- [Create a custom video](https://hyperframes.heygen.com/guides/general-video.md): Combine sources, change existing footage, or co-direct a video when no focused workflow fits.\n- [HyperFrames or Remotion?](https://hyperframes.heygen.com/guides/hyperframes-vs-remotion.md): The same three-second title card written in Remotion React and in HyperFrames HTML, plus an honest read on which tool fits your project.\n\n### Build the project\n\n- [How a HyperFrames project works](https://hyperframes.heygen.com/concepts/index.md): Understand the editable files, compositions, timing, and tools behind a HyperFrames video.\n- [Work with media](https://hyperframes.heygen.com/guides/media.md): Use footage, images, audio, captions, backgrounds, and color in a HyperFrames project.\n- [Use images and video](https://hyperframes.heygen.com/guides/video-components.md): Import, place, replace, trim, and review images and footage in a HyperFrames project.\n- [Add an avatar presenter](https://hyperframes.heygen.com/guides/avatar-presenter.md): Create or reuse a presenter clip, keep it as project media, and combine it with editable HyperFrames scenes.\n- [Use voice, music, sound, and captions](https://hyperframes.heygen.com/guides/voice-and-audio.md): Build an understandable audio mix, transcribe real speech, and turn it into readable captions.\n- [Remove a background](https://hyperframes.heygen.com/guides/remove-background.md): Turn footage of a person or a portrait image into transparent media you can layer over a HyperFrames scene.\n- [Color grade images and footage](https://hyperframes.heygen.com/guides/color-grading.md): Fix exposure and color on an image or video, shape a look with wheels and curves, apply a LUT, and check the result against real measurements.\n- [Apply media effects](https://hyperframes.heygen.com/guides/media-effects.md): Turn an image or video into ASCII, halftone print, tape damage, CRT, painted art, and more — without touching the original file.\n- [Finish and share a video](https://hyperframes.heygen.com/guides/export-and-share.md): Review the project, run its checks, render through an agent, Studio, or the CLI, and deliver the right file or link.\n\n### Help\n\n- [Get unstuck](https://hyperframes.heygen.com/help.md): Start with what you can see, try the smallest useful fix, and get back to your HyperFrames task.\n- [Troubleshooting](https://hyperframes.heygen.com/guides/troubleshooting.md): Solve common Studio, project, media, animation, preview, and rendering problems.\n- [Share feedback](https://hyperframes.heygen.com/guides/feedback.md): Report a problem or tell the HyperFrames team what would make the product better.\n\n## Studio\n\n### Start in Studio\n\n- [Work on a project in Studio](https://hyperframes.heygen.com/studio/index.md): Open a HyperFrames project, understand the workspace, make a safe edit, and finish a version.\n\n### Edit\n\n- [Edit the frame](https://hyperframes.heygen.com/studio/canvas.md): Select the right element, change its content or design, arrange layers, and verify the result in motion.\n- [Edit timing on the timeline](https://hyperframes.heygen.com/studio/timeline.md): Move, trim, split, align, and inspect clips in HyperFrames Studio.\n- [Edit animation and keyframes](https://hyperframes.heygen.com/studio/animation.md): Read existing motion, add and retime keyframes, record gestures, shape paths, and handle generated animation.\n- [Edit captions](https://hyperframes.heygen.com/studio/captions.md): Review captions in context and understand which Studio edits are saved today.\n\n### Audio\n\n- [Mix audio and apply effects](https://hyperframes.heygen.com/studio/audio-effects.md): Open a track's effect rack, fix a voice with one preset, and add individual effects in an order that works.\n- [Make music sit under narration](https://hyperframes.heygen.com/studio/voiceover-carve.md): Take only the frequencies a voice occupies out of a music bed, so the music keeps its character while speech stays intelligible.\n- [Group tracks, mute, and solo](https://hyperframes.heygen.com/studio/audio-groups.md): Give several audio clips one set of effects, one fader, and one mute — and know which of mute and solo reaches the export.\n- [Automate a parameter over time](https://hyperframes.heygen.com/studio/audio-automation.md): Draw an envelope on a track's volume or an effect's knob, shape a selection, and know which parameters can move at all.\n\n### Build and reuse\n\n- [Use Assets and Catalog](https://hyperframes.heygen.com/studio/assets-and-blocks.md): Import project media, reuse existing files, and add ready-made visuals.\n- [Use variables and templates](https://hyperframes.heygen.com/studio/variables.md): Turn a visible value into a reusable input, preview variants, and hand the template off.\n- [Build a slideshow](https://hyperframes.heygen.com/studio/slideshows.md): Shape the main presentation, then add reveals, notes, branches, and hotspots where they help.\n\n### Finish and recover\n\n- [Export and manage renders](https://hyperframes.heygen.com/studio/export.md): Choose a format, quality, resolution, and frame rate, then manage the render queue.\n- [Studio troubleshooting](https://hyperframes.heygen.com/studio/troubleshooting.md): Recover from selection, preview, editing, timeline, and export problems.\n\n### Reference\n\n- [Work with source and an agent](https://hyperframes.heygen.com/studio/source.md): Edit project files, diagnose a failed check, and hand the right context to an AI agent.\n- [Keyboard shortcuts](https://hyperframes.heygen.com/studio/shortcuts.md): Use Studio shortcuts for playback, editing, navigation, and project actions.\n\n- [Catalog (388 pages)](https://hyperframes.heygen.com/_llms/catalog.md): Documentation for Catalog.\n\n## Developers\n\n### Start here\n\n- [How HyperFrames fits into an application](https://hyperframes.heygen.com/developers/overview.md): Understand the composition contract, editing surfaces, Player, CLI, and rendering layers before choosing an integration.\n\n### Command line\n\n- [CLI guide](https://hyperframes.heygen.com/developers/cli.md): Find the HyperFrames command for creating, checking, rendering, publishing, and automating projects.\n- [CLI](https://hyperframes.heygen.com/packages/cli.md): Create, preview, and render HTML video compositions from the command line.\n- [How catalog search works](https://hyperframes.heygen.com/developers/catalog-search.md): What `hyperframes catalog --query` does, the on-device model behind meaning search, what it downloads, and how its index is built.\n- [@hyperframes/lint](https://hyperframes.heygen.com/packages/lint.md): The composition linter as a standalone library — lint a directory or a single HTML file without the CLI.\n\n### SDK guides\n\n- [Edit a composition with the SDK](https://hyperframes.heygen.com/sdk/quickstart.md): Open composition HTML, query and edit elements, serialize the result, and add persistence.\n- [Querying & Editing Elements](https://hyperframes.heygen.com/sdk/guides/querying-and-editing.md): Find elements by property, make typed mutations, group edits with batch, and work with element handles and selection.\n- [Timing & Animation](https://hyperframes.heygen.com/sdk/guides/timing-and-animation.md): Set clip timing, elastic holds, GSAP tweens, and keyframed animations on composition elements.\n- [Undo, Redo & Patches](https://hyperframes.heygen.com/sdk/guides/undo-redo-and-patches.md): Use the SDK's built-in undo stack, subscribe to patch events, and integrate with a host application's own history.\n- [Persistence](https://hyperframes.heygen.com/sdk/guides/persistence.md): Autosave composition edits through pluggable adapters — filesystem, memory, or your own storage backend.\n- [Embedded Override Mode](https://hyperframes.heygen.com/sdk/guides/embedded-override-mode.md): Layer a sparse delta on top of a reusable base composition so the host stores only what changed.\n- [Canvas & Preview Integration](https://hyperframes.heygen.com/sdk/guides/canvas-integration.md): Connect a same-origin composition iframe to the SDK for hit-testing, draft preview, and selection.\n- [Editing Affordances](https://hyperframes.heygen.com/sdk/guides/editing-affordances.md): Resolve capability flags and inspector sections for a selected element so your editor panel is element-aware.\n\n### SDK reference\n\n- [openComposition](https://hyperframes.heygen.com/sdk/reference/open-composition.md): Open a composition HTML string for editing. Returns a Composition session.\n- [Composition](https://hyperframes.heygen.com/sdk/reference/composition.md): The main editing surface returned by openComposition — query, mutate, animate, and serialize a composition.\n- [Edit Operations](https://hyperframes.heygen.com/sdk/reference/edit-operations.md): The complete EditOp catalog for dispatch(), can(), and batch().\n- [Types](https://hyperframes.heygen.com/sdk/reference/types.md): Core types exported from @hyperframes/sdk, with pointers to the adapter, history, and persistence types.\n- [Adapters](https://hyperframes.heygen.com/sdk/reference/adapters.md): Persistence and preview adapter interfaces, contracts, and the built-in factory functions.\n- [Utilities & Constants](https://hyperframes.heygen.com/sdk/reference/utilities.md): History module, persist queue, document utilities, constants, and error types exported from @hyperframes/sdk.\n\n### Composition, design & animation\n\n- [Compositions](https://hyperframes.heygen.com/concepts/compositions.md): The fundamental building block of a Hyperframes video.\n- [Reuse a design with variables](https://hyperframes.heygen.com/concepts/variables.md): Change approved text, colors, media, and choices without rebuilding the composition.\n- [Time elements with data attributes](https://hyperframes.heygen.com/concepts/data-attributes.md): Place clips on the HyperFrames timeline without putting timing logic in JavaScript.\n- [Animate with GSAP](https://hyperframes.heygen.com/guides/gsap-animation.md): Create a paused timeline that HyperFrames can seek to any frame.\n- [Frame adapters](https://hyperframes.heygen.com/concepts/frame-adapters.md): Connect a seekable animation timeline to a custom HyperFrames host.\n- [Deterministic Rendering](https://hyperframes.heygen.com/concepts/determinism.md): Same input, identical output. Every time.\n- [HTML in Canvas](https://hyperframes.heygen.com/guides/html-in-canvas.md): Use live DOM content as a texture for WebGL and canvas effects.\n- [Per-pixel effects with data-vfx-chain](https://hyperframes.heygen.com/guides/vfx-chain.md): The data-vfx-chain attribute: a WebGL2 kernel chain for warps, displacement, and generated noise that repaints deterministically on every seek.\n- [Figma integration](https://hyperframes.heygen.com/guides/figma.md): Bring Figma designs into HyperFrames — frozen assets, brand tokens, editable components, storyboard reconstruction, and Figma Motion timelines translated to GSAP.\n\n### Composition reference\n\n- [HTML schema reference](https://hyperframes.heygen.com/reference/html-schema.md): The current contract for a HyperFrames composition.\n- [Color grading implementation](https://hyperframes.heygen.com/reference/color-grading.md): Persist, automate, animate, and spatially isolate media color grading.\n- [Audio effects implementation](https://hyperframes.heygen.com/reference/audio-effects.md): The four audio attributes, every effect and parameter, automation targets, the voiceover carve, audio groups, and how preview and render stay identical.\n- [Speed ramps](https://hyperframes.heygen.com/reference/speed-ramps.md): Change a clip's playback speed over time with a rate lane in data-automation. One curve drives the preview, the render and Studio.\n\n### Rendering paths\n\n- [Render from the command line](https://hyperframes.heygen.com/guides/rendering.md): Check a project and render MP4, MOV, WebM, GIF, or PNG output.\n- [Choose a rendering path](https://hyperframes.heygen.com/deploy/overview.md): Choose the smallest HyperFrames rendering surface for local work, an application backend, managed cloud, or infrastructure you operate.\n- [Cloud rendering](https://hyperframes.heygen.com/deploy/cloud.md): Render on HeyGen's managed cloud without deploying your own infrastructure.\n- [Deploy a preview and render API](https://hyperframes.heygen.com/guides/deploy.md): Start from an official Vercel, Cloudflare, or Modal template when you need a hosted preview and MP4 render endpoint.\n\n### Cloud infrastructure\n\n- [AWS Lambda](https://hyperframes.heygen.com/deploy/aws-lambda.md): Deploy distributed HyperFrames rendering to AWS Lambda and drive renders from a laptop or CI.\n- [Google Cloud Run](https://hyperframes.heygen.com/deploy/gcp-cloud-run.md): Deploy distributed HyperFrames rendering to Cloud Run, Cloud Workflows, and Google Cloud Storage.\n- [Render templates on Lambda](https://hyperframes.heygen.com/deploy/templates-on-lambda.md): Render one HyperFrames composition with different variable values, individually or from a JSONL batch.\n- [Migrating to HyperFrames Lambda](https://hyperframes.heygen.com/deploy/migrating-to-hyperframes-lambda.md): Side-by-side mapping for adopters coming to HyperFrames from another one-command-deploy video renderer.\n- [@hyperframes/aws-lambda](https://hyperframes.heygen.com/packages/aws-lambda.md): AWS Lambda and Step Functions adapter for distributed HyperFrames rendering.\n- [@hyperframes/gcp-cloud-run](https://hyperframes.heygen.com/packages/gcp-cloud-run.md): Google Cloud Run and Workflows adapter for distributed HyperFrames rendering.\n\n### Advanced rendering\n\n- [Render in 4K](https://hyperframes.heygen.com/guides/4k-rendering.md): Author at 4K or supersample an existing composition at render time.\n- [Render HDR video](https://hyperframes.heygen.com/guides/hdr.md): Preserve BT.2020 PQ or HLG sources in a 10-bit H.265 MP4.\n- [Fix a slow preview or render](https://hyperframes.heygen.com/guides/performance.md): Find the expensive part of a composition and make it cheaper.\n\n### Packages\n\n- [@hyperframes/core](https://hyperframes.heygen.com/packages/core.md): Composition types, generation, compilation, and browser runtime.\n- [@hyperframes/parsers](https://hyperframes.heygen.com/packages/parsers.md): The GSAP + HTML parser/writer suite — standalone, zero @hyperframes/* dependencies.\n- [@hyperframes/studio-server](https://hyperframes.heygen.com/packages/studio-server.md): Mount the Studio project and preview API in your own server.\n- [@hyperframes/sdk](https://hyperframes.heygen.com/packages/sdk.md): Headless, framework-neutral composition editing engine for agents and custom editors.\n- [@hyperframes/engine](https://hyperframes.heygen.com/packages/engine.md): Low-level, seekable frame capture and encoding primitives.\n- [@hyperframes/player](https://hyperframes.heygen.com/packages/player.md): Embeddable web component for playing HyperFrames compositions in any web page.\n- [@hyperframes/producer](https://hyperframes.heygen.com/packages/producer.md): Render a HyperFrames project from Node.js.\n- [@hyperframes/shader-transitions](https://hyperframes.heygen.com/packages/shader-transitions.md): WebGL shader transitions for HyperFrames scenes and compositions.\n- [@hyperframes/studio](https://hyperframes.heygen.com/packages/studio.md): React components and hooks used to build the HyperFrames Studio editing interface.\n\n### Agent setup\n\n- [Authentication & API keys](https://hyperframes.heygen.com/guides/authentication.md): Sign in to HeyGen and understand how agent workflows choose voice, music, sound, and optional capture-description providers.\n- [Install the HyperFrames plugin](https://hyperframes.heygen.com/guides/plugins.md): Install video creation skills as one versioned plugin and let your agent manage updates.\n- [Install and update agent skills](https://hyperframes.heygen.com/guides/skills.md): Teach a coding agent how to create valid HyperFrames projects and load specialized workflows when needed.\n- [Let an agent drive Studio](https://hyperframes.heygen.com/guides/webmcp.md): Studio exposes its editing capabilities as WebMCP tools, so an agent in your browser can see the composition and change it alongside you.\n\n### Contributing & community\n\n- [Contribute to HyperFrames](https://hyperframes.heygen.com/contributing.md): Set up the repository, make a focused change, and open a pull request.\n- [Contribute to the Catalog](https://hyperframes.heygen.com/contributing/catalog.md): Add a reusable block or component to the HyperFrames registry.\n- [Release channels](https://hyperframes.heygen.com/contributing/release-channels.md): How HyperFrames keeps alpha-only work out of stable releases.\n- [Release agent plugins](https://hyperframes.heygen.com/contributing/agent-plugins.md): Build, verify, and publish HyperFrames plugin packages from one committed release.\n- [Changelog process](https://hyperframes.heygen.com/contributing/changelog-process.md): How HyperFrames drafts, reviews, and publishes release notes.\n- [Test local CLI changes](https://hyperframes.heygen.com/contributing/testing-local-changes.md): Run an unreleased HyperFrames CLI build against a real project outside the monorepo.\n- [Canary rollouts](https://hyperframes.heygen.com/contributing/canary-rollouts.md): Ship a change to a percentage of installs instead of all-or-nothing.\n- [Adopters](https://hyperframes.heygen.com/community/adopters.md): Organizations using HyperFrames in production or actively evaluating it.\n\n> The links below point to documentation indexes. Follow each `/_llms/` index recursively until you reach documentation pages.\n\n## Indexes\n\n- [Catalog (388 pages)](https://hyperframes.heygen.com/_llms/catalog.md): Documentation for Catalog.\n" }, { "url": "https://hyperframes.heygen.com/.well-known/agent-card.json", "domain": "hyperframes.heygen.com", "endpoint": "/.well-known/agent-card.json", "filename": "agent-card.json", "content": { "name": "HyperFrames", "url": "https://hyperframes.heygen.com/", "version": "1.0.0", "protocolVersion": "0.3", "preferredTransport": "HTTP+JSON", "supportedInterfaces": [ { "url": "https://hyperframes.heygen.com/", "protocolBinding": "HTTP+JSON", "protocolVersion": "0.3" } ], "provider": { "url": "https://hyperframes.heygen.com/", "organization": "HyperFrames" }, "documentationUrl": "https://hyperframes.heygen.com/", "capabilities": { "streaming": false, "pushNotifications": false }, "defaultInputModes": [ "text/plain" ], "defaultOutputModes": [ "text/plain" ], "skills": [ { "id": "hyperframes", "name": "hyperframes", "description": "Use when building, editing, or rendering HTML-based video compositions. Reach for HyperFrames when an agent needs to create videos from prompts, when you need to edit existing compositions, when you're setting up rendering infrastructure, or when you need to validate and check video projects before delivery.", "tags": [], "url": "https://hyperframes.heygen.com/.well-known/agent-skills/hyperframes/skill.md" } ] } }, { "url": "https://hyperframes.heygen.com/.well-known/agent-skills/hyperframes/skill.md", "domain": "hyperframes.heygen.com", "endpoint": "/.well-known/agent-skills/hyperframes/skill.md", "filename": "skill.md", "content": "---\nname: hyperframes\ndescription: Use when building, editing, or rendering HTML-based video compositions. Reach for HyperFrames when an agent needs to create videos from prompts, when you need to edit existing compositions, when you're setting up rendering infrastructure, or when you need to validate and check video projects before delivery.\nmetadata:\n mintlify-proj: hyperframes\n version: \"1.0\"\n---\n\n# HyperFrames Skill\n\n## Product summary\n\nHyperFrames is an open-source framework that turns HTML into video. Compositions are plain HTML files with `data-*` timing attributes, CSS, and JavaScript (typically GSAP animations). Agents write compositions from prompts; you edit them in Studio or code; the CLI validates, previews, and renders them to MP4 or other formats. Key files: `index.html` (root composition), `compositions/` (nested scenes), `assets/` (media). Primary CLI: `npx hyperframes `. Core packages: `@hyperframes/sdk` (editing), `@hyperframes/player` (embedding), `@hyperframes/cli` (automation). [Full documentation](https://hyperframes.heygen.com)\n\n## When to use\n\n- **Agent-driven video creation**: Use `/hyperframes` slash command to request videos from URLs, scripts, data, or creative briefs. The agent writes composition HTML, CSS, and GSAP animations.\n- **Editing existing projects**: Open a project with `npx hyperframes preview` to use Studio (visual editor) or ask an agent to modify the HTML source.\n- **Validation before delivery**: Run `npx hyperframes lint` (structure) and `npx hyperframes check` (browser, layout, motion, contrast) before rendering.\n- **Rendering and automation**: Use the CLI to render locally, batch-render with variables, or deploy to AWS Lambda, Google Cloud Run, or HeyGen's managed cloud.\n- **Building custom editors or integrations**: Use the SDK (`@hyperframes/sdk`) to inspect and edit composition HTML programmatically, or the Player (`@hyperframes/player`) to embed seekable compositions in web pages.\n\n## Quick reference\n\n### Essential CLI commands\n\n| Task | Command |\n|------|---------|\n| Create a project | `npx hyperframes init my-video` |\n| Open Studio editor | `npx hyperframes preview` |\n| Validate HTML structure | `npx hyperframes lint` |\n| Run browser + layout + motion checks | `npx hyperframes check` |\n| Render to MP4 | `npx hyperframes render --output video.mp4` |\n| Capture review frames | `npx hyperframes snapshot --at 0,2,5` |\n| Generate narration | `npx hyperframes tts \"script text\"` |\n| Transcribe audio | `npx hyperframes transcribe audio.mp3` |\n| Publish to web | `npx hyperframes publish` |\n| Check system setup | `npx hyperframes doctor` |\n\n### Composition structure\n\n```html\n
\n \n \n \n \n \n \n
\n```\n\n### Key data attributes\n\n| Attribute | Purpose | Example |\n|-----------|---------|---------|\n| `data-composition-id` | Identifies a composition (required on root) | `data-composition-id=\"intro\"` |\n| `data-start` | When clip appears (seconds or anchor) | `data-start=\"2\"` or `data-start=\"intro\"` |\n| `data-duration` | How long clip stays visible | `data-duration=\"3\"` |\n| `data-track-index` | Layer/track number (0 = bottom) | `data-track-index=\"1\"` |\n| `class=\"clip\"` | Marks timed elements (required) | `class=\"clip\"` |\n| `data-width` / `data-height` | Viewport dimensions | `data-width=\"1920\" data-height=\"1080\"` |\n| `data-composition-src` | Path to nested composition file | `data-composition-src=\"compositions/intro.html\"` |\n| `data-no-timeline` | Composition has no GSAP animation | `data-no-timeline` |\n\n### Authentication and credentials\n\n```bash\n# Sign in (opens browser OAuth)\nnpx hyperframes auth login\n\n# Or use API key (for CI/headless)\nnpx hyperframes auth login --api-key\n\n# Check what's configured\nnpx hyperframes auth status\n```\n\nEnvironment variables (first match wins):\n- `HEYGEN_API_KEY` or `HYPERFRAMES_API_KEY` — HeyGen voice/music\n- `ELEVENLABS_API_KEY` — ElevenLabs TTS fallback\n- `GEMINI_API_KEY` — Gemini TTS or music generation\n- `OPENROUTER_API_KEY` — Capture descriptions\n\n## Decision guidance\n\n| Situation | Use | Why |\n|-----------|-----|-----|\n| Creating a video from scratch | `/hyperframes` slash command + agent | Agent writes HTML; you iterate in Studio or with prompts |\n| Editing visible elements | Studio canvas + Design panel | Direct visual feedback; safe edits |\n| Changing timing or structure | Studio timeline or agent prompt | Timeline for small moves; agent for story changes |\n| Batch rendering with different text/colors | `--variables` flag + CLI | One composition, many renders with different values |\n| Embedding video in a web page | `@hyperframes/player` web component | Seekable playback without rendering to MP4 |\n| Programmatic composition edits | `@hyperframes/sdk` | Inspect, query, and edit HTML from code |\n| Rendering locally | `npx hyperframes render` | Fast iteration; no cloud setup |\n| Rendering 4K or multi-minute videos | AWS Lambda or Google Cloud Run | Distribute work across workers |\n| Managed rendering without infrastructure | HeyGen cloud (`--cloud` flag) | No AWS account needed |\n\n## Workflow\n\n### Creating a video with an agent\n\n1. **Initialize project**: `npx hyperframes init my-video`\n2. **Open preview**: `npx hyperframes preview` (keeps this running in background)\n3. **Prompt the agent**: Use `/hyperframes` slash command with a workflow (e.g., `/product-launch-video`, `/faceless-explainer`, `/music-to-video`) or `/hyperframes` for custom work\n4. **Review the first draft**: Watch the preview as the agent builds; it updates live\n5. **Iterate**: Ask for specific changes (\"make the opening faster\", \"use the site's colors\", \"add captions\")\n6. **Validate**: Run `npx hyperframes lint && npx hyperframes check` — both must pass\n7. **Render**: `npx hyperframes render --output final.mp4`\n8. **Deliver**: Watch the final file once before sharing\n\n### Editing in Studio\n\n1. Open project: `npx hyperframes preview`\n2. Pause at the frame where you see the problem\n3. Click the element on canvas or find it in Layers panel\n4. Change one property in Design panel (text, color, position, duration)\n5. Play through the surrounding moment to confirm\n6. Repeat for other changes\n7. For story/structure changes, ask the agent instead\n\n### Rendering with variables\n\n1. Declare variables in composition: `data-composition-variables='[{\"id\":\"title\",\"type\":\"string\",\"default\":\"Default\"}]'`\n2. Read in script: `const { title } = window.__hyperframes.getVariables()`\n3. Render with overrides: `npx hyperframes render --variables '{\"title\":\"New Title\"}' --output out.mp4`\n4. Batch render: `npx hyperframes render --variables-file vars.json --output 'out-{index}.mp4'`\n\n### Deploying to cloud\n\n**HeyGen managed cloud** (simplest):\n```bash\nnpx hyperframes render --cloud --output video.mp4\n```\n\n**AWS Lambda** (requires AWS credentials):\n```bash\nnpx hyperframes lambda deploy\nnpx hyperframes render --lambda --output video.mp4\n```\n\n**Google Cloud Run** (requires GCP credentials):\n```bash\nnpx hyperframes cloudrun deploy\nnpx hyperframes render --cloudrun --output video.mp4\n```\n\n## Common gotchas\n\n- **Missing `class=\"clip\"` on timed elements**: Elements with `data-start` and `data-duration` must have `class=\"clip\"` or they stay visible the whole time. Linter catches this.\n- **Animating video dimensions directly**: Never animate `width`, `height`, `top`, `left` on `