Deploy Models with Flask APIs

Learn to deploy your machine learning models as Flask APIs — a practical Python for data science lesson with hands-on steps, troubleshooting, and next steps.

Focus: deploy models with flask apis

Sponsored

You’ve spent hours training a model — tuning hyperparameters, squeezing out that last 0.01 accuracy, and validating on a holdout set. But when it’s time to share your work with the world, you hit a wall: how do you let others use your model without handing them the training code and data? The answer is deploying models with Flask APIs — turning your Python model into a live web service that anyone can call with a simple HTTP request. In this lesson, you’ll learn the core concept, build a complete Flask API step by step, and troubleshoot the common pitfalls that trip up even experienced data scientists. By the end, you’ll have a deployable model endpoint you can connect to a frontend, a mobile app, or another microservice.

The problem this lesson solves

Your model is useless if it only lives in a Jupyter notebook. Real-world users — whether they’re analysts, customer-facing apps, or other services — need a way to send input data and receive predictions reliably and securely. Without an API, you’re forced to export predictions manually, share scripts, or let someone dig through your codebase. That’s slow, fragile, and often dangerous (imagine exposing your training data by accident).

Deploying models with Flask APIs solves this by wrapping your model in a lightweight web server. The server listens for requests, runs the model, and returns a JSON response. It’s the same pattern used by production ML systems — think Netflix recommendations or spam filters — but you can start small and scale up.

Pro tip: You don’t need a heavyweight framework like Django or FastAPI to start. Flask’s minimal design makes it perfect for a single-model endpoint — and it’s already familiar if you’ve done any web work in Python.

Core concept / mental model

Think of your model as a black-box function: input goes in, prediction comes out. A Flask API is the delivery mechanism that lets external clients call that function over the network.

Here’s the mental model in three layers:

  1. Model layer — your trained scikit-learn, TensorFlow, or PyTorch model (often saved to a file like model.pkl).
  2. API layer — the Flask app that loads the model once, exposes an endpoint (e.g., /predict), and handles incoming requests.
  3. Client layer — anything that sends HTTP requests: a web form, a mobile app, curl in your terminal, or another Python script.

The flow looks like this:

Client --POST JSON--> Flask app --> load model --> preprocess --> predict --> return JSON

Definitions to keep straight:

  • Endpoint — the URL path (e.g., /predict) that triggers your function.
  • Request — the HTTP message from the client, usually containing input data (as JSON).
  • Response — the HTTP message back, typically including the prediction and a status code.
  • Serialization — converting your model to a file (using pickle or joblib) so it can be loaded later.

Once your model is behind a Flask API, it’s deployed in the most basic sense: it’s accessible to external callers. The same pattern works whether you run it on your laptop, a cloud VM, or a container.

How it works step by step

Deploying a model with Flask boils down to four steps. Let’s go through each in order.

1. Train and save your model

You can’t deploy a model that isn’t persisted. Use joblib (preferred for scikit-learn) or pickle to save the trained object to disk. This file is your deployable artifact.

# train_and_save.py
from sklearn.datasets import load_iris
from sklearn.ensemble import RandomForestClassifier
import joblib

# Load data and train
data = load_iris()
X, y = data.data, data.target
model = RandomForestClassifier(n_estimators=100)
model.fit(X, y)

# Save the model
joblib.dump(model, 'iris_model.pkl')
print("Model saved to iris_model.pkl")

Expected output:

Model saved to iris_model.pkl

2. Create the Flask app

Build a minimal Flask app with a single route. The route receives JSON, converts it to the format your model expects, and calls predict().

# app.py
from flask import Flask, request, jsonify
import joblib
import numpy as np

app = Flask(__name__)

# Load the model once at startup
model = joblib.load('iris_model.pkl')

@app.route('/predict', methods=['POST'])
def predict():
    data = request.get_json()
    features = np.array(data['features']).reshape(1, -1)
    prediction = model.predict(features)
    return jsonify({'prediction': int(prediction[0])})

