I'm building my project from this template. When I deploy, I'm encountering persistent 404 NOT_FOUND
errors for all Flask endpoints (e.g., /api/news-galore
, /api/raw
, /api/
) and the root page (/
) of my Next.js app fails to load on /. The deployment succeeds (READY
state), but the backend doesn’t seem to be serving requests, and the frontend likely fails due to a dependent API call. I’ve tried updating vercel.json
, adding pyproject.toml
, and setting environment variables, but the issue persists.
Here is my directory -
nextjs-flask/
├── api/
│ ├── index.py
│ ├── requirements.txt
│ └── pyproject.toml
├── app/
│ ├── page.tsx
│ ├── components/
│ │ ├── FeedTray.tsx
│ │ ├── navbar.tsx
│ │ └── newsTile.tsx
│ └── routings/
│ ├── login/
│ │ └── page.tsx
│ ├── signup/
│ │ └── page.tsx
│ └── profile/
│ └── page.tsx
├── next.config.js
├── vercel.json
├── package.json
└── .vercelignore
Here are my endpoints file, api/index.py
-
from flask import Flask, jsonify, request, make_response
from flask_cors import CORS
from dotenv import load_dotenv
import os
from news_lambda import news_app_lambda
from user_lambda import user_app_lambda
from mongoengine import connect
import boto3
load_dotenv()
app = Flask(__name__)
CORS(app, supports_credentials=True, origins=["http://localhost:3000", ";])
connect(host=os.getenv("MONGO_URI"))
@app.route('/', methods=['GET'])
def health_check():
return jsonify({"status": "ok"}), 200
@app.route('/news-galore', methods=['GET'])
def news_galore():
session = request.cookies.get('session')
if not session:
return jsonify({"error": "Unauthorized"}), 401
lambda_client = boto3.client('lambda', region_name='us-east-1',
aws_access_key_id=os.getenv('AWS_ACCESS_KEY_ID'),
aws_secret_access_key=os.getenv('AWS_SECRET_ACCESS_KEY'))
response = lambda_client.invoke(FunctionName='news-app-lambda',
InvocationType='RequestResponse',
Payload=bytes(json.dumps({"session": session}).encode()))
return jsonify(json.loads(response['Payload'].read().decode('utf-8'))), 200
@app.route('/raw', methods=['GET'])
def hello_world():
session = request.cookies.get('session')
if not session:
return jsonify({"error": "Unauthorized"}), 401
lambda_client = boto3.client('lambda', region_name='us-east-1',
aws_access_key_id=os.getenv('AWS_ACCESS_KEY_ID'),
aws_secret_access_key=os.getenv('AWS_SECRET_ACCESS_KEY'))
response = lambda_client.invoke(FunctionName='news-app-lambda',
InvocationType='RequestResponse',
Payload=bytes(json.dumps({"session": session}).encode()))
return jsonify(json.loads(response['Payload'].read().decode('utf-8'))), 200
@app.route('/signup', methods=['POST'])
def signup():
data = request.get_json()
email = data.get('email')
password = data.get('password')
# Signup logic here
return jsonify({"message": "Signup successful"}), 200
@app.route('/login', methods=['POST'])
def login():
data = request.get_json()
email = data.get('email')
password = data.get('password')
# Login logic here
resp = make_response(jsonify({"message": "Login successful"}))
resp.set_cookie('session', 'dummy_session_token', httponly=True)
return resp, 200
@app.route('/logout', methods=['GET'])
def logout():
resp = make_response(jsonify({"message": "Logout successful"}))
resp.set_cookie('session', '', expires=0)
return resp, 200
@app.route('/user', methods=['GET'])
def get_user():
session = request.cookies.get('session')
if not session:
return jsonify({"error": "Unauthorized"}), 401
# User logic here
return jsonify({"user": "user_data"}), 200
@app.route('/preferences', methods=['POST'])
def update_preferences():
session = request.cookies.get('session')
if not session:
return jsonify({"error": "Unauthorized"}), 401
data = request.get_json()
preferences = data.get('preferences')
# Preferences logic here
return jsonify({"message": "Preferences updated"}), 200
if __name__ == '__main__':
app.run(debug=True, host='0.0.0.0', port=5000)
requirements.txt
-
flask==2.3.3
flask-cors==4.0.0
requests==2.31.0
python-dotenv==1.0.0
boto3==1.28.57
werkzeug==3.0.1
mongoengine==0.27.0
pymongo==4.5.0
Here is pyproject.toml
-
[tool.vercel]
runtime = "python3.9"
[build-system]
requires = ["setuptools>=61.0"]
build-backend = "setuptools.build_meta"
[project]
name = "news-app-flask"
version = "0.1.0"
dependencies = [
"flask==2.3.3",
"flask-cors==4.0.0",
"requests==2.31.0",
"python-dotenv==1.0.0",
"boto3==1.28.57",
"werkzeug==3.0.1",
"mongoengine==0.27.0",
"pymongo==4.5.0"
]
Here is next.config.js
-
/** @type {import('next').NextConfig} */
const nextConfig = {
rewrites: async () => {
return [
{
source: '/api/:path*',
destination:
process.env.NODE_ENV === 'development'
? 'http://127.0.0.1:5000/api/:path*'
: '/api/:path*',
},
];
},
};
module.exports = nextConfig;
app/page.tsx
-
"use client";
import { useEffect, useState } from "react";
import FeedTray from "../components/FeedTray";
export default function Home() {
const [isAuthenticated, setIsAuthenticated] = useState(false);
useEffect(() => {
fetch("/api/news-galore", { credentials: "include" })
.then((response) => response.json())
.then((data) => {
if (data.error !== "Unauthorized") {
setIsAuthenticated(true);
}
})
.catch((error) => console.error("Error fetching news:", error));
}, []);
return isAuthenticated ? <FeedTray /> : null;
}
...
here is vercel deployment log snippets -
[client-debug] 2025-04-03T18:25:45.297Z Deployment state changed to READY
[client-debug] 2025-04-03T18:25:45.297Z Yielding a 'ready' event
> [debug] [2025-04-03T18:25:45.297Z] Spinner invoked (Completing) with a 0ms delay
[client-debug] 2025-04-03T18:25:45.297Z Deployment alias assigned
❗️ Due to `builds` existing in your configuration file, the Build and Development Settings defined in your Project Settings will not apply. Learn More: /unused-build-settings
curl tests -
curl -X GET /api/news-galore -b "session=your-session-cookie"
The page could not be found
NOT_FOUND
bom1::h7mvg-1743703843749-4884836164a0
curl -X GET /api/
The page could not be found
NOT_FOUND
bom1::6d666-1743703058469-f05ee13be576
Can anyone help me identify why the Flask backend isn’t serving requests on Vercel and why the Next.js root page isn’t loading? I’d appreciate guidance on debugging the Vercel runtime logs or suggestions for fixing the configuration. Thank you!
I'm building my project from this template. When I deploy, I'm encountering persistent 404 NOT_FOUND
errors for all Flask endpoints (e.g., /api/news-galore
, /api/raw
, /api/
) and the root page (/
) of my Next.js app fails to load on https://newsapp-parthgupta.vercel.app/. The deployment succeeds (READY
state), but the backend doesn’t seem to be serving requests, and the frontend likely fails due to a dependent API call. I’ve tried updating vercel.json
, adding pyproject.toml
, and setting environment variables, but the issue persists.
Here is my directory -
nextjs-flask/
├── api/
│ ├── index.py
│ ├── requirements.txt
│ └── pyproject.toml
├── app/
│ ├── page.tsx
│ ├── components/
│ │ ├── FeedTray.tsx
│ │ ├── navbar.tsx
│ │ └── newsTile.tsx
│ └── routings/
│ ├── login/
│ │ └── page.tsx
│ ├── signup/
│ │ └── page.tsx
│ └── profile/
│ └── page.tsx
├── next.config.js
├── vercel.json
├── package.json
└── .vercelignore
Here are my endpoints file, api/index.py
-
from flask import Flask, jsonify, request, make_response
from flask_cors import CORS
from dotenv import load_dotenv
import os
from news_lambda import news_app_lambda
from user_lambda import user_app_lambda
from mongoengine import connect
import boto3
load_dotenv()
app = Flask(__name__)
CORS(app, supports_credentials=True, origins=["http://localhost:3000", "https://newsapp-parthgupta.vercel.app"])
connect(host=os.getenv("MONGO_URI"))
@app.route('/', methods=['GET'])
def health_check():
return jsonify({"status": "ok"}), 200
@app.route('/news-galore', methods=['GET'])
def news_galore():
session = request.cookies.get('session')
if not session:
return jsonify({"error": "Unauthorized"}), 401
lambda_client = boto3.client('lambda', region_name='us-east-1',
aws_access_key_id=os.getenv('AWS_ACCESS_KEY_ID'),
aws_secret_access_key=os.getenv('AWS_SECRET_ACCESS_KEY'))
response = lambda_client.invoke(FunctionName='news-app-lambda',
InvocationType='RequestResponse',
Payload=bytes(json.dumps({"session": session}).encode()))
return jsonify(json.loads(response['Payload'].read().decode('utf-8'))), 200
@app.route('/raw', methods=['GET'])
def hello_world():
session = request.cookies.get('session')
if not session:
return jsonify({"error": "Unauthorized"}), 401
lambda_client = boto3.client('lambda', region_name='us-east-1',
aws_access_key_id=os.getenv('AWS_ACCESS_KEY_ID'),
aws_secret_access_key=os.getenv('AWS_SECRET_ACCESS_KEY'))
response = lambda_client.invoke(FunctionName='news-app-lambda',
InvocationType='RequestResponse',
Payload=bytes(json.dumps({"session": session}).encode()))
return jsonify(json.loads(response['Payload'].read().decode('utf-8'))), 200
@app.route('/signup', methods=['POST'])
def signup():
data = request.get_json()
email = data.get('email')
password = data.get('password')
# Signup logic here
return jsonify({"message": "Signup successful"}), 200
@app.route('/login', methods=['POST'])
def login():
data = request.get_json()
email = data.get('email')
password = data.get('password')
# Login logic here
resp = make_response(jsonify({"message": "Login successful"}))
resp.set_cookie('session', 'dummy_session_token', httponly=True)
return resp, 200
@app.route('/logout', methods=['GET'])
def logout():
resp = make_response(jsonify({"message": "Logout successful"}))
resp.set_cookie('session', '', expires=0)
return resp, 200
@app.route('/user', methods=['GET'])
def get_user():
session = request.cookies.get('session')
if not session:
return jsonify({"error": "Unauthorized"}), 401
# User logic here
return jsonify({"user": "user_data"}), 200
@app.route('/preferences', methods=['POST'])
def update_preferences():
session = request.cookies.get('session')
if not session:
return jsonify({"error": "Unauthorized"}), 401
data = request.get_json()
preferences = data.get('preferences')
# Preferences logic here
return jsonify({"message": "Preferences updated"}), 200
if __name__ == '__main__':
app.run(debug=True, host='0.0.0.0', port=5000)
requirements.txt
-
flask==2.3.3
flask-cors==4.0.0
requests==2.31.0
python-dotenv==1.0.0
boto3==1.28.57
werkzeug==3.0.1
mongoengine==0.27.0
pymongo==4.5.0
Here is pyproject.toml
-
[tool.vercel]
runtime = "python3.9"
[build-system]
requires = ["setuptools>=61.0"]
build-backend = "setuptools.build_meta"
[project]
name = "news-app-flask"
version = "0.1.0"
dependencies = [
"flask==2.3.3",
"flask-cors==4.0.0",
"requests==2.31.0",
"python-dotenv==1.0.0",
"boto3==1.28.57",
"werkzeug==3.0.1",
"mongoengine==0.27.0",
"pymongo==4.5.0"
]
Here is next.config.js
-
/** @type {import('next').NextConfig} */
const nextConfig = {
rewrites: async () => {
return [
{
source: '/api/:path*',
destination:
process.env.NODE_ENV === 'development'
? 'http://127.0.0.1:5000/api/:path*'
: '/api/:path*',
},
];
},
};
module.exports = nextConfig;
app/page.tsx
-
"use client";
import { useEffect, useState } from "react";
import FeedTray from "../components/FeedTray";
export default function Home() {
const [isAuthenticated, setIsAuthenticated] = useState(false);
useEffect(() => {
fetch("/api/news-galore", { credentials: "include" })
.then((response) => response.json())
.then((data) => {
if (data.error !== "Unauthorized") {
setIsAuthenticated(true);
}
})
.catch((error) => console.error("Error fetching news:", error));
}, []);
return isAuthenticated ? <FeedTray /> : null;
}
...
here is vercel deployment log snippets -
[client-debug] 2025-04-03T18:25:45.297Z Deployment state changed to READY
[client-debug] 2025-04-03T18:25:45.297Z Yielding a 'ready' event
> [debug] [2025-04-03T18:25:45.297Z] Spinner invoked (Completing) with a 0ms delay
[client-debug] 2025-04-03T18:25:45.297Z Deployment alias assigned
❗️ Due to `builds` existing in your configuration file, the Build and Development Settings defined in your Project Settings will not apply. Learn More: https://vercel.link/unused-build-settings
curl tests -
curl -X GET https://newsapp-parthgupta.vercel.app/api/news-galore -b "session=your-session-cookie"
The page could not be found
NOT_FOUND
bom1::h7mvg-1743703843749-4884836164a0
curl -X GET https://newsapp-parthgupta.vercel.app/api/
The page could not be found
NOT_FOUND
bom1::6d666-1743703058469-f05ee13be576
Can anyone help me identify why the Flask backend isn’t serving requests on Vercel and why the Next.js root page isn’t loading? I’d appreciate guidance on debugging the Vercel runtime logs or suggestions for fixing the configuration. Thank you!
Share Improve this question edited Apr 3 at 20:07 Parth Gupta asked Mar 27 at 21:57 Parth GuptaParth Gupta 214 bronze badges1 Answer
Reset to default 0I couldn't find any clear solution so I am deploying backend and frontend separately.