Skip to content

Conversation

@ricardo-agz
Copy link
Contributor

@ricardo-agz ricardo-agz commented Nov 28, 2025

Support zero-config deployments for arbitrary Python frameworks so long as they contain an app script in project.scripts in pyproject.toml, e.g:

[project]
name = "my-starlette-app"
version = "0.1.0"
requires-python = ">=3.12"
dependencies = [
  "starlette",
]

[project.scripts]
app = "main:app"

vc dev suport in: #14383

@changeset-bot
Copy link

changeset-bot bot commented Nov 28, 2025

🦋 Changeset detected

Latest commit: b51a906

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 4 packages
Name Type
@vercel/frameworks Patch
@vercel/python Patch
vercel Patch
@vercel/fs-detectors Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

Add changeset for supporting arbitrary Python frameworks.
@github-actions
Copy link
Contributor

github-actions bot commented Nov 28, 2025

🧪 Test Strategy

Comparing: f9b8fb2b51a906 (view diff)

Strategy: Affected packages only

✅ Only testing packages that have been modified or depend on modified packages. This saves time while maintaining safety.

Affected packages (6):

  1. @vercel/frameworks
  2. @vercel/fs-detectors
  3. @vercel/python
  4. @vercel/static-build
  5. examples
  6. vercel

E2E Tests: Only affected package e2e tests will run


This comment is automatically generated based on the affected testing strategy

Copy link
Contributor

@vercel vercel bot left a comment

Choose a reason for hiding this comment

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

Additional Suggestion:

The 'pyproject' framework is not supported by the dev server, preventing users from running vercel dev with the new generic Python framework. The framework check explicitly excludes 'pyproject', causing the function to return null and opt-out of dev server support.

