Get started with Neon Functions
A function takes a request and returns a web response, running on long lived Node.js compute next to your database. The request can come over HTTP, or from a Function Trigger on a schedule or object u...
A function takes a request and returns a web response, running on long-lived Node.js compute next to your database. The request can come over HTTP, or from a Function Trigger on a schedule or object upload.
Hello world
Section titled “Hello world”Write a file and deploy it:
export default {
fetch: (request: Request) => new Response('Hello world'),
};neon link
neon functions deploy helloworld --src hello-world.tsDone, function deployed. Get the public URL:
neon functions get helloworld -o yamlid: helloworld
slug: helloworld
name: helloworld
invocation_url: https://br-wispy-brook-a1b2c3d4-helloworld.compute.c-2.us-east-2.aws.neon.tech/
current_deployment:
id: 1
status: completed
memory_mib: 2048
runtime: nodejs24
created_at: 2026-08-03T21:19:18.120982Z
active_deployment:
id: 1
status: completed
memory_mib: 2048
runtime: nodejs24
created_at: 2026-08-03T21:19:18.120982Z
created_at: 2026-08-03T21:19:17.989227ZWhen status is completed, the function is live. Call invocation_url to see the function's output, which is "Hello world" in this case.
That's a deployed function in three commands. The rest of this guide builds a more realistic one: declared in neon.ts, run locally with neon dev, and querying Postgres.
Prerequisites
- A Neon project in AWS US East (Ohio) (
aws-us-east-2), AWS US East (N. Virginia) (aws-us-east-1), AWS Europe (Frankfurt) (aws-eu-central-1), or AWS Asia Pacific (Singapore) (aws-ap-southeast-1). Support is expanding toward all regions. - The latest
neon, installed and authenticated. Functions commands are new and change often, so upgrade before you start (npm install -g neon@latest). - Node.js 20 or later. Deployed functions run on Node.js 24, so use 24 locally for the closest match.
To give your AI coding assistant context for Neon and Functions, install the agent skills with the Neon CLI:
Bash neon skills -s neon -s neon-functionsWithout the Neon CLI, run
npx skills add neondatabase/agent-skills -s neon -s neon-functionsinstead.- A Neon project in AWS US East (Ohio) (
Set up your project
Create your project directory:
Bash mkdir my-function && cd my-functionThen link the directory to your Neon project. There are two ways:
With an AI coding assistant. Ask your assistant to set up Neon for the project. Using the skills you installed, it links your project (creating one if you need it) with
neon linkand pulls your environment variables. Sign-in opens a browser window, so complete the OAuth step when prompted.By hand. Run
neon linkand select your project and branch when prompted (or pass--project-id). This writes a.neonfile and pulls the branch's environment variables into a local.envfile (or.env.localif there's no.envyet).Bash neon linkTo start from a working example instead, run
neon bootstrap. It scaffolds a starter template, installs dependencies, and links it. Templates include a REST API, GraphQL API, tRPC API, MCP server, realtime chat and counter, AI agents, and Discord, Telegram, and WhatsApp bots. Runneon bootstrap --list-templatesfor the full catalog. This guide builds the function by hand.Define your function
Create
neon.tsat your project root. It declares your functions and is whatneon devandneon deployread:neon.ts import { defineConfig } from "@neon/config/v1"; export default defineConfig({ functions: { // The key is the function's slug: // a permanent ID used in CLI commands and the URL. hello: { name: "My first function", // display label only source: "./functions/hello.ts", // path to the handler file }, }, });The slug is permanent: it can't be renamed after the first deploy. See the neon.ts reference for all options.
Install dependencies:
Bash npm install @neon/config @neon/functions hono pg npm install --save-dev @types/pgA function is any module whose default export has a
fetch(request)method that returns aResponse. That can be an object with afetchmethod:TypeScript export default { fetch: (request: Request) => new Response('Hello world'), };Or a bare async function:
TypeScript export default async function handler(request: Request) { return new Response('Hello world'); }A Hono app exports the object shape, so
export default appworks directly. For this guide, write a handler that queries Postgres.DATABASE_URLis injected automatically from the linked branch's Postgres database:functions/hello.ts import { Hono } from 'hono'; import { attachDatabasePool } from '@neon/functions'; import { Pool } from 'pg'; // Create the pool once at module scope so it's reused across requests. const pool = new Pool({ connectionString: process.env.DATABASE_URL, max: 5 }); attachDatabasePool(pool); const app = new Hono(); app.get('/', async (c) => { const { rows } = await pool.query('SELECT version()'); return c.json(rows[0]); }); export default app;Use a connection pool, not the serverless driver
A function keeps running across requests, so connect to Postgres with a long-lived
pgPoolcreated once at module scope. Don't use@neondatabase/serverlesshere: it's built for short-lived, edge-style invocations that open a connection per request, which wastes the persistent runtime a function gives you. Use the pooledDATABASE_URLfor queries; useDATABASE_URL_UNPOOLEDonly where you need a dedicated connection (such asLISTEN/NOTIFY).Call
attachDatabasePool(pool)once after creating the pool (requires@neon/functions0.8.0 or later). When Postgres drops an idle client (scale-to-zero, pooler reclaim, a TCP reset),pgemits anerroron the pool; with no listener attached, that becomes an uncaught exception and the isolate exits.attachDatabasePoolswallows expected idle disconnects and logs anything unexpected. The pool has already discarded the dead client, so the next query opens a fresh connection. You don't need to drain the pool on shutdown: when the runtime evicts an isolate, Neon's pooler reclaims those connections for you.Develop locally
neon devserves all functions declared inneon.tswith hot reload. It injectsDATABASE_URLand other Neon env vars from the linked branch. See Environment variables for the full list and how to pull them into a local.envfile.Bash neon devThe terminal prints the URL for each running function:
Neon Functions dev server hello http://localhost:8787Deploy
neon deployreadsneon.tsand applies it to the linked branch, deploying every function it declares:Bash neon deployThe CLI bundles each function with esbuild, uploads it, and waits for the deployment to complete.
To deploy a single file without a
neon.ts, deploy it by slug instead:Bash neon functions deploy hello --src functions/hello.tsFor all deploy options, including the Neon API, see Deploy and manage functions.
Invoke
Once the deployment reaches
completed, retrieve the invocation URL:Bash neon functions get helloThe
invocation_urlfield contains the public URL for your function:https://<branch_id>-<slug>.compute.<cell>.us-east-2.aws.neon.tech/Call it with curl:
Bash curl https://<branch_id>-hello.compute.<cell>.us-east-2.aws.neon.tech/The response is a JSON object with your branch's Postgres version:
JSON { "version": "PostgreSQL 17.x on ..., compiled by gcc ..." }
Next steps
Section titled “Next steps”- Function Triggers: invoke a function on a cron schedule or an object upload instead of over HTTP
- Deploy and manage: the CLI and API for managing deployed functions
- Authentication: verify callers before a function runs
- Custom domains: serve a function from a domain you own
Need help?
Section titled “Need help?”Join our Discord Server to ask questions or see what others are doing with Neon. For paid plan support options, see Support.