if __name__ == '__main__':
    app.run(host='0.0.0.0', port=5000)

3. Run the server

Start the Flask app with python app.py. By default it runs on port 5000. The host='0.0.0.0' makes it accessible outside your local machine (e.g., from a Docker container or another device on your network).

4. Test the API

Use curl or Python to send a POST request with sample features. You should get back a JSON response.

curl -X POST http://127.0.0.1:5000/predict \
  -H "Content-Type: application/json" \
  -d '{"features": [5.1, 3.5, 1.4, 0.2]}'

Expected response:

{"prediction":0}

Pro tip: Always load your model at the top level (module scope), not inside the route function. Loading is expensive — you don’t want it to happen on every request.

Hands-on walkthrough

Let’s build a complete, runnable example from scratch. We’ll use a simple linear regression model (your own model can be swapped in).

Step 1: Install dependencies

pip install flask scikit-learn joblib

Step 2: Save the model (run once)

# save_model.py
from sklearn.linear_model import LinearRegression
import joblib, numpy as np

# Dummy data: y = 2*x + 1
X = np.array([[1], [2], [3], [4]])
y = np.array([3, 5, 7, 9])

model = LinearRegression().fit(X, y)
joblib.dump(model, 'linreg.pkl')
print("Saved")

Step 3: Write the Flask API

# app.py
from flask import Flask, request, jsonify
import joblib
import numpy as np

app = Flask(__name__)
model = joblib.load('linreg.pkl')

@app.route('/predict', methods=['POST'])
def predict():
    try:
        data = request.get_json()
        features = np.array(data['features'])
        features = features.reshape(1, -1)
        pred = model.predict(features)
        return jsonify({'prediction': float(pred[0])})
    except Exception as e:
        return jsonify({'error': str(e)}), 400

if __name__ == '__main__':
    app.run(host='0.0.0.0', port=5000, debug=True)

Step 4: Run and test

Start the server in one terminal:

python app.py

In another terminal, send a request:

# test_request.py
import requests

resp = requests.post(
    'http://127.0.0.1:5000/predict',
    json={'features': [10]}
)
print(resp.json())

Expected output:

{'prediction': 21.0}

Notice the error handling: if the client sends malformed data, you return a 400 status with an error message instead of a confusing crash.

Pro tip: When you’re ready for production, set debug=False — the debugger can expose sensitive code and is a security risk.

Compare options / when to choose what

Flask isn’t your only choice. Here’s a quick comparison:

Framework Best for Pros Cons
Flask Simple single-model APIs Minimal, familiar, huge ecosystem Sync by default, not built for heavy async
FastAPI High-performance, async, auto docs Asynchronous, Pydantic validation, automatic OpenAPI docs Slightly steeper learning curve
Django REST Full web apps + API Batteries included (auth, admin) Heavy for just a model endpoint
TensorFlow Serving TensorFlow models at scale Optimized for TF, batching TF-specific, more ops overhead

For most data science projects, Flask is the right starting point — it’s simple to debug, quick to prototype, and the skills transfer to FastAPI if you outgrow it. Choose FastAPI if you expect high concurrency or need auto-generated docs. Choose TensorFlow Serving only when your model is TensorFlow and performance is critical.

Pro tip: Deployment is a spectrum. Start with Flask on your laptop, then move to a cloud VM (AWS, GCP) or containerize with Docker. Your API code stays the same — only the host changes.

Troubleshooting & edge cases

The most common issues when deploying models with Flask APIs are:

  • Model not found (FileNotFoundError) — Make sure the .pkl file is in the same directory as your Flask app, or use an absolute path.
  • JSON shape mismatch — Your client sends a different number of features than your model expects. Use np.array(data['features']).reshape(1, -1) — but verify the feature count matches the training data.
  • CORS errors — If your frontend is on a different origin, you need to add CORS headers. Use the flask-cors package.
  • Port already in use — If port 5000 is taken, change it with port=5001 or kill the existing process.
  • Model not serializable — Some custom objects (e.g., custom transformers) fail with pickle. Use joblib and test the save/load cycle before deployment.