View Details
📝 Patch Details
diff --git a/packages/python/src/start-dev-server.ts b/packages/python/src/start-dev-server.ts
index 026ce7b7e..79049b17f 100644
--- a/packages/python/src/start-dev-server.ts
+++ b/packages/python/src/start-dev-server.ts
@@ -162,9 +162,9 @@ function createDevWsgiShim(
 export const startDevServer: StartDevServer = async opts => {
   const { entrypoint: rawEntrypoint, workPath, meta = {}, config } = opts;
 
-  // Only start a dev server for FastAPI or Flask for now
+  // Only start a dev server for FastAPI, Flask, or generic pyproject for now
   const framework = config?.framework;
-  if (framework !== 'fastapi' && framework !== 'flask') {
+  if (framework !== 'fastapi' && framework !== 'flask' && framework !== 'pyproject') {
     return null;
   }
 
@@ -177,15 +177,19 @@ export const startDevServer: StartDevServer = async opts => {
     rawEntrypoint
   );
   if (!entry) {
-    const searched =
-      framework === 'fastapi'
-        ? FASTAPI_CANDIDATE_ENTRYPOINTS.join(', ')
-        : FLASK_CANDIDATE_ENTRYPOINTS.join(', ');
+    let searched: string;
+    if (framework === 'fastapi') {
+      searched = FASTAPI_CANDIDATE_ENTRYPOINTS.join(', ');
+    } else if (framework === 'flask') {
+      searched = FLASK_CANDIDATE_ENTRYPOINTS.join(', ');
+    } else {
+      searched = 'Define an \'app\' script in pyproject.toml';
+    }
     throw new NowBuildError({
       code: 'PYTHON_ENTRYPOINT_NOT_FOUND',
       message: `No ${framework} entrypoint found. Add an 'app' script in pyproject.toml or define an entrypoint in one of: ${searched}.`,
-      link: `https://vercel.com/docs/frameworks/backend/${framework?.toLowerCase()}#exporting-the-${framework?.toLowerCase()}-application`,
-      action: 'Learn More',
+      link: framework !== 'pyproject' ? `https://vercel.com/docs/frameworks/backend/${framework?.toLowerCase()}#exporting-the-${framework?.toLowerCase()}-application` : undefined,
+      action: framework !== 'pyproject' ? 'Learn More' : undefined,
     });
   }
 
@@ -276,7 +280,7 @@ export const startDevServer: StartDevServer = async opts => {
         }
       }
 
-      if (framework === 'fastapi') {
+      if (framework === 'fastapi' || framework === 'pyproject') {
         // Create a tiny ASGI shim that serves static files first (when present)
         // and falls back to the user's app. Always applied for consistent behavior.
         const devShimModule = createDevAsgiShim(workPath, modulePath);

Analysis

The 'pyproject' framework is not supported by the dev server, preventing vercel dev with generic Python frameworks

What fails: The startDevServer() function in packages/python/src/start-dev-server.ts explicitly excludes the 'pyproject' framework via a framework type check on line 167, causing it to return null and opt-out of dev server support.

How to reproduce:

  1. Create a Python project with a generic ASGI/WSGI framework (e.g., Starlette) configured via pyproject.toml with a [project.scripts] section defining an app entrypoint
  2. Run vercel dev with framework: 'pyproject' in the Vercel configuration
  3. The dev server fails to start because startDevServer() returns null

Result: Users with framework: 'pyproject' configuration cannot use vercel dev for local development, even though production deployments work correctly.

Expected: The dev server should support the 'pyproject' framework the same way it supports 'fastapi' and 'flask'. Since the test fixture 45-pyproject-app uses Starlette (an ASGI framework), it should route through the ASGI code path.

Fix implemented:

  • Updated line 167 to include 'pyproject' in the framework check
  • Updated line 305 to route 'pyproject' to the ASGI code path (matching the behavior for FastAPI)
  • Updated error handling for entrypoint detection to handle 'pyproject' framework appropriately
Fix on Vercel

Copy link
Contributor

@vercel vercel bot left a comment

Choose a reason for hiding this comment

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

Additional Suggestion:

The pyproject framework doesn't execute custom install and build commands configured in vercel.json or the Vercel dashboard, even though the framework definition allows them to be configured. This will cause deployments to fail if users rely on custom install commands like uv sync.

View Details
📝 Patch Details
diff --git a/packages/python/src/index.ts b/packages/python/src/index.ts
index bc0d62167..969bcac73 100644
--- a/packages/python/src/index.ts
+++ b/packages/python/src/index.ts
@@ -118,8 +118,8 @@ export const build: BuildV3 = async ({
     throw err;
   }
 
-  // For FastAPI/Flask, also honor project install/build commands (vercel.json/dashboard)
-  if (framework === 'fastapi' || framework === 'flask') {
+  // For FastAPI/Flask/Pyproject, also honor project install/build commands (vercel.json/dashboard)
+  if (framework === 'fastapi' || framework === 'flask' || framework === 'pyproject') {
     const {
       cliType,
       lockfileVersion,

Analysis

Custom install and build commands not executed for pyproject framework

What fails: The pyproject framework doesn't execute custom install and build commands configured in vercel.json or the Vercel dashboard, even though the framework definition explicitly supports these settings with installCommand placeholder of `uv sync`.

How to reproduce:

  1. Create a Python project with pyproject.toml that uses [project.scripts] with an app entry
  2. Configure a custom install command (e.g., uv sync) in vercel.json or Vercel dashboard for the pyproject framework
  3. Deploy the project to Vercel

Result: The custom install command is silently ignored. The build output shows no record of the uv sync command running.

Expected: The custom install command should run before attempting to install dependencies, as it does for fastapi and flask frameworks (per the code logic at packages/python/src/index.ts line 122).

Root cause: Line 122 in packages/python/src/index.ts only checks for framework === 'fastapi' || framework === 'flask', excluding framework === 'pyproject'. This prevents the projectSettings.installCommand and projectSettings.buildCommand blocks from executing for pyproject deployments, even though the framework definition in packages/frameworks/src/frameworks.ts (line 3865) declares these settings as configurable with installCommand: { placeholder: 'uv sync' }.

Impact: Users cannot use alternative installation methods like uv sync or poetry install for pyproject deployments. They are limited to the automatic uv export + install flow, which differs from direct uv/poetry package manager workflows. This is a breaking limitation for projects that require specific dependency resolution or installation approaches.

Fix on Vercel

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.

2 participants