Issue Integrating Python Serverless Function with App Router

Hi all,

We are developing an application using the Next.js App Router framework and deploying it on Vercel. The application primarily uses Next.js for the frontend and its built-in API routes (under app/api/). However, we also need to include a specific backend task written as a Python Serverless Function.

Project Structure & Initial Problem:

Our project structure includes the standard Next.js app/ directory containing pages and API route handlers (app/api/). Initially, we placed our Python function (extract_recipe.py) inside a root /api directory, following the standard Vercel convention for Serverless Functions:

.
├── api  // <--- ORIGINAL location for Python function
│   └── extract_recipe.py
├── app
│   ├── api  // Next.js API Routes (incl. /api/auth/[...nextauth]/route.ts)
│   │   ├── auth
│   │   │   └── [...nextauth]
│   │   │       └── route.ts
│   │   └── ... (other Next.js API routes)
│   └── ... (other Next.js app files: pages, components, etc.)
├── requirements.txt       // Python dependencies (in root)
├── vercel.json            // Vercel configuration file (in root)
├── next.config.js
├── package.json
└── ... (other project files)

With this structure, we encountered a conflict. Requests to our Next.js API routes, specifically Next-Auth endpoints like /api/auth/signin (handled by app/api/auth/[…nextauth]/route.ts), started returning 404 errors when running vercel dev or when deployed. We believe this happened because Vercel’s routing prioritized the root /api directory (containing the Python function) for all requests starting with /api/…, preventing these requests from reaching the intended Next.js application handlers in app/api/.

Troubleshooting Step: Renaming the Python Directory

To resolve the conflict with Next.js API routes, we renamed the root directory containing our Python function from api to serverless-functions:

.
-├── api
-│   └── extract_recipe.py
+├── serverless-functions // <--- RENAMED location for Python function
+│   └── extract_recipe.py
├── app
│   ├── api  // Next.js API Routes (incl. /api/auth/[...nextauth]/route.ts)
│   │   ├── auth
│   │   │   └── [...nextauth]
│   │   │       └── route.ts
│   │   └── ... (other Next.js API routes)
│   └── ... (other Next.js app files: pages, components, etc.)
├── requirements.txt       // Python dependencies (in root)
├── vercel.json            // Vercel configuration file (in root)
├── next.config.js
├── package.json
└── ... (other project files)

This renaming step successfully resolved the 404 errors for our Next.js /api/auth/… routes, confirming the path conflict was the cause.

Attempts to Configure the Renamed Python Function:

Now, needing to make the Python function work from the new serverless-functions directory, we took the following steps:

  1. Directory Renamed: Function is now at /serverless-functions/extract_recipe.py.

  2. Created requirements.txt: Ensured a requirements.txt file exists in the project root listing all necessary Python dependencies (Flask, requests, etc.).

  3. Configured vercel.json: Created/updated vercel.json in the root to explicitly define the function and its route:

{
  "functions": {
    "serverless-functions/extract_recipe.py": {
      "runtime": "@vercel/python", // Also tried without this line
      "memory": 1024,
      "maxDuration": 30
    }
  },
  "routes": [
    {
      // Route requests to the function path to the python file
      "src": "/serverless-functions/extract_recipe",
      "dest": "serverless-functions/extract_recipe.py"
    },
    {
      // Fallback route for Next.js
      "src": "/(.*)",
      "dest": "/$1"
    }
  ]
}
  1. Verified Python Code: Confirmed that serverless-functions/extract_recipe.py is a valid Flask application defining an app = Flask(name) object at the module level and uses @app.route(‘/’) to handle requests routed to it by Vercel.

Current Issue:

Despite these configurations after renaming the directory, when running vercel dev, we now encounter the following error:

Error: The pattern "serverless-functions/extract_recipe.py" defined in `functions` doesn't match any Serverless Functions.

This error occurs even though the file exists at that path, requirements.txt is present, and the Python file contains a valid Flask app structure. It seems the Vercel build/dev process isn’t recognizing or discovering the Python file as a valid function now that it’s outside the default /api directory, even with the explicit vercel.json configuration.

Question:

Could you please help us understand why the functions configuration in vercel.json isn’t correctly identifying our Python function located at serverless-functions/extract_recipe.py after we renamed its parent directory from api/ to resolve conflicts with Next.js API routes? What is the correct way to configure vercel.json (or any other necessary steps) to allow our Python Flask function in the serverless-functions directory to be deployed and routed correctly alongside our Next.js App Router application, ensuring that Next.js API routes under app/api/ (especially /api/auth/…) also continue to function without conflict?

Thank you for your assistance.

Best regards,

Mike

Hi @jmqcooper, welcome to the Vercel Community!

Sorry that you’re facing this issue.

Vercel looks for the serverless functions in the /api this is why you should create the Python route handler in there.

But, given your project has a /api route from the Next.js app, it’ll have confusion when routing. That’s why I think a better approach would be to name the app/api folder as app/bff-api or something similar.

Now coming to the vercel.json:

  • routes is a legacy configuration option and we don’t recommend using it. Instead use the rewrites option.
  • functions is used to provide additional config to the severless functions such as memory and max duration. But it is only used when Vercel recognizes the functions. In our case, Vercel doesn’t know about the functions unless they are at api/.

I hope this was helpful.

Hi,

I tried this, but with no success. Could we perhaps talk about the potential solution on a support email?

Mike

I see. If you need more help, please share your public repo or a minimal reproducible example. That will let us all work together from the same code to figure out what’s going wrong.