As Neon turns into a platform with backend primitives for apps and agents, including functions, object storage, an AI gateway and of course serverless Postgres, provisioning those primitives matters more than ever.
Using the Neon MCP and CLI you can already create projects and branches and pull the associated database connection string into your local .env
file. That's a pretty good developer (and agent) experience on its own. In fact, our open REST API exposes enough endpoints to rebuild the Neon Console from scratch!
But as you add more Neon services to a project, managing them one CLI command at a time with neonctl bucket list
and friends stops scaling. Your dev workflow needs a higher-order primitive that sits above those per-primitive commands. This is where infrastructure as code comes in.
IaC has always been a great idea, just a bit cumbersome to manage in practice. As Dax put it on X:
IaC was always such a beautiful idea with imperfections. Things always went sideways and you'd have to clean up resources or state manually. But now it's actually as magical as it could be because your agent deals with that for you.
I agree. That's why we're shipping neon.ts
, Neon's branch config and infrastructure-as-code file for your full stack projects.
We started building it because Neon Functions needs a config file for declaring your function sources for local dev, build and deployment. But it's 2026 and neon.json
isn't as fun as neon.ts
, so we decided to go big and ship a full IaC config runtime. And you can try it today.
Install the Neon CLI globally:
Add the config package to your project:
Link your project root to a Neon project:
And create a neon.ts
file:
So what does it do? There are three main use cases:
Declare your Neon services in yourneon.ts
and runneonctl config
commands to provision them.Type-safe environment variables for your Neon services (DATABASE_URL
, the Neon Auth URL and more).Branch configuration: declare the settings new branches should get (TTL, autoscaling limits, scale to zero) with your own TypeScript logic.
Infrastructure as code #
First, you can use neon.ts
to declare which Neon services your project's branches should include. Every project ships with serverless Postgres and with neon.ts
you can already enable the Neon Data API and Neon Auth today:
Then neonctl config plan
shows you what would change and neonctl config apply
provisions it:
And soon you'll declare functions and buckets and enable the AI gateway the same way, under a preview
block:
These preview primitives are rolling out gradually, so sign up for the Neon Platform Preview here to get access.
The neon.ts CLI commands
neonctl deploy
is shorthand for neonctl config apply
when you just want to push your changes:
neonctl link
and neonctl checkout
set up the branch you work against - link your project root to a Neon project or switch to (and create) a branch:
We shipped link
and checkout
recently as part of our branch-first dev loop; that post walks through the full flow. And two more for inspecting state:
Anytime you provision or switch branches (neonctl config apply
/ neonctl deploy
, neonctl link
and neonctl checkout
), Neon pulls that branch's environment variables into your local .env.local
, so your env always matches the branch you're working against.
Which brings us to type-safe env management and the new @neondatabase/env
package, built on top of the config.
Type-safe Neon environment variables #
@neondatabase/env
ships a parseEnv
utility that takes your neon.ts
config object and returns a parsed, typed env object. It reads process.env
and validates it against the Neon services your config declares. Any missing variables are flagged with clear error messages (for you and your agents).
Because the services live in your neon.ts
, the shape of env
follows them: enable auth
and you get env.auth
, enable dataApi
and you get env.dataApi
. Just like that you get full type safety and env validation for your Neon environment variables.
Not every app needs every variable, though. If one of your apps only needs a subset of env variables, pass an array of the variables that app actually needs, and parseEnv
validates and returns just those without throwing over the ones you left out:
The keys autocomplete from your neon.ts
, so you can only select variables the services in your config actually enable. The returned object also narrows to exactly what you asked for. And of course all of this is type-safe!
Branch configurations #
Last but not least, you can program what configuration new branches should get with the branch
property. It's a function that receives the branch being evaluated and returns its settings:
Here's what this does. The branch
function runs whenever Neon evaluates a branch against your policy. It gets a branch
object describing the target (its name
, whether it exists
yet, whether it's the default and more) and you return the tuning you want.
In this example, existing branches are left alone (branch.exists
is true
, so we return an empty object). New branches whose name starts with dev
get a 7-day TTL so they clean themselves up, plus a cheap compute profile: autoscaling from 0.25 CU (scale to zero) up to 1 CU, suspending after 5 minutes of inactivity. Every other branch falls through to the defaults.
Right now, branch policies apply when you create a branch with neonctl checkout
:
This creates a new branch named dev-add-auth
and, if you have a neon.ts
, runs your branch policy as part of the checkout, so the branch comes up with these settings and services already in place, no extra step. Checking out an existing branch never reconciles it; for those you apply config changes explicitly with neonctl config apply
(or neonctl config plan
for a dry run first).
A bit of TypeScript magic #
Declaring your infrastructure in TypeScript also means we can communicate the available configuration options to you and your agents through type errors.
Take this example:
By default, the Data API uses Neon Auth as its authorization service. But here you haven't declared that you want Neon Auth! So you get a type error right on dataApi
:
In plain words: Neon's Data API verifies incoming requests with Neon Auth by default, so it can't run without it. And the error spells out both ways to fix it: enable Neon Auth with auth: true
or point the Data API at your own identity provider with authProvider: 'external'
and a jwksUrl
.
This immediately makes it clear that the Data API requires Neon Auth unless you specify a different authProvider
.
Here's the part I'm proud of. The default way TypeScript communicates "these two fields depend on each other" is Type 'true' is not assignable to type 'never'
. That's bad DX! We went all the way and encoded the actual rule (and its fixes) as the expected type, so you and your coding agents immediately know which infrastructure-as-code configurations work together!
Wrapping up #
neon.ts
is the config layer for Neon as a platform. Declare your services and provision them with config apply
, get type-safe environment variables with parseEnv
and program your branch settings in plain TypeScript. It composes with the branch-first dev loop, so the same link
and checkout
commands that set up a branch (pulling its env for you) also keep it in sync with your config.
This is just the start. More primitives (functions, buckets, the AI gateway) are landing under preview
soon. To try neon.ts
today, install neonctl
and @neondatabase/config
, run neonctl link
and drop a defineConfig({})
into a neon.ts
file. If there's something you wish it did, drop into the Neon Discord and tell us.
Happy coding!