Real-world example of a shape error:

# Wrong: data['features'] = [1, 2, 3] but your model was trained on 4 features
features = np.array([1, 2, 3]).reshape(1, -1)  # shape (1,3) -> error

Fix: make sure your request JSON includes all features, and consider adding a validation step:

if len(features[0]) != model.n_features_in_:
    return jsonify({'error': f'Expected {model.n_features_in_} features, got {len(features[0])}'}), 400

Pro tip: Always wrap your prediction logic in a try/except and return a meaningful error message with a status code. Your API users will thank you.

What you learned & what's next

In this lesson, you learned how to deploy models with Flask APIs — the essential skill for turning your trained models into live services. You now understand:

  • Why deployment matters (models become usable by others)
  • The mental model of model → API → client
  • How to save a model with joblib and load it in a Flask app
  • How to build a /predict endpoint that accepts JSON and returns JSON
  • How to test your API with curl and Python
  • How to compare Flask with other frameworks and choose the right tool
  • Common pitfalls like shape mismatches and CORS, and how to fix them

You’ve met both learning objectives: you can explain the core idea behind deploying models with Flask APIs, and you’ve completed a practical exercise that builds and tests a working endpoint.

What’s next? In the next lesson, you’ll take your deployment further by adding input validation, authentication, and versioning — turning your basic API into a production-ready service. You’ll also explore containerization with Docker to make your API portable and scalable.

Keep this lesson fresh: every time you train a new model, practice deploying it as a Flask API before moving on. It’s a skill that will pay off in every project from here on.

Practice recap

As a next step, try deploying a model you’ve already trained in this track. Save it with joblib, build a Flask API with a /predict endpoint, and test it with curl. If you’re feeling ambitious, add a second endpoint like /health that returns a 200 status, and containerize the whole thing with a simple Dockerfile.

Common mistakes

  • Loading the model inside the route function — this slows down every request and can cause memory issues.
  • Forgetting to reshape the input to the shape the model expects (e.g., using a list instead of a 2D array).
  • Not handling exceptions in the /predict endpoint, so any bad input causes a crash.
  • Using pickle instead of joblib for scikit-learn models, which can fail with certain estimators.
  • Running Flask with debug=True in production, exposing sensitive information.

Variations

  1. Use FastAPI instead of Flask for asynchronous handling and automatic OpenAPI documentation.
  2. Containerize your Flask app with Docker to ensure consistent environments across machines.
  3. Use the flask-cors package to enable cross-origin requests from frontend applications.

Real-world use cases

  • A data scientist deploys a churn prediction model as a Flask API for the customer service team to query in real time.
  • An e-commerce startup exposes a product recommendation model via a Flask endpoint that the website frontend calls on each page load.
  • A research lab shares a medical diagnosis model as a Flask API so clinicians can submit patient data and get predictions securely.

Key takeaways

  • Deploying models with Flask wraps your model in a web server, making it accessible via HTTP requests.
  • Always save your trained model with joblib (or pickle) and load it once at the top of your Flask app.
  • A /predict endpoint with POST method receives JSON, preprocesses it, runs the model, and returns JSON.
  • Test your API with curl or requests to ensure it works before integrating with clients.
  • Choose Flask for simplicity, FastAPI for async performance, and Docker for production-grade portability.
  • Handle errors and validate input to make your API robust and user-friendly.

Sponsored

Sponsored

Discussion

Questions, corrections, and tips help everyone reading this page.

0 comments

Add a comment

Shown publicly with your comment.

Be constructive · max 4,000 characters

No comments yet — start the thread.

Related tutorials, quizzes, and articles for this topic.