Skip to content

feat(vercel): allow overriding function config by route#4124

Open
RihanArfan wants to merge 6 commits intomainfrom
feat/vercel-per-function-config
Open

feat(vercel): allow overriding function config by route#4124
RihanArfan wants to merge 6 commits intomainfrom
feat/vercel-per-function-config

Conversation

@RihanArfan
Copy link
Member

@RihanArfan RihanArfan commented Mar 17, 2026

🔗 Linked issue

Closes #3815

❓ Type of change

  • 📖 Documentation (updates to the documentation, readme, or JSdoc annotations)
  • 🐞 Bug fix (a non-breaking change that fixes an issue)
  • 👌 Enhancement (improving an existing functionality like performance)
  • ✨ New feature (a non-breaking change that adds functionality)
  • 🧹 Chore (updates to the build process or auxiliary tools and libraries)
  • ⚠️ Breaking change (fix or feature that would cause existing functionality to change)

📚 Description

Allows setting Vercel function configuration (https://vercel.com/docs/build-output-api/primitives#serverless-function-configuration) on a per-function basis. It continues to symlink the existing to __server.func besides .vc-config.json for functions which match the routes which has custom config.

This unblocks future work for supporting Vercel Queues within Nitro as we'll be able to add triggers to a new queue handler route.

📝 Checklist

  • I have linked an issue or discussion.
  • I have updated the documentation accordingly.

@RihanArfan RihanArfan requested a review from pi0 as a code owner March 17, 2026 15:43
@coderabbitai
Copy link

coderabbitai bot commented Mar 17, 2026

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Adds a Vercel preset option routeFunctionConfig that maps route patterns to per-route Vercel function configs, implements rou3 matching, and creates merged per-route .vc-config.json function directories for matched routes while leaving others as symlinked functions.

Changes

Cohort / File(s) Summary
Types
src/presets/vercel/types.ts
Adds routeFunctionConfig?: Record<string, VercelServerlessFunctionConfig> to VercelOptions with JSDoc and example.
Vercel preset utils
src/presets/vercel/utils.ts
Adds rou3 router for routeFunctionConfig; creates per-route custom function directories by symlinking server contents (excluding .vc-config.json) and writing merged .vc-config.json (array properties replaced); updates build config routes to include route-specific entries; supports ISR and observability routes; deduplicates created dirs.
Tests & fixtures
test/presets/vercel.test.ts, test/fixture/nitro.config.ts
Adds tests and fixture config exercising routeFunctionConfig overrides, verifying custom function dirs, merged .vc-config.json contents (including array-replace semantics and experimental fields), and that base __server.func remains unchanged.
Docs
docs/2.deploy/20.providers/vercel.md
Documents "Per-route function configuration", merge semantics (arrays replaced), rou3 wildcard support, and provides a TypeScript example for vercel.routeFunctionConfig.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 20.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title 'feat(vercel): allow overriding function config by route' follows conventional commits format with type, scope, and descriptive message.
Description check ✅ Passed The PR description clearly explains the feature, links to issue #3815, documents the rationale, and includes a checklist confirming documentation updates.
Linked Issues check ✅ Passed The PR fully implements the requirements from issue #3815 by adding per-route Vercel function configuration support, enabling targeted config overrides like maxDuration without global changes.
Out of Scope Changes check ✅ Passed All changes are directly scoped to implementing per-route Vercel function configuration: types, utils, tests, documentation, and fixture updates align with the stated objectives.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/vercel-per-function-config
📝 Coding Plan
  • Generate coding plan for human review comments

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@vercel
Copy link

vercel bot commented Mar 17, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
nitro.build Ready Ready Preview, Comment Mar 18, 2026 2:15pm

Request Review

@pkg-pr-new
Copy link

pkg-pr-new bot commented Mar 17, 2026

Open in StackBlitz

npm i https://pkg.pr.new/nitro@4124

commit: af5775a

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/presets/vercel/utils.ts`:
- Around line 336-342: The route-function config emission currently iterates
Object.keys(nitro.options.vercel.routeFunctionConfig) which yields
nondeterministic order and can let wildcards shadow specific routes; update the
logic that maps over nitro.options.vercel.routeFunctionConfig to first sort the
route patterns by specificity (e.g., more static segments and
fewer/wildcards/params first) so specific patterns come before wildcards, and
ensure the generated src uses nitro.options.baseURL as a prefix (apply the same
baseURL handling used for observability routes) before calling
normalizeRouteSrc; keep dest generation via
withLeadingSlash(normalizeRouteDest(pattern)) unchanged.
- Around line 597-598: The current use of defu to create mergedConfig
(defu(overrides, baseFunctionConfig)) concatenates array fields like regions or
experimentalTriggers instead of letting per-route overrides replace them; change
the merge to treat arrays as replace-not-concat by implementing a custom merge
step: when combining overrides and baseFunctionConfig for mergedConfig, copy all
scalar/object fields normally but if a field exists in overrides and is an array
(e.g., overrides.regions, overrides.experimentalTriggers) then set
mergedConfig[field] = overrides[field] rather than concatenating; update the
logic around mergedConfig creation (the call site using defu, plus any
helper/merge function you add) so writeFile(resolve(funcDir, ".vc-config.json"),
JSON.stringify(mergedConfig, null, 2)) receives the corrected config.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 62396395-9a97-4ee6-8df2-4c9c7bbd66bf

📥 Commits

Reviewing files that changed from the base of the PR and between 5d51b7f and da1808e.

📒 Files selected for processing (3)
  • src/presets/vercel/types.ts
  • src/presets/vercel/utils.ts
  • test/presets/vercel.test.ts

Comment on lines +336 to +342
// Route function config routes
...(nitro.options.vercel?.routeFunctionConfig
? Object.keys(nitro.options.vercel.routeFunctionConfig).map((pattern) => ({
src: normalizeRouteSrc(pattern),
dest: withLeadingSlash(normalizeRouteDest(pattern)),
}))
: []),
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Route-function routes should be specificity-ordered and baseURL-aware.

Current emission order depends on object key insertion, so wildcard patterns can shadow specific ones. Also, these src routes are not prefixed with nitro.options.baseURL, unlike observability routes.

💡 Proposed fix
+  const routeFunctionPatterns = nitro.options.vercel?.routeFunctionConfig
+    ? Object.keys(nitro.options.vercel.routeFunctionConfig).sort(
+        (a, b) => b.split(/\/(?!\*)/).length - a.split(/\/(?!\*)/).length
+      )
+    : [];
+
   config.routes!.push(
@@
-    ...(nitro.options.vercel?.routeFunctionConfig
-      ? Object.keys(nitro.options.vercel.routeFunctionConfig).map((pattern) => ({
-          src: normalizeRouteSrc(pattern),
+    ...routeFunctionPatterns.map((pattern) => ({
+          src: joinURL(nitro.options.baseURL, normalizeRouteSrc(pattern)),
           dest: withLeadingSlash(normalizeRouteDest(pattern)),
-        }))
-      : []),
+        })),
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/presets/vercel/utils.ts` around lines 336 - 342, The route-function
config emission currently iterates
Object.keys(nitro.options.vercel.routeFunctionConfig) which yields
nondeterministic order and can let wildcards shadow specific routes; update the
logic that maps over nitro.options.vercel.routeFunctionConfig to first sort the
route patterns by specificity (e.g., more static segments and
fewer/wildcards/params first) so specific patterns come before wildcards, and
ensure the generated src uses nitro.options.baseURL as a prefix (apply the same
baseURL handling used for observability routes) before calling
normalizeRouteSrc; keep dest generation via
withLeadingSlash(normalizeRouteDest(pattern)) unchanged.

* }
* ```
*/
routeFunctionConfig?: Record<string, VercelServerlessFunctionConfig>;
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@pi0 what should we call the key? I'm not satisfied with this, just used it as a placeholder for now. Also as it accepts a list of routes perhaps the key should be plural with routeFunctionsConfig if we decide not to change it to something else altogether?

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (1)
docs/2.deploy/20.providers/vercel.md (1)

64-83: Consider adding a wildcard pattern example.

The example only shows exact path patterns (e.g., /api/heavy-computation), but line 85 mentions wildcard support via rou3 matching. Including at least one wildcard pattern example in the main code block would better demonstrate this capability.

💡 Example with wildcard pattern
 export default defineNitroConfig({
   vercel: {
     routeFunctionConfig: {
       "/api/heavy-computation": {
         maxDuration: 800,
         memory: 4096,
       },
+      "/api/slow/**": {
+        maxDuration: 300,
+      },
       "/api/regional": {
         regions: ["lhr1", "cdg1"],
       },
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@docs/2.deploy/20.providers/vercel.md` around lines 64 - 83, Add a wildcard
route example to the existing vercel.routeFunctionConfig in the
defineNitroConfig snippet so readers see rou3 matching in practice: update the
routeFunctionConfig block (the vercel object used with defineNitroConfig) to
include at least one pattern using a wildcard (e.g., a prefix or glob-style
path) alongside the existing exact paths, and show any relevant keys
(maxDuration, memory, regions, experimentalTriggers) applied to that wildcard
entry so the example demonstrates how to configure wildcard routes.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@docs/2.deploy/20.providers/vercel.md`:
- Line 60: The docs for vercel.routeFunctionConfig are ambiguous about array
property merging; update the sentence describing merge behavior to explicitly
state that array properties (e.g., regions) in a route's partial config
completely replace the corresponding arrays from the base vercel.functions
config rather than being concatenated/merged, and add a short example or note
referencing vercel.routeFunctionConfig and vercel.functions to make this
replacement behavior clear (this follows the behavior implemented in the
route-merge logic around the array handling in the vercel utils).

---

Nitpick comments:
In `@docs/2.deploy/20.providers/vercel.md`:
- Around line 64-83: Add a wildcard route example to the existing
vercel.routeFunctionConfig in the defineNitroConfig snippet so readers see rou3
matching in practice: update the routeFunctionConfig block (the vercel object
used with defineNitroConfig) to include at least one pattern using a wildcard
(e.g., a prefix or glob-style path) alongside the existing exact paths, and show
any relevant keys (maxDuration, memory, regions, experimentalTriggers) applied
to that wildcard entry so the example demonstrates how to configure wildcard
routes.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 0a493dd7-ebeb-46f3-be6c-5f3d7310a649

📥 Commits

Reviewing files that changed from the base of the PR and between ba05eb0 and 2758d9b.

📒 Files selected for processing (1)
  • docs/2.deploy/20.providers/vercel.md

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
test/presets/vercel.test.ts (1)

170-177: Avoid locking duplicate route entries into the snapshot.

/api/hello and /api/echo are expected here and again at Line 315-Line 325. Keeping both in expected output can normalize redundant route generation instead of surfacing it.

♻️ Suggested guard for duplicates
       expect(config).toMatchInlineSnapshot(`...`);
+
+      const apiRoutePairs = config.routes
+        .filter((r: any) => r?.src === "/api/hello" || r?.src === "/api/echo")
+        .map((r: any) => `${r.src}->${r.dest}`);
+      expect(new Set(apiRoutePairs).size).toBe(apiRoutePairs.length);
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@test/presets/vercel.test.ts` around lines 170 - 177, The snapshot contains
duplicate route entries (e.g., "/api/hello" and "/api/echo") which mask
redundant generation; update the test to deduplicate before asserting by
filtering the expected routes (the array used for the snapshot, e.g.,
expectedRoutes) to keep only unique entries (compare on dest and src) — for
example, apply a filter or build a Set/Map keyed by `${dest}|${src}` so the
snapshot only contains the first occurrence and remove the repeated literal
entries from the expected list.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@test/presets/vercel.test.ts`:
- Around line 170-177: The snapshot contains duplicate route entries (e.g.,
"/api/hello" and "/api/echo") which mask redundant generation; update the test
to deduplicate before asserting by filtering the expected routes (the array used
for the snapshot, e.g., expectedRoutes) to keep only unique entries (compare on
dest and src) — for example, apply a filter or build a Set/Map keyed by
`${dest}|${src}` so the snapshot only contains the first occurrence and remove
the repeated literal entries from the expected list.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 13c5d6de-4764-4ade-ad45-251b4d2ed4ce

📥 Commits

Reviewing files that changed from the base of the PR and between af5775a and 0b8d4c5.

📒 Files selected for processing (2)
  • test/fixture/nitro.config.ts
  • test/presets/vercel.test.ts

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

set vercel function config per route

1 participant