How to Use Vercel.toml: The Beginner's Guide (The TOML Alternative to vercel.json)
CodexFuse Team · 2026-11-03T17:24:46.975Z · 15 min read min read
How to Use Vercel.toml: The Beginner's Guide (The TOML Alternative to vercel.json)
Learning how to use vercel.toml is suddenly worth your time: on November 2, 2026, Vercel announced that projects can now be configured with a vercel.toml file, giving developers a brand-new way to control builds, routing, functions, and more. All of the same configuration properties are supported as in vercel.json, but the TOML format supports comments and has a flatter structure — which makes it the friendliest option for anyone whose config file keeps growing. This guide walks you through writing your first vercel.toml, the properties that matter most, how to migrate from vercel.json, and the one-file rule you must not break.
If you have never deployed anything on the platform before, start with our Vercel beginner guide — it covers the deploy flow itself. This article is about the configuration file that sits in your project root and tells Vercel exactly how to build and serve what you push.
What is vercel.toml, exactly?
vercel.toml is a static, file-based project configuration file for Vercel written in TOML. Vercel's own documentation puts it plainly: "The vercel.toml file lets you configure your Vercel project with TOML. In addition to supporting the same configuration properties as vercel.json, it supports comments and has a flatter structure." You create it in your project root and commit it with your code, and Vercel reads it on every deploy to override its framework-detection defaults — the build command, the output directory, routing rules, function behavior, scheduled tasks, image optimization, and more.
The mental model that matters: vercel.toml is the same idea as vercel.json, just a different syntax. Nothing about your project changes — same repo, same framework, same deploy button. Only the file you write the settings in is different.
Why would you pick TOML over JSON?
You would pick TOML for readability: TOML lets you write comments and reads in a flatter, less nested structure than JSON, so a big config file stays scannable. Vercel's documentation explicitly recommends TOML "when you have a large or complex configuration, such as if you need to configure many Rewrites or are using Services to deploy multiple applications within one Vercel project." The November 2026 announcement frames the same trade-off: identical properties, but comments plus a flatter structure.
If you come from traditional server work, the contrast is sharper than the syntax debate. On what is VPS hosting explains the model: on a rented box you SSH in and hand-edit config files living on the server, separate from your code. Vercel flips that — the configuration travels with the repository, gets version-controlled with your code, and every git push carries the exact settings that produced the deploy. TOML just makes that file the easiest one to read six months later.
The practical payoff of comments deserves one concrete example. In vercel.json, a rewrite rule is an opaque object; in vercel.toml you can write # sends /api/* to the FastAPI backend directly above it. Future you — or the teammate who inherits the project — will thank present you.
How do you write your first vercel.toml, step by step?
How to write your first vercel.toml: create the file in your project root, add the schema line for editor autocomplete, set your build and output settings, add any routing rules, then commit and push. The whole arc takes about five minutes. Here it is as a numbered walkthrough:
- Create
vercel.tomlin your project root. The file must live at the top level of your repository, next topackage.json— not inside a subfolder. If avercel.jsonorvercel.tsalready exists in the root, you are about to replace it (the one-file rule: only one configuration file per project). - Add the schema line first. Put
"$schema" = "https://openapi.vercel.sh/vercel.json"at the top. This enables IDE autocomplete and validation in VS Code and other editors — Vercel's docs list it as the official way to get schema support, and the same schema URL serves the TOML format. - Set the build command and output directory. If Vercel's framework detection guesses wrong — common with monorepos or custom setups — pin them explicitly:
buildCommand = "pnpm run build"andoutputDirectory = "dist". For most framework projects you can skip this step entirely; Vercel detects the right values from your framework. - Add one readability win: comments. This is the step JSON never let you take. A line like
# clean URLs: /about.html becomes /aboutabovecleanUrls = truedocuments intent where it lives. - Add your first routing rule if you need one. A single
[[rewrites]]block with asourceand adestinationis enough to start — the worked example below shows the exact shape. - Commit the file with your code. Vercel's docs say it directly: "Create
vercel.tomlin your project root and commit it with your code." If the git side of that sentence feels new, our GitHub beginner guide covers first repositories and first pushes — the config file rides along with the same commit as everything else. - Push and watch the deploy.
git pushtriggers a deployment; Vercel detects the file and applies it. Check the deployment's build logs to confirm your overrides took effect — a wrong property name fails loudly there, which beats guessing.
The smallest meaningful file, adapted from Vercel's own documentation, looks like this:
"$schema" = "https://openapi.vercel.sh/vercel.json"
buildCommand = "pnpm run build"
outputDirectory = "dist"
cleanUrls = true
What goes inside? The properties in plain English
vercel.toml supports all the same configuration fields as vercel.json — Vercel's docs state the equivalence explicitly, so the reference table for one format is the reference table for both. You do not need most of them; Vercel's framework detection covers the common cases, and you add a property only when you need one specific override. Here are the ones beginners actually touch, with their TOML shape:
| Property | What it does | TOML shape |
|---|---|---|
$schema | Enables IDE autocomplete and validation; has no effect on the deploy itself | "$schema" = "https://openapi.vercel.sh/vercel.json" |
buildCommand | Overrides the build command for your project | buildCommand = "pnpm run build" |
outputDirectory | Specifies the build output directory | outputDirectory = "dist" |
installCommand | Overrides the package install command | installCommand = "pnpm install --frozen-lockfile" |
framework | Pins the framework preset when detection guesses wrong | framework = "nextjs" |
rewrites | Routes requests to different paths or external URLs | [[rewrites]] blocks (see example below) |
redirects | Redirects requests to different URLs | [[redirects]] blocks |
headers | Adds custom HTTP headers to responses | [[headers]] blocks |
cleanUrls | Removes .html extensions from URLs | cleanUrls = true |
trailingSlash | Adds or removes trailing slashes from URLs | trailingSlash = true |
functions | Configures function memory, duration, and runtime | [functions."api/*.js"] tables |
crons | Schedules functions to run at specific times | [[crons]] blocks |
regions | Deploys functions to specific regions | regions = ["iad1"] |
Two notes on that table. First, the double-bracket syntax ([[rewrites]]) is TOML's way of saying "a list of tables" — each block is one entry in the list, and it is exactly the flatter structure the announcement advertises: no braces-within-braces-within-arrays the way the JSON equivalent needs. Second, crons deserves a pointer: scheduled functions are just what a cron job is applied to serverless functions — a schedule expression plus the path to run.
vercel.toml vs vercel.json vs vercel.ts: which one should you use?
Use vercel.toml when you want the most readable static config, vercel.json when your tooling already speaks JSON, and vercel.ts only when you need the config computed at build time. The one hard rule, stated identically in the changelog and the docs: use only one project configuration file — vercel.toml, vercel.json, or vercel.ts. Keeping two is the single most common beginner mistake, and it is covered in the mistakes table below.
vercel.toml | vercel.json | vercel.ts | |
|---|---|---|---|
| Nature | Static | Static | Programmatic (runs at build time) |
| Comments | Yes — native TOML | No — JSON has no comments | Yes — TypeScript |
| Structure | Flatter | Nested | Code |
| Property set | Same as JSON | The reference set | Same properties, typed |
| Dynamic values | No | No | Yes — environment variables, API calls, build-time logic |
| Best for | Large or complex configs, Services, teams that document intent | Existing setups, JSON-native tooling | Configs that must be computed per environment |
| Schema support | Yes, via $schema | Yes, via $schema | Yes, via types |
The vercel.ts column needs one clarifying sentence from the vendor docs: the static formats support the same properties, "while vercel.ts lets you generate configuration dynamically using environment variables, API calls, or other build-time logic." If your config never changes between environments, you do not need it — reach for TOML instead. And no, vercel.json is not deprecated: Vercel supports all three formats, and the choice is about your workflow, not about migrating away from something dying.
vercel.toml example: a real two-service project
Here is the vercel.toml example that shows off everything TOML does better: a project with a Next.js frontend and a FastAPI backend deployed together as Vercel Services, with comments explaining each routing rule. It is adapted from the official Services example in Vercel's documentation — same shape, with the comments TOML was made for:
"$schema" = "https://openapi.vercel.sh/vercel.json"
# Next.js frontend — served from the frontend/ directory
[services.frontend]
root = "frontend/"
# FastAPI backend — entrypoint points at the app object
[services.backend]
root = "backend/"
entrypoint = "main:app"
# API traffic goes to the backend service...
[[rewrites]]
source = "/api/(.*)"
destination = { service = "backend" }
# ...and everything else goes to the frontend
[[rewrites]]
source = "/(.*)"
destination = { service = "frontend" }
Notice three things. First, the comments do real work: without them, source = "/api/(.*)" followed by source = "/(.*)" is a puzzle; with them, the routing intent is obvious. Second, the flatter structure: the equivalent vercel.json nests the same information three levels deep (the docs print both side by side, and the JSON version is visibly noisier). Third, the order of the rewrite blocks matters — /api/* is checked before the catch-all /(.*), exactly as in the JSON version.
This example also explains why the announcement landed when it did. Vercel's 2026 has been about owning the backend: Services launched in June 2026 to deploy frontend and backend in one project, Python reached general availability at Ship 2026 on October 15 (FastAPI, Flask, and Django), and as one October roundup put it, "a single vercel.toml now deploys your FastAPI backend and Next.js frontend atomically, with shared previews and unified logging." The TOML format arrived as the readable way to write the multi-service configs that 2026's Vercel now encourages.
How do comments work in vercel.toml?
The vercel.toml comments question has the shortest answer in this whole guide: a # starts a comment that runs to the end of the line. That is the entire mechanism — there is no special Vercel syntax — and it is the feature JSON users have missed for years. Write them as intent notes ("why this rule exists"), not as narration ("this is a rewrite"); the file is read by future maintainers, and "why" is what they will need.
One honest limitation: comments live in the source file only. Once Vercel parses the file at deploy time, the comments do not travel anywhere — they are documentation for humans, not instructions for the platform. Treat them that way and they stay valuable.
How do you migrate from vercel.json to vercel.toml?
If you want to migrate vercel.json to vercel.toml, the good news is that the property sets are identical, so the move is a syntax translation, not a redesign: convert each JSON property to its TOML equivalent, write the new file, verify the deploy, then delete the old file — never keep both. The arc:
- Copy the property values, not the punctuation. Every key in your
vercel.jsonhas the same name in TOML."buildCommand": "pnpm run build"becomesbuildCommand = "pnpm run build"; nested objects become[tables]; arrays of objects become[[lists]]. - Write
vercel.tomlin the project root. Keep the schema line at the top so your editor validates as you type. - Move any tribal knowledge into comments. This is the migration's bonus round: every rewrite rule you only understood from memory gets a
# whyline while you are translating it. - Deploy with both files still present — then check which one Vercel used. During the transition window, confirm the deploy log reflects the TOML values.
- Delete
vercel.json. The one-file rule is absolute:vercel.toml,vercel.json, orvercel.ts— pick one. A stalevercel.jsonsitting next to your new file is the classic source of "why isn't my config applying" confusion.
There is no official automated converter to lean on, and the translation is simple enough that doing it by hand doubles as a review pass: most teams discover dead properties (overrides they no longer need) while converting.
vercel.toml vs netlify.toml: the cross-platform cousin
If you have used Netlify, vercel.toml will feel familiar: Netlify's netlify.toml has played the same role — build settings, redirects, and headers in a TOML file at the repo root — for years. Netlify's own Vercel-to-Netlify migration checklist makes the parallel explicit: converting means translating Vercel build settings into a netlify.toml block like [build] with command = "next build" and publish = ".next", then re-homing redirects and headers.
The philosophies differ in one place worth knowing. Netlify's TOML file is the platform's primary config idiom; on Vercel, TOML is the newest of three equal citizens, and JSON remains the format most existing guides and tools assume. If you deploy to both platforms (or might migrate later), keeping your mental model in TOML terms transfers cleanly — but the property names are platform-specific, so expect a translation pass, not a copy-paste.
What about the 2026 ecosystem: Services, Daemons, and Python?
The TOML format is arriving into a busier Vercel than the one vercel.json grew up in, and the new properties it configures are worth knowing about. Three 2026 developments, all fetched from Vercel's own changelog and current coverage:
- Services (June 2026). Frontend and backend services deploy within one Vercel project, with private service-to-service traffic — the pattern the two-service example above demonstrates. This is the workload Vercel's docs cite first when recommending TOML for complex configurations.
- Python general availability (October 15, 2026). FastAPI, Flask, and Django are now first-class runtimes at Vercel's Ship 2026 event, which is why the canonical TOML example pairs a Next.js frontend with a FastAPI backend — that pairing is the platform's current headline use case.
- Daemons (public beta, October 2026). Long-running workers — Celery, BullMQ, Temporal consumers, CI runners — run as containers alongside your app. You declare them with a
daemonsentry invercel.tomlat the project root (fields:root,entrypoint,command, per-regioninstances), and a November changelog entry added service bindings so a daemon can call your services through a private URL.
The honest framing: this ecosystem is weeks to months old. Guides, Stack Overflow answers, and AI training data still overwhelmingly assume vercel.json, so expect the occasional outdated snippet. When in doubt, the vendor docs page for vercel.toml — which Vercel's own changelog links — is the source of truth.
5 beginner mistakes that break vercel.toml deploys
Every one of these comes from the rules documented above — which is why they are so easy to make once and never again:
| Mistake | Why it breaks | The fix |
|---|---|---|
Keeping vercel.json next to vercel.toml | One configuration file per project — two files means ambiguous or ignored config | Delete the old file the moment the new one is verified |
| Putting the file in a subfolder | Vercel reads config from the project root only | Move it next to package.json |
| Writing JSON syntax inside TOML | { "key": "value" } is not valid TOML at the top level | Use key = "value", [tables], [[lists]] |
| Catch-all rewrite listed before specific rules | Rules are evaluated in order — /(.*) first swallows /api/* | Specific sources first, catch-all last |
| Skipping the schema line | No autocomplete, no validation — typos fail at deploy time instead of in the editor | Keep "$schema" = "https://openapi.vercel.sh/vercel.json" at the top |
Sources
Every fact in this article was verified against a page fetched on November 3, 2026:
- Vercel changelog, "Projects can now be configured with vercel.toml" (November 2026) — the announcement, the "same properties, comments, flatter structure" verbatim, the one-file rule, and the Services example.
- Vercel documentation, "Static Configuration with vercel.toml" (stamped 2026-08-25) — the TOML-vs-JSON equivalence, the "large or complex configuration" guidance, the project-root rule, the worked basic and Services examples.
- Vercel documentation, "Project Configuration" (stamped 2026-08-25) — the full property table and the "static formats support the same properties / vercel.ts generates dynamically" distinction.
- Vercel changelog, "Vercel Daemons can now call services with bindings" (October 2026) — the daemon service-binding syntax.
- Netlify documentation, "Vercel to Netlify migration checklist" — the
netlify.tomlbuild-settings conversion example. - DEV Community, "Python GA on Vercel" roundup, Issue #110 (October 2026) — the "single vercel.toml deploys FastAPI backend and Next.js frontend atomically" context.
- Firerun, "Vercel Daemons Put Long-Running Queue Workers on Vercel" (October 18, 2026) — the
daemonsentry fields and setup steps.
Frequently Asked Questions
Do I even need a vercel.toml file?
Usually not at first. Vercel automatically detects your framework and sets sensible defaults for builds, deployments, and routing — most Next.js projects need no config file at all. You add vercel.toml when you need a specific override: a custom build command, routing rules, scheduled functions, or a multi-service layout.
Is vercel.json deprecated now that vercel.toml exists?
No. Vercel supports all three formats — vercel.toml, vercel.json, and vercel.ts — and the announcement frames TOML as an additional option, not a replacement. The constraint is that you may use only one of them per project.
Can I keep both vercel.json and vercel.toml in my project?
No — use only one project configuration file. The rule is stated in both the changelog and the documentation, and keeping both is the most common source of "my config isn't applying" confusion. Migrate, verify, then delete the old file.
How do comments work in vercel.toml?
A # starts a comment that runs to the end of the line, exactly as in any TOML file. There is no Vercel-specific comment syntax. Comments are documentation for humans — they do not affect the deploy.
Does the $schema line actually do anything?
The vercel.toml schema story is simple: yes, it does something real — in your editor. "$schema" = "https://openapi.vercel.sh/vercel.json" enables autocomplete and validation in VS Code and other editors that support JSON Schema. Vercel's docs list it as the official schema reference for the TOML format too; it has no effect on the deploy itself.

