Flask and Next.js are two unique open source web frameworks built on top of the Python and JavaScript programming languages, respectively.
You can build a Flask application without Next.js, and you can also build a Next.js app without Flask. However, you might find yourself in a situation where you’ve built an application with Flask and later decide to use Next.js for server-side rendering.
So, what do you do at this point?
One thing you can try is to incrementally adopt Next.js or Flask. In this article, I’ll show you how to make Next.js work seamlessly with a Flask API using the Next.js incremental adoption design, and how you can deploy it with Nginx on an Ubuntu server.
To jump ahead in this article:
Let’s start by building a sample Next.js application. Following the official Next.js documentation, run the following command to install Next.js on your computer: npx create-next-app@latest
. Follow the instructions to set up a basic app.
This installation will give us a “Hello, World!” app, ready for deployment. If all goes well, you can run yarn run dev
on the terminal and visit localhost:3000
on your browser to confirm that it works. You should see something like this:
That’s all there is to it for now. Next, let’s build a basic Flask API. I’ll assume you have Python installed, but if you don’t, you can install it by following the instructions in the official documentation for your OS.
First, let’s create and activate a virtual environment to contain the Python application.
python3 -m venv env & source ./env/bin/activate
Next, install Flask by running the following command in your terminal. We’ll use Flask-RESTful to create a restful API:
pip install Flask flask-restful
Then, create a file called hello.py
and add the following code to it:
from flask import Flask from flask_restful import reqparse, Api, Resource app = Flask(__name__) api = Api(app) parser = reqparse.RequestParser() parser.add_argument('task') class Message(Resource): def get(self): return {"message": 'Hello World'} api.add_resource(Message, '/api/hello') if __name__ == '__main__': app.run(debug=True)
Now, we have both the Flask and the Next.js app set up. Let’s proceed with making them work together.
Next.js rewrites allow you to map an incoming request path to a different destination path.
Move into the directory of the Next.js app we just created, open the next.config.js
file, and replace the content with the code below:
module.exports = () => { const rewrites = () => { return [ { source: "/hello/:path*", destination: "http://localhost:5000/hello/:path*", }, ]; }; return { rewrites, }; };
With this integration, we can access all of our API routes directly from Next.js as though the API is in the same domain and port as the Next.js client. This means we’ll only need to call http://localhost:3000/api/
and that we’ll be able to reach the API at port 5000
indirectly.
Let’s look at an example.
Open the /pages/index.js
file and replace its component with the “Hello, World!” component below:
import styles from '../styles/Home.module.css' import { useEffect, useState } from 'react' export default function Home() { const [message, setMessage] = useState(""); const [loading, setLoading] = useState(true); useEffect(() => { fetch('/hello/') .then(res => res.json()) .then(data => { setMessage(data.message); setLoading(false); }) }, []) return ( <div className={styles.container}> <p> {!loading ? message : "Loading.."}</p> </div> ) }
The code above is a simple Next.js component that talks to the Flask API using Fetch. As you can see, we didn’t have to put the exact URL in the call to the API. Next.js understood it based on the settings we initially set.
Of course, you can also choose to call the Flask API directly.
Now that we have a working integration, let’s proceed to deployment in Nginx. Install Nginx on your server (an Ubuntu server, in our case), create a config file for your Nginx configuration, which we’ll call nextflask
, and add the following code to the file:
/** /etc/nginx/sites-available/nextflask **/ server { server_name yourdomainname.com www.yourdomainname.com; listen 80; location /hello/ { proxy_pass http://127.0.0.1:5000/hello/; proxy_http_version 1.1; proxy_set_header Connection "upgrade"; proxy_set_header Host $host; proxy_set_header Upgrade $http_upgrade; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; } location / { proxy_pass http://0.0.0.0:3000; proxy_http_version 1.1; proxy_set_header Connection "upgrade"; proxy_set_header Host $host; proxy_set_header Upgrade $http_upgrade; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; } }
The Nginx config above will serve your Next.js app on the root domain yourdomainname.com
and serve your API on yourdomainname.com/api/hello
.
After adding this configuration, start Nginx by running the command below:
sudo systemctl start nginx.service
That’s it for setting up Nginx to serve our Flask API and Next.js server. Push your Flask and Next.js code to your server, install the dependencies, and run them separately. Oh, wait, we’ll need to daemonize them.
You can daemonize a Flask app with either Supervisor or Gunicorn, which are two popular tools for deploying Python applications.
We’ll use Gunicorn for Flask and PM2 for Next.js.
Let’s start with running the Flask API with Gunicorn. Ensure that you have a working Python installation on your server, then create a virtual environment to install Gunicorn.
Create a virtual environment:
python3 -m venv env
Then, install Gunicorn and Flask:
pip install gunicorn flask
First, create a wsgi.py
file in the root directory. This will serve as the entry point of the application. Add the following code to the file:
// wsgi.py from hello import app if __name__ == "__main__": app.run()
Next, create config file sudo vim /etc/systemd/system/hello.service
for Gunicorn and add the following configuration to it:
[Unit] Description=Gunicorn instance to serve hello After=network.target [Service] User=eze Group=www-data WorkingDirectory=/path/to/your/app/directory ExecStart=/path/to/gunicorn/bin/gunicorn --workers 3 --bind unix:hello.sock -m 007 wsgi:app [Install] WantedBy=multi-user.target
Pay attention to the reference paths. Finally, start and enable Gunicorn by running the following command in your terminal:
sudo systemctl start hello & sudo systemctl enable hello
To check if the operation was successful, review the status by running the command below:
sudo systemctl status
If all goes well, our Flask app should be up and running on port 500
and in the root domain, yourdomainname.com
.
PM2 is a process management tool for Node.js applications. To use it, install PM2 globally with the following command:
pm2 install -g pm2
Next, run this command in the directory that has your Next.js code:
pm2 start "npm run start" --name nextapp
Your Next.js application will start working on port 3000
and in the root domain, yourdomainname.com
.
Congratulations! You have successfully deployed your Next.js frontend with your Flask API. It might seem complicated at first, but you won’t have to repeat this process in your future deployments, because this sets the basic environment for your application to work properly. You might only need to push your code and restart your server, which can be managed by your CI/CD pipeline.
New technologies come and go all the time, and now might be the time for you to choose to deploy Next.js with Flask to improve the general engineering of your application. I hope you find this article helpful.
Personally, I had an old Flask API, but I wanted to continue development with Next.js while retaining some of the Python backend implementations. I found it very easy to switch without interrupting or breaking my existing API.
Check out this sample Next.js project, which you can clone to replicate the process from this article. Cheers!
Debugging Next applications can be difficult, especially when users experience issues that are difficult to reproduce. If you’re interested in monitoring and tracking state, automatically surfacing JavaScript errors, and tracking slow network requests and component load time, try LogRocket.
LogRocket is like a DVR for web and mobile apps, recording literally everything that happens on your Next.js app. Instead of guessing why problems happen, you can aggregate and report on what state your application was in when an issue occurred. LogRocket also monitors your app's performance, reporting with metrics like client CPU load, client memory usage, and more.
The LogRocket Redux middleware package adds an extra layer of visibility into your user sessions. LogRocket logs all actions and state from your Redux stores.
Modernize how you debug your Next.js apps — start monitoring for free.
Hey there, want to help make our blog better?
Join LogRocket’s Content Advisory Board. You’ll help inform the type of content we create and get access to exclusive meetups, social accreditation, and swag.
Sign up nowBuild scalable admin dashboards with Filament and Laravel using Form Builder, Notifications, and Actions for clean, interactive panels.
Break down the parts of a URL and explore APIs for working with them in JavaScript, parsing them, building query strings, checking their validity, etc.
In this guide, explore lazy loading and error loading as two techniques for fetching data in React apps.
Deno is a popular JavaScript runtime, and it recently launched version 2.0 with several new features, bug fixes, and improvements […]
One Reply to "Deploying Next.js with Flask"
It is not clear where you put the “hello.py” file. You did not “cd basic-app” so it is to be assumed that you put the “hello.py” file and “env” in the directory above “basic-app”. However, following your instructions up to (but excluding) the Nginx part, I get “Unhandled Runtime Error
SyntaxError: JSON.parse: unexpected character at line 1 column 1 of the JSON data”.