Build a Simple SaaS App in Python (Flask) – FULL CODE

SaaS (Software as a Service) apps are everywhere — Netflix, Dropbox, Notion — and you can build your own even as a beginner. In this tutorial, we’ll build a simple SaaS web app in Python using Flask. You’ll get:

  • Login & signup system
  • Free vs Pro plan logic
  • Protected SaaS feature
  • HTML Templates
  • Full Python code

Project Overview

We’ll build a Text Summarizer SaaS:

  • Free users can summarize 1 text per day
  • Pro users get unlimited summaries
  • Upgrade button available

Project Structure

saas-app/

├── app.py
├── models.py
├── templates/
   ├── base.html
   ├── home.html
   ├── signup.html
   ├── login.html
   ├── dashboard.html
   ├── upgrade.html

Step 1 – Install Dependencies

mkdir saas-app
cd saas-app
pip install flask flask-login flask-bcrypt

models.py

from flask_login import UserMixin
from flask_bcrypt import generate_password_hash, check_password_hash

# In-memory database simulation
users = []
usage = {}

class User(UserMixin):
    def __init__(self, id, email, password, plan="free"):
        self.id = id
        self.email = email
        self.password_hash = generate_password_hash(password).decode('utf-8')
        self.plan = plan

    def check_password(self, password):
        return check_password_hash(self.password_hash, password)

app.py

from flask import Flask, render_template, request, redirect, url_for
from flask_login import LoginManager, login_user, login_required, logout_user, current_user
from models import User, users, usage

app = Flask(__name__)
app.secret_key = "supersecretkey"

login_manager = LoginManager(app)
login_manager.login_view = "login"

@login_manager.user_loader
def load_user(user_id):
    return users[int(user_id)]

@app.route("/")
def home():
    return render_template("home.html")

@app.route("/signup", methods=["GET", "POST"])
def signup():
    if request.method == "POST":
        email = request.form["email"]
        password = request.form["password"]
        user = User(len(users), email, password)
        users.append(user)
        login_user(user)
        return redirect(url_for("dashboard"))
    return render_template("signup.html")

@app.route("/login", methods=["GET", "POST"])
def login():
    if request.method == "POST":
        email = request.form["email"]
        password = request.form["password"]
        for user in users:
            if user.email == email and user.check_password(password):
                login_user(user)
                return redirect(url_for("dashboard"))
    return render_template("login.html")

@app.route("/logout")
@login_required
def logout():
    logout_user()
    return redirect(url_for("home"))

@app.route("/dashboard")
@login_required
def dashboard():
    return render_template("dashboard.html", plan=current_user.plan)

@app.route("/summarize", methods=["POST"])
@login_required
def summarize():
    text = request.form["text"]
    user_id = current_user.id

    if current_user.plan == "free":
        usage[user_id] = usage.get(user_id, 0)
        if usage[user_id] >= 1:
            return redirect(url_for("upgrade"))
        usage[user_id] += 1

    summary = text[:50] + "..."
    return render_template("dashboard.html", plan=current_user.plan, summary=summary)

@app.route("/upgrade")
@login_required
def upgrade():
    return render_template("upgrade.html")

if __name__ == "__main__":
    app.run(debug=True)

HTML Templates

Create a folder called templates and add the files below.

templates/base.html

<!DOCTYPE html>
<html>
<head>
    <title>Python SaaS Example</title>
    <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css">
</head>
<body class="bg-light">
<nav class="navbar navbar-dark bg-dark px-3">
    <a class="navbar-brand" href="/">Mini SaaS</a>
    {% if current_user.is_authenticated %}
        <a class="btn btn-danger" href="/logout">Logout</a>
    {% else %}
        <a class="btn btn-success" href="/login">Login</a>
    {% endif %}
</nav>
<div class="container mt-4">
    {% block content %}{% endblock %}
</div>
</body>
</html>

🏠 templates/home.html

{% extends "base.html" %}
{% block content %}
<h2>Welcome to Mini SaaS App</h2>
<p>Create summaries and upgrade anytime!</p>
<a href="/signup" class="btn btn-primary">Get Started</a>
{% endblock %}

✍️ templates/signup.html

{% extends "base.html" %}
{% block content %}
<h2>Sign Up</h2>
<form method="POST">
    <input class="form-control mb-2" name="email" placeholder="Email" required>
    <input class="form-control mb-2" type="password" name="password" placeholder="Password" required>
    <button class="btn btn-primary">Sign Up</button>
</form>
{% endblock %}

🔐 templates/login.html

{% extends "base.html" %}
{% block content %}
<h2>Log In</h2>
<form method="POST">
    <input class="form-control mb-2" name="email" placeholder="Email" required>
    <input class="form-control mb-2" type="password" name="password" placeholder="Password" required>
    <button class="btn btn-success">Log In</button>
</form>
{% endblock %}

📊 templates/dashboard.html

{% extends "base.html" %}
{% block content %}
<h2>Dashboard</h2>
<p>Your plan: <strong>{{ plan }}</strong></p>

<form method="POST" action="/summarize">
    <textarea name="text" class="form-control mb-2" placeholder="Enter text to summarize" required></textarea>
    <button class="btn btn-warning">Summarize</button>
</form>

{% if summary %}
    <div class="alert alert-success mt-3">
        {{ summary }}
    </div>
{% endif %}
{% endblock %}

💳 templates/upgrade.html

{% extends "base.html" %}
{% block content %}
<h2>Upgrade to Pro</h2>
<p>Free users can only summarize once. Go Pro for unlimited usage!</p>
<button class="btn btn-success">Upgrade Now (Stripe Coming Soon)</button>
{% endblock %}

✅ Run the App

python app.py

Open: http://127.0.0.1:5000

Leave a Reply