{"slug": "introducing-neon-ts-infrastructure-as-code-for-your-neon-projects", "title": "Introducing neon.ts: infrastructure as code for your Neon projects", "summary": "Neon launched neon.ts, an infrastructure-as-code config file for its platform, enabling developers to declare and provision Neon services like Postgres, Data API, and Auth using TypeScript. The tool integrates with the Neon CLI for branch management and type-safe environment variables, aiming to simplify multi-service project workflows.", "body_md": "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.\n\nUsing the Neon MCP and CLI you can already create projects and branches and pull the associated database connection string into your local `.env`\n\nfile. 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](https://neon.com/blog/slop-fork-neon)!\n\nBut as you add more Neon services to a project, managing them one CLI command at a time with `neonctl bucket list`\n\nand 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.\n\nIaC has always been a great idea, just a bit cumbersome to manage in practice. As Dax [put it on X](https://x.com/thdxr/status/2064114820295618808):\n\nIaC 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.\n\nI agree. That's why we're shipping `neon.ts`\n\n, Neon's branch config and infrastructure-as-code file for your full stack projects.\n\nWe 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`\n\nisn't as fun as `neon.ts`\n\n, so we decided to go big and ship a full IaC config runtime. And you can try it today.\n\nInstall the Neon CLI globally:\n\nAdd the config package to your project:\n\nLink your project root to a Neon project:\n\nAnd create a `neon.ts`\n\nfile:\n\nSo what does it do? There are three main use cases:\n\n**Declare your Neon services** in your`neon.ts`\n\nand run`neonctl config`\n\ncommands to provision them.**Type-safe environment variables** for your Neon services (`DATABASE_URL`\n\n, 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.\n\n## Infrastructure as code\n\nFirst, you can use `neon.ts`\n\nto declare which Neon services your project's branches should include. Every project ships with serverless Postgres and with `neon.ts`\n\nyou can already enable the Neon Data API and Neon Auth today:\n\nThen `neonctl config plan`\n\nshows you what would change and `neonctl config apply`\n\nprovisions it:\n\nAnd soon you'll declare functions and buckets and enable the AI gateway the same way, under a `preview`\n\nblock:\n\nThese preview primitives are rolling out gradually, so [sign up for the Neon Platform Preview here](https://neon.com/blog/were-building-backends#access) to get access.\n\n### The neon.ts CLI commands\n\n`neonctl deploy`\n\nis shorthand for `neonctl config apply`\n\nwhen you just want to push your changes:\n\n`neonctl link`\n\nand `neonctl checkout`\n\nset up the branch you work against - link your project root to a Neon project or switch to (and create) a branch:\n\nWe shipped `link`\n\nand `checkout`\n\nrecently as part of our [branch-first dev loop](https://neon.com/blog/branch-first-dev-loop); that post walks through the full flow.\n\nAnd two more for inspecting state:\n\nAnytime you provision or switch branches (`neonctl config apply`\n\n/ `neonctl deploy`\n\n, `neonctl link`\n\nand `neonctl checkout`\n\n), Neon pulls that branch's environment variables into your local `.env.local`\n\n, so your env always matches the branch you're working against.\n\nWhich brings us to type-safe env management and the new `@neondatabase/env`\n\npackage, built on top of the config.\n\n## Type-safe Neon environment variables\n\n`@neondatabase/env`\n\nships a `parseEnv`\n\nutility that takes your `neon.ts`\n\nconfig object and returns a parsed, typed env object. It reads `process.env`\n\nand validates it against the Neon services your config declares. Any missing variables are flagged with clear error messages (for you and your agents).\n\nBecause the services live in your `neon.ts`\n\n, the shape of `env`\n\nfollows them: enable `auth`\n\nand you get `env.auth`\n\n, enable `dataApi`\n\nand you get `env.dataApi`\n\n. Just like that you get full type safety and env validation for your Neon environment variables.\n\nNot 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`\n\nvalidates and returns just those without throwing over the ones you left out:\n\nThe keys autocomplete from your `neon.ts`\n\n, 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!\n\n## Branch configurations\n\nLast but not least, you can program what configuration new branches should get with the `branch`\n\nproperty. It's a function that receives the branch being evaluated and returns its settings:\n\nHere's what this does. The `branch`\n\nfunction runs whenever Neon evaluates a branch against your policy. It gets a `branch`\n\nobject describing the target (its `name`\n\n, whether it `exists`\n\nyet, whether it's the default and more) and you return the tuning you want.\n\nIn this example, existing branches are left alone (`branch.exists`\n\nis `true`\n\n, so we return an empty object). New branches whose name starts with `dev`\n\nget 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.\n\nRight now, branch policies apply when you create a branch with `neonctl checkout`\n\n:\n\nThis creates a new branch named `dev-add-auth`\n\nand, if you have a `neon.ts`\n\n, 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`\n\n(or `neonctl config plan`\n\nfor a dry run first).\n\n## A bit of TypeScript magic\n\nDeclaring your infrastructure in TypeScript also means we can communicate the available configuration options to you and your agents through type errors.\n\nTake this example:\n\nBy 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`\n\n:\n\nIn 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`\n\nor point the Data API at your own identity provider with `authProvider: 'external'`\n\nand a `jwksUrl`\n\n.\n\nThis immediately makes it clear that the Data API requires Neon Auth unless you specify a different `authProvider`\n\n.\n\nHere'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'`\n\n. 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!\n\n## Wrapping up\n\n`neon.ts`\n\nis the config layer for Neon as a platform. Declare your services and provision them with `config apply`\n\n, get type-safe environment variables with `parseEnv`\n\nand program your branch settings in plain TypeScript. It composes with the [branch-first dev loop](https://neon.com/blog/branch-first-dev-loop), so the same `link`\n\nand `checkout`\n\ncommands that set up a branch (pulling its env for you) also keep it in sync with your config.\n\nThis is just the start. More primitives (functions, buckets, the AI gateway) are landing under `preview`\n\nsoon. To try `neon.ts`\n\ntoday, install `neonctl`\n\nand `@neondatabase/config`\n\n, run `neonctl link`\n\nand drop a `defineConfig({})`\n\ninto a `neon.ts`\n\nfile. If there's something you wish it did, drop into the [Neon Discord](https://discord.gg/tXC49r2M4q) and tell us.\n\nHappy coding!", "url": "https://wpnews.pro/news/introducing-neon-ts-infrastructure-as-code-for-your-neon-projects", "canonical_source": "https://neon.com/blog/introducing-neon-ts", "published_at": "2026-06-15 12:00:00+00:00", "updated_at": "2026-06-14 18:42:09.125554+00:00", "lang": "en", "topics": ["developer-tools", "ai-infrastructure", "ai-tools"], "entities": ["Neon", "Neon CLI", "Neon MCP", "Neon Data API", "Neon Auth", "Neon Functions", "neonctl", "@neondatabase/env"], "alternates": {"html": "https://wpnews.pro/news/introducing-neon-ts-infrastructure-as-code-for-your-neon-projects", "markdown": "https://wpnews.pro/news/introducing-neon-ts-infrastructure-as-code-for-your-neon-projects.md", "text": "https://wpnews.pro/news/introducing-neon-ts-infrastructure-as-code-for-your-neon-projects.txt", "jsonld": "https://wpnews.pro/news/introducing-neon-ts-infrastructure-as-code-for-your-neon-projects.jsonld"}}