Generate Flask API Boilerplate Code with AI

Tested prompts for ai generate flask app compared across 5 leading AI models.

BEST BY JUDGE SCORE GPT-5.4 8/10

If you searched 'ai generate flask app', you are probably staring at a blank file and need a working Flask API skeleton in the next few minutes, not the next few hours. You know Python, you know what your API needs to do, and you just want the boilerplate out of the way so you can focus on actual logic. That is exactly what AI code generation is built for.

Flask boilerplate is highly repetitive: app factory pattern, blueprint registration, error handlers, config classes, database initialization, JWT or API key middleware. Writing it from scratch every project wastes time and introduces inconsistency. AI models like GPT-4, Claude, and Gemini can produce a complete, runnable Flask project structure from a single detailed prompt in under ten seconds.

This page shows you the exact prompt structure that produces the best output, compares how four leading models handle it, and explains where AI-generated Flask code is solid versus where you need to verify it yourself before shipping. If you paste the prompt below into any capable model, you will have a working Flask app skeleton ready to extend.

When to use this

AI Flask generation is the right move when you need a production-shaped skeleton fast and the architecture is well-understood. REST APIs, internal tooling backends, microservices, and prototype APIs all fit. If you can describe the endpoints and data model in a paragraph, the AI can scaffold it cleanly.

  • Starting a new REST API and want a consistent project structure with blueprints, config, and error handling already wired up
  • Building a quick internal tool or admin API where you need CRUD endpoints over a single database model
  • Prototyping a startup MVP backend where speed to first working endpoint matters more than custom architecture
  • Scaffolding a microservice that needs JWT auth, a health-check route, and a predictable folder layout
  • Onboarding a new team member who needs a reference implementation of your standard Flask patterns

When this format breaks down

  • Your app has non-standard architecture requirements like async-first design, complex multi-tenant data isolation, or deeply nested blueprint hierarchies. AI output defaults to the common pattern and refactoring away from it costs more than writing it directly.
  • You are generating code for a security-sensitive context like payment processing or healthcare data without a thorough manual review. AI models produce plausible-looking auth and validation code that can have subtle logical flaws.
  • The project already has an established codebase with strong conventions. Dropping AI-generated scaffolding into an existing app usually creates style conflicts and duplicate abstractions.
  • You need a specific Flask extension combination the model has limited training data on, such as a niche third-party plugin or a very recent library version. The generated imports and configuration will likely be outdated or incorrect.

The prompt we tested

You are an expert Python developer specializing in building production-ready Flask APIs. Generate complete, runnable Flask application boilerplate code based on the user's requirements below.

Follow these instructions strictly:
Output a complete Flask app with a modular structure (app factory pattern, blueprints for routes, separate config.py, and requirements.txt). Include working CRUD endpoints matching the user's domain, proper error handling with JSON responses, and environment variable support via python-dotenv. Format code in labeled Markdown code blocks per file, and finish with a short 'How to Run' section listing install and launch commands.

User requirements:
I need a Flask REST API for a simple task manager. It should support creating, reading, updating, and deleting tasks with fields like title, description, and completed status. Use SQLite with SQLAlchemy and include basic input validation.

Return the full project structure and all necessary code files (app.py, requirements.txt, config, routes, models, etc.) with clear file headers, inline comments explaining key sections, and setup/run instructions at the end.

Model comparison

ModelQualityCostLatencyTokens
Claude Opus 4.7 6 $0.1589 18.7s 356 / 2048
Claude Haiku 4.5 7 $0.0105 11.3s 240 / 2048
GPT-5.4 8 $0.0313 25.1s 213 / 2048
Gemini 2.5 Pro 2 $0.0016 18.4s 219 / 259
Grok 4.1 Fast Reasoning 7 $0.0008 28.2s 362 / 1459

Outputs

Claude Opus 4.7 6/10
# Flask Task Manager REST API

A production-ready Flask REST API boilerplate for managing tasks with SQLite, SQLAlchemy, and input validation.

## Project Structure

```
task_manager/
├── app/
│   ├── __init__.py          # App factory
│   ├── extensions.py        # Flask extensions (db)
│   ├── models.py            # SQLAlchemy models
│   ├── schemas.py           # Input validation schemas
│   ├── errors.py            # Error handlers
│   └── routes/
│       ├── __init__.py
│       └── tasks.py         # Task blueprint with CRUD endpoints
├── config.py                # Configuration classes
├── .env.example             # Example environment variables
├── requirements.txt         # Python dependencies
└── run.py                   # Application entry point
```

---

### `requirements.txt`

```txt
Flask==3.0.3
Flask-SQLAlchemy==3.1.1
python-dotenv==1.0.1
marshmallow==3.21.3
```

---

### `config.py`

```python
"""
Configuration module.
Loads settings from environment variables with sensible defaults.
"""
import os
from dotenv import load_dotenv

# Load variables from .env file into os.environ
load_dotenv()

BASE_DIR = os.path.abspath(os.path.dirname(__file__))


class Config:
    """Base configuration shared across environments."""
    SECRET_KEY = os.getenv("SECRET_KEY", "dev-secret-change-me")
    # Default to a local SQLite file if DATABASE_URL isn't set
    SQLALCHEMY_DATABASE_URI = os.getenv(
        "DATABASE_URL", f"sqlite:///{os.path.join(BASE_DIR, 'tasks.db')}"
    )
    SQLALCHEMY_TRACK_MODIFICATIONS = False
    JSON_SORT_KEYS = False


class DevelopmentConfig(Config):
    DEBUG = True


class ProductionConfig(Config):
    DEBUG = False


class TestingConfig(Config):
    TESTING = True
    SQLALCHEMY_DATABASE_URI = "sqlite:///:memory:"


# Map string keys to config classes for easy lookup
config_by_name = {
    "development": DevelopmentConfig,
    "production": ProductionConfig,
    "testing": TestingConfig,
}
```

---

### `.env.example`

```env
# Copy this file to `.env` and adjust as needed
FLASK_ENV=development
SECRET_KEY=replace-with-a-secure-random-string
DATABASE_URL=sqlite:///tasks.db
```

---

### `app/extensions.py`

```python
"""
Centralized Flask extension instances.
Keeping them here prevents circular imports in the factory/blueprints.
"""
from flask_sqlalchemy import SQLAlchemy

db = SQLAlchemy()
```

---

### `app/models.py`

```python
"""
SQLAlchemy models.
"""
from datetime import datetime
from .extensions import db


class Task(db.Model):
    """Represents a single task in the task manager."""
    __tablename__ = "tasks"

    id = db.Column(db.Integer, primary_key=True)
    title = db.Column(db.String(120), nullable=False)
    description = db.Column(db.Text, nullable=True)
    completed = db.Column(db.Boolean, default=False, nullable=False)
    created_at = db.Column(db.DateTime, default=datetime.utcnow, nullable=False)
    updated_at = db.Column(
        db.DateTime,
        default=datetime.utcnow,
        onupdate=datetime.utcnow,
        nullable=False,
    )

    def to_dict(self):
        """Serialize the model to a JSON-friendly dict."""
        return {
            "id": self.id,
            "title": self.title,
            "description": self.description,
            "completed": self.completed,
            "created_at": self.created_at.isoformat(),
            "updated_at": self.updated_at.isoformat(),
        }

    def __repr__(self):
        return f"<Task {self.id}: {self.title}>"
```

---

### `app/schemas.py`

```python
"""
Marshmallow schemas for input validation.
These protect the API from malformed or malicious payloads.
"""
from marshmallow import Schema, fields, validate


class TaskCreateSchema(Schema):
    """Schema for creating a new task - title is required."""
    title = fields.String(
        required=True,
        validate=validate.Length(min=1, max=120, error="Title must be 1-120 chars."),
    )
    description = fields.String(
        load_default=None,
        validate=validate.Length(max=2000),
        allow_none=True,
    )
    completed = fields.Boolean(load_default=False)


class TaskUpdateSchema(Schema):
    """Schema for updating a task - all fields optional (PATCH-style)."""
    title = fields.String(
        validate=validate.Length(min=1, max=120, error="Title must be 1-120 chars.")
    )
    description = fields.String(
        validate=validate.Length(max=2000),
        allow_none=True,
    )
    completed = fields.Boolean()
```

---

### `app/errors.py`

```python
"""
Global JSON error handlers.
Ensures all errors return consistent JSON responses instead of HTML.
"""
from flask import jsonify
from marshmallow import ValidationError
from werkzeug.exceptions import HTTPException


def register_error_handlers(app):
    """Attach error handlers to the Flask app."""

    @app.errorhandler(ValidationError)
    def handle_validation_error(err):
        # Marshmallow raises this when payload fails validation
        return jsonify({"error": "Validation failed", "messages": err.messages}), 400

    @app.errorhandler(404)
    def handle_not_found(err):
        return jsonify({"error": "Res
Judge notes: The output is cut off mid-file (errors.py is truncated), meaning the code is not complete or runnable as delivered, which is a critical failure for a boilerplate generator task.
Claude Haiku 4.5 7/10
# Flask Task Manager API - Complete Boilerplate

I'll generate a production-ready Flask REST API for task management with a modular structure. Here's the complete project:

## Project Structure
```
task-manager-api/
├── app.py
├── config.py
├── requirements.txt
├── .env.example
├── .gitignore
├── models/
│   ├── __init__.py
│   └── task.py
├── routes/
│   ├── __init__.py
│   └── tasks.py
├── schemas/
│   ├── __init__.py
│   └── task_schema.py
├── utils/
│   ├── __init__.py
│   ├── validators.py
│   └── responses.py
└── instance/
    └── (auto-created)
```

---

## File: `requirements.txt`

```txt
Flask==3.0.0
Flask-SQLAlchemy==3.1.1
python-dotenv==1.0.0
Werkzeug==3.0.1
```

---

## File: `.env.example`

```env
# Flask Configuration
FLASK_ENV=development
FLASK_APP=app.py
SECRET_KEY=your-secret-key-here-change-in-production

# Database
DATABASE_URL=sqlite:///instance/tasks.db

# Server
DEBUG=True
PORT=5000
HOST=0.0.0.0
```

---

## File: `.gitignore`

```
# Environment variables
.env
.env.local

# Python
__pycache__/
*.py[cod]
*$py.class
*.so
.Python
env/
venv/
ENV/
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
wheels/
*.egg-info/
.installed.cfg
*.egg

# IDE
.vscode/
.idea/
*.swp
*.swo
*~

# Database
instance/
*.db
*.sqlite
*.sqlite3

# OS
.DS_Store
Thumbs.db
```

---

## File: `config.py`

```python
"""
Flask application configuration module.
Handles environment-based settings and database configuration.
"""

import os
from dotenv import load_dotenv
from datetime import timedelta

# Load environment variables from .env file
load_dotenv()


class Config:
    """Base configuration with common settings."""
    
    # Flask settings
    SECRET_KEY = os.getenv('SECRET_KEY', 'dev-secret-key-change-in-production')
    FLASK_ENV = os.getenv('FLASK_ENV', 'development')
    
    # SQLAlchemy settings
    SQLALCHEMY_DATABASE_URI = os.getenv(
        'DATABASE_URL',
        'sqlite:///instance/tasks.db'
    )
    SQLALCHEMY_TRACK_MODIFICATIONS = False
    
    # API settings
    JSON_SORT_KEYS = False
    JSONIFY_PRETTYPRINT_REGULAR = True
    
    # Pagination
    ITEMS_PER_PAGE = 20
    
    # Request timeout
    PROPAGATE_EXCEPTIONS = True


class DevelopmentConfig(Config):
    """Development configuration with debug mode enabled."""
    
    DEBUG = True
    TESTING = False
    SQLALCHEMY_ECHO = True


class TestingConfig(Config):
    """Testing configuration with SQLite in-memory database."""
    
    DEBUG = True
    TESTING = True
    SQLALCHEMY_DATABASE_URI = 'sqlite:///:memory:'


class ProductionConfig(Config):
    """Production configuration with strict settings."""
    
    DEBUG = False
    TESTING = False
    SQLALCHEMY_ECHO = False


# Configuration dictionary
config = {
    'development': DevelopmentConfig,
    'testing': TestingConfig,
    'production': ProductionConfig,
    'default': DevelopmentConfig,
}


def get_config():
    """Get appropriate config based on FLASK_ENV."""
    env = os.getenv('FLASK_ENV', 'development')
    return config.get(env, config['default'])
```

---

## File: `models/__init__.py`

```python
"""
Models package - SQLAlchemy ORM models for database entities.
"""

from flask_sqlalchemy import SQLAlchemy

# Initialize SQLAlchemy without app binding
db = SQLAlchemy()

# Import models to register them
from models.task import Task

__all__ = ['db', 'Task']
```

---

## File: `models/task.py`

```python
"""
Task model - ORM definition for task entities.
Defines the database schema and methods for task management.
"""

from datetime import datetime
from models import db


class Task(db.Model):
    """
    Task model representing a task entity in the database.
    
    Attributes:
        id (int): Primary key, auto-incremented.
        title (str): Task title, required, max 200 characters.
        description (str): Detailed task description, optional.
        completed (bool): Task completion status, defaults to False.
        created_at (datetime): Timestamp of task creation.
        updated_at (datetime): Timestamp of last update.
    """
    
    __tablename__ = 'tasks'
    
    # Primary Key
    id = db.Column(db.Integer, primary_key=True, autoincrement=True)
    
    # Task Data
    title = db.Column(db.String(200), nullable=False, index=True)
    description = db.Column(db.Text, nullable=True)
    completed = db.Column(db.Boolean, default=False, nullable=False)
    
    # Timestamps
    created_at = db.Column(
        db.DateTime,
        nullable=False,
        default=datetime.utcnow,
        index=True
    )
    updated_at = db.Column(
        db.DateTime,
        nullable=False,
        default=datetime.utcnow,
        onupdate=datetime.utcnow
    )
    
    def __repr__(self):
        """String representation of Task object."""
        return f'<Task {self.id}: {self.title}>'
    
    def to_dict(self):
        """
        Convert Task object to dictionary for JSON serialization.
        
        Returns:
            dict: Task data with all fields.
        """
        return {
            'id': self.id,
            'title': self.title,
            'description': self.description,
            'completed': self.completed,
            'created_at': self.created_at.isoformat(),
            'updated_at': self.updated_at.isoformat(),
        }
    
    @staticmethod
    def from_dict(data):
        """
        Create Task object from dictionary.
        
        Args:
            data (dict): Dictionary containing task fields.
            
        Returns:
            Task: New Task instance.
        """
        return Task(
            title=data.get('title'),
            description=data.get('description', ''),
            completed=data.get('completed', False),
        )
```

---

## File: `schemas/__init__.py`

```python
"""
Schemas package - Request/response validation and serialization.
"""
```

---

## File: `schemas/task_schema.py`

```python
"""
Task schema - Validation schemas for task request/response data.
Handles input validation and serialization of task objects.
"""


class TaskSchema:
    """Schema for validating task input data."""
    
    @staticmethod
    def validate_create(data):
        """
        Validate data for task creation.
        
        Args:
            data (dict): Request data to validate.
            
        Returns:
            tuple: (is_valid, errors_dict)
            
        Raises:
            ValueError: If required fields are missing or invalid.
        """
        errors = {}
        
        # Validate title
        if 'title' not in data or not data['title']:
            errors['title'] = 'Title is required and cannot be empty.'
        elif not isinstance(data['title'], str):
            errors['title'] = 'Title must be a string.'
        elif len(data['title']) > 200:
            errors['title'] = 'Title must not exceed 200 characters.'
Judge notes: The output is cut off mid-file (schemas/task_schema.py is incomplete), meaning the boilerplate is not fully runnable as promised, and critical files like `app.py`, `routes/tasks.py`, `utils/validators.py`, and the "How to Run" section are entirely missing.
GPT-5.4 8/10
## Project Structure

```text
task_manager_api/
├── app.py
├── requirements.txt
├── .env
├── config.py
└── app/
    ├── __init__.py
    ├── extensions.py
    ├── models/
    │   ├── __init__.py
    │   └── task.py
    ├── routes/
    │   ├── __init__.py
    │   └── tasks.py
    └── utils/
        ├── __init__.py
        └── errors.py
```

---

## `requirements.txt`

```txt
Flask==3.0.3
Flask-SQLAlchemy==3.1.1
python-dotenv==1.0.1
```

---

## `.env`

```env
# Flask environment settings
FLASK_ENV=development
FLASK_DEBUG=True

# SQLite database path
DATABASE_URL=sqlite:///tasks.db
```

---

## `config.py`

```python
import os
from dotenv import load_dotenv

# Load environment variables from .env file
load_dotenv()


class Config:
    """Base configuration class."""
    SECRET_KEY = os.getenv("SECRET_KEY", "dev-secret-key")
    SQLALCHEMY_DATABASE_URI = os.getenv("DATABASE_URL", "sqlite:///tasks.db")
    SQLALCHEMY_TRACK_MODIFICATIONS = False
    JSON_SORT_KEYS = False
```

---

## `app.py`

```python
from app import create_app

# Create the Flask application using the factory pattern
app = create_app()

if __name__ == "__main__":
    app.run()
```

---

## `app/__init__.py`

```python
from flask import Flask, jsonify
from config import Config
from app.extensions import db
from app.routes.tasks import tasks_bp
from app.utils.errors import register_error_handlers


def create_app(config_class=Config):
    """Application factory function."""
    app = Flask(__name__)
    app.config.from_object(config_class)

    # Initialize extensions
    db.init_app(app)

    # Register blueprints
    app.register_blueprint(tasks_bp, url_prefix="/api/tasks")

    # Register global error handlers
    register_error_handlers(app)

    # Create database tables automatically on startup
    with app.app_context():
        db.create_all()

    @app.route("/")
    def health_check():
        return jsonify({
            "message": "Task Manager API is running",
            "status": "success"
        }), 200

    return app
```

---

## `app/extensions.py`

```python
from flask_sqlalchemy import SQLAlchemy

# Initialize extensions here so they can be imported elsewhere
db = SQLAlchemy()
```

---

## `app/models/__init__.py`

```python
from app.models.task import Task

__all__ = ["Task"]
```

---

## `app/models/task.py`

```python
from app.extensions import db


class Task(db.Model):
    """Task model representing a task in the database."""
    __tablename__ = "tasks"

    id = db.Column(db.Integer, primary_key=True)
    title = db.Column(db.String(255), nullable=False)
    description = db.Column(db.Text, nullable=True)
    completed = db.Column(db.Boolean, default=False, nullable=False)

    def to_dict(self):
        """Serialize the model to a Python dictionary."""
        return {
            "id": self.id,
            "title": self.title,
            "description": self.description,
            "completed": self.completed,
        }
```

---

## `app/routes/__init__.py`

```python
# This file can remain empty or be used for route package exports.
```

---

## `app/routes/tasks.py`

```python
from flask import Blueprint, jsonify, request
from app.extensions import db
from app.models.task import Task

tasks_bp = Blueprint("tasks", __name__)


def validate_task_input(data, partial=False):
    """
    Validate incoming task payload.
    If partial=True, used for updates where all fields are optional.
    """
    errors = {}

    if not data:
        errors["body"] = "Request body must be valid JSON."

    if not partial or "title" in data:
        title = data.get("title")
        if title is None or not isinstance(title, str) or not title.strip():
            errors["title"] = "Title is required and must be a non-empty string."

    if "description" in data and data.get("description") is not None:
        if not isinstance(data.get("description"), str):
            errors["description"] = "Description must be a string."

    if "completed" in data and not isinstance(data.get("completed"), bool):
        errors["completed"] = "Completed must be a boolean."

    return errors


@tasks_bp.route("/", methods=["POST"])
def create_task():
    """Create a new task."""
    data = request.get_json(silent=True)
    errors = validate_task_input(data)

    if errors:
        return jsonify({
            "status": "error",
            "message": "Validation failed",
            "errors": errors
        }), 400

    task = Task(
        title=data["title"].strip(),
        description=data.get("description", ""),
        completed=data.get("completed", False)
    )

    db.session.add(task)
    db.session.commit()

    return jsonify({
        "status": "success",
        "message": "Task created successfully",
        "data": task.to_dict()
    }), 201


@tasks_bp.route("/", methods=["GET"])
def get_tasks():
    """Get all tasks."""
    tasks = Task.query.all()
    return jsonify({
        "status": "success",
        "data": [task.to_dict() for task in tasks]
    }), 200


@tasks_bp.route("/<int:task_id>", methods=["GET"])
def get_task(task_id):
    """Get a single task by ID."""
    task = Task.query.get(task_id)
    if not task:
        return jsonify({
            "status": "error",
            "message": f"Task with id {task_id} not found"
        }), 404

    return jsonify({
        "status": "success",
        "data": task.to_dict()
    }), 200


@tasks_bp.route("/<int:task_id>", methods=["PUT"])
def update_task(task_id):
    """Update an existing task."""
    task = Task.query.get(task_id)
    if not task:
        return jsonify({
            "status": "error",
            "message": f"Task with id {task_id} not found"
        }), 404

    data = request.get_json(silent=True)
    errors = validate_task_input(data, partial=True)

    if errors:
        return jsonify({
            "status": "error",
            "message": "Validation failed",
            "errors": errors
        }), 400

    # Update only provided fields
    if "title" in data:
        task.title = data["title"].strip()
    if "description" in data:
        task.description = data["description"]
    if "completed" in data:
        task.completed = data["completed"]

    db.session.commit()

    return jsonify({
        "status": "success",
        "message": "Task updated successfully",
        "data": task.to_dict()
    }), 200


@tasks_bp.route("/<int:task_id>", methods=["DELETE"])
def delete_task(task_id):
    """Delete a task by ID."""
    task = Task.query.get(task_id)
    if not task:
        return jsonify({
            "status": "error",
            "message": f"Task with id {task_id} not found"
        }), 404

    db.session.delete(task)
    db.session.commit()

    return jsonify({
        "status": "success",
        "message": "Task deleted successfully"
    }), 200
```

---

## `app/utils/__init__.py`

```python
# Utility package initializer
```

---

## `app/utils/errors.py`

```python
from flask import jsonify
from werkzeug.exceptions import HTTPException


def register_error_handlers(app):
    """Register application-wide JSON error handlers."""

    @app.errorhandler(404)
    def not_found(error):
        return jsonify({
            "status": "error",
            "message": "Resource not found"
        }), 404

    @app.errorhandler(405)
    def method_not_allowed(error):
        return jsonify({
            "status": "error",
            "message": "Method not allowed"
        }), 405

    @app.errorhandler(400)
    def bad_request(error):
        return jsonify({
            "status": "error",
            "message": "Bad request"
        }), 400

    @app.errorhandler(HTTPException)
    def handle_http_exception(error):
        return jsonify({
            "status": "error",
            "message": error.description
        }), error.code

    @app.errorhandler(Exception)
    def handle_unexpected_error(error):
        return jsonify({
            "status": "error",
            "message": "An unexpected error occurred"
        }), 500
```

---

## How to Run

### 1. Create the project files
Create the folder structure above and save each file in its matching path.

### 2. Install dependencies

```bash
pip install -r requirements.txt
```

### 3. Run the Flask app

```bash
python app.py
```

### 4. API Base URL

```text
http://127.0.0.1:5000/api/tasks
```

### Example Endpoints

- `POST /api/tasks/` — create a task
- `GET /api/tasks/` — list all tasks
- `GET /api/tasks/<id>` — get one task
- `PUT /api/tasks/<id>` — update
Judge notes: Nearly production-ready with clean modular structure, but uses deprecated `Task.query.get()` (removed in SQLAlchemy 2.x) instead of `db.session.get(Task, task_id)`, and the "How to Run" section is cut off mid-list missing the DELETE endpoint example.
Gemini 2.5 Pro 2/10
Of course. As a Flask expert, I will generate a complete, production-ready boilerplate for a Task Manager REST API. The code follows modern best practices, including the application factory pattern, blueprints for modular routing, SQLAlchemy for database interaction, and environment-based configuration.

Here is the complete project structure and code.

### Project Structure

```
task_manager_api/
├── app/
│   ├── __init__.py         # Contains the application factory
│   ├── models.py           # Defines the SQLAlchemy DB models
│   └── routes/
│       ├── __init__.py     # Makes 'routes' a Python package
│       └── task_routes.py  # Blueprint with all task-related API endpoints
├── instance/
│   └── (tasks.db will be created here automatically)
├── .env.example            # Example environment variables
├── .flaskenv               # Instructs the 'flask' command-line tool
├── config.py               # Application configuration settings
├── requirements.txt        # Project dependencies
└── run.py                  # Main entry point for running the application
```

---

### File Contents

#### 1. `requirements.txt`
This file lists all the Python packages required for the
Judge notes: The output is truncated mid-sentence and delivers almost none of the actual code files requested, making it nearly unusable despite the promising introduction and project structure outline.
Grok 4.1 Fast Reasoning 7/10
```python
# app.py
"""
Flask app factory for the Task Manager API.
Handles app creation, extension initialization, blueprint registration, and error handling.
"""
from flask import Flask, jsonify
from dotenv import load_dotenv
from config import DevelopmentConfig
from extensions import db
from tasks import tasks_bp

def create_app(config_class=DevelopmentConfig):
    # Load environment variables from .env file
    load_dotenv()

    # Create Flask app and load config
    app = Flask(__name__)
    app.config.from_object(config_class)

    # Initialize extensions
    db.init_app(app)

    # Create database tables only in debug/development mode
    if app.config.get('DEBUG', False):
        with app.app_context():
            db.create_all()

    # Register blueprints
    app.register_blueprint(tasks_bp, url_prefix='/api')

    # Global error handlers for JSON responses
    @app.errorhandler(404)
    def not_found(e):
        return jsonify({'error': 'Resource not found'}), 404

    @app.errorhandler(400)
    def bad_request(e):
        return jsonify({'error': 'Bad request parameters'}), 400

    @app.errorhandler(500)
    def internal_error(e):
        db.session.rollback()
        return jsonify({'error': 'Internal server error'}), 500

    return app

if __name__ == '__main__':
    app = create_app()
    app.run(debug=True)
```

```python
# config.py
"""
Configuration classes for different environments.
Supports environment variables via python-dotenv.
"""
import os


class Config:
    """Base configuration."""
    SECRET_KEY = os.environ.get('SECRET_KEY') or 'dev-task-manager-key-change-in-prod'
    SQLALCHEMY_DATABASE_URI = os.environ.get('DATABASE_URL') or 'sqlite:///app.db'
    SQLALCHEMY_TRACK_MODIFICATIONS = False


class DevelopmentConfig(Config):
    """Development configuration."""
    DEBUG = True


class ProductionConfig(Config):
    """Production configuration."""
    DEBUG = False
```

```python
# extensions.py
"""
Flask extensions initialization.
"""
from flask_sqlalchemy import SQLAlchemy

db = SQLAlchemy()
```

```python
# models.py
"""
SQLAlchemy models for the Task Manager.
Defines the Task model with to_dict() for JSON serialization.
"""
from extensions import db


class Task(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    title = db.Column(db.String(100), index=True, nullable=False)
    description = db.Column(db.Text, nullable=True)
    completed = db.Column(db.Boolean, default=False)

    def to_dict(self):
        """Convert model to dictionary for JSON response."""
        return {
            'id': self.id,
            'title': self.title,
            'description': self.description,
            'completed': self.completed
        }
```

```python
# tasks.py
"""
Blueprint for task-related routes.
Implements CRUD operations with basic input validation and error handling.
"""
from flask import Blueprint, request, jsonify
from extensions import db
from models import Task

tasks_bp = Blueprint('tasks', __name__)


@tasks_bp.route('/tasks', methods=['GET'])
def get_tasks():
    """Retrieve all tasks."""
    tasks = Task.query.all()
    return jsonify({'tasks': [task.to_dict() for task in tasks]})


@tasks_bp.route('/tasks/<int:task_id>', methods=['GET'])
def get_task(task_id):
    """Retrieve a single task by ID."""
    task = Task.query.get_or_404(task_id)
    return jsonify(task.to_dict())


@tasks_bp.route('/tasks', methods=['POST'])
def create_task():
    """Create a new task with basic validation."""
    data = request.get_json() or {}

    # Basic input validation
    if not data.get('title'):
        return jsonify({'error': 'Title is required'}), 400
    if not isinstance(data.get('title'), str) or not 1 <= len(data['title']) <= 100:
        return jsonify({'error': 'Title must be a string between 1 and 100 characters'}), 400
    if data.get('description') is not None and not isinstance(data['description'], str):
        return jsonify({'error': 'Description must be a string or null'}), 400
    if data.get('completed') is not None and not isinstance(data['completed'], bool):
        return jsonify({'error': 'Completed must be a boolean'}), 400

    task = Task(
        title=data['title'],
        description=data.get('description'),
        completed=data.get('completed', False)
    )
    db.session.add(task)
    db.session.commit()
    return jsonify(task.to_dict()), 201


@tasks_bp.route('/tasks/<int:task_id>', methods=['PUT'])
def update_task(task_id):
    """Update an existing task with basic validation."""
    task = Task.query.get_or_404(task_id)
    data = request.get_json() or {}

    # Basic input validation for provided fields
    if data.get('title') is not None:
        if not isinstance(data['title'], str) or not 1 <= len(data['title']) <= 100:
            return jsonify({'error': 'Title must be a string between 1 and 100 characters'}), 400
        task.title = data['title']
    if data.get('description') is not None:
        if data['description'] is not None and not isinstance(data['description'], str):
            return jsonify({'error': 'Description must be a string or null'}), 400
        task.description = data['description']
    if data.get('completed') is not None:
        if not isinstance(data['completed'], bool):
            return jsonify({'error': 'Completed must be a boolean'}), 400
        task.completed = data['completed']

    db.session.commit()
    return jsonify(task.to_dict())


@tasks_bp.route('/tasks/<int:task_id>', methods=['DELETE'])
def delete_task(task_id):
    """Delete a task by ID."""
    task = Task.query.get_or_404(task_id)
    db.session.delete(task)
    db.session.commit()
    return '', 204
```

```txt
# requirements.txt
Flask==3.0.3
Flask-SQLAlchemy==3.1.1
python-dotenv==1.0.1
```

```env
# .env.example
# Copy this to .env and customize as needed.
FLASK_ENV=development
SECRET_KEY=your-secret-key-here
DATABASE_URL=sqlite:///app.db
```

## How to Run

1. Create a project directory and save all files above into it.
2. Copy `.env.example` to `.env` (optional, defaults work).
3. Install dependencies: `pip install -r requirements.txt`
4. Launch the app: `python app.py`
5. The API will be available at `http://localhost:5000/api/tasks`
   - Test with tools like curl or Postman (e.g., `curl http://localhost:5000/api/tasks`)
Judge notes: Functional and well-structured, but `db.create_all()` is gated to DEBUG mode only (breaks production cold starts), `get_or_404` is deprecated in newer SQLAlchemy/Flask-SQLAlchemy, and there's no `FLASK_APP` environment variable or project-level directory structure (e.g., no `tasks/` package folder shown), making "modular" a partial claim.

What makes these work

  1. 01
    Specify extensions by name

    Saying 'add authentication' gets you a random choice of flask-login, flask-jwt-extended, or hand-rolled token logic. Saying 'use flask-jwt-extended with refresh tokens' gets you exactly what you need. Name every library you want in the prompt and the model will wire them together correctly instead of guessing.

  2. 02
    Request the folder structure explicitly

    Ask the model to output the folder tree first, then each file. This forces it to commit to a consistent layout before writing code, which dramatically reduces cases where imports reference paths that do not match the actual file locations it generates. A one-line 'show the project tree before the code' instruction pays off every time.

  3. 03
    Pin your Python and library versions

    Flask 2.x and Flask 3.x have meaningful differences, and SQLAlchemy 1.4 versus 2.0 syntax diverges significantly. Include 'Python 3.11, Flask 3.0, SQLAlchemy 2.0' in your prompt and the model will use the current API instead of defaulting to older patterns it saw more of in training data.

  4. 04
    Ask for a requirements.txt in the same output

    Generated code that imports a library you do not have installed wastes time. Ending your prompt with 'include a requirements.txt with pinned versions' gives you a runnable environment instantly. Verify the pins against PyPI before committing, since models sometimes hallucinate version numbers for minor releases.

More example scenarios

#01 · SaaS product REST API with JWT auth
Input
Generate a Flask REST API boilerplate for a SaaS product. Include an app factory in __init__.py, a config.py with Development and Production classes, a users blueprint with register and login endpoints, JWT authentication using flask-jwt-extended, SQLAlchemy with a User model, and a global error handler returning JSON errors. Use Python 3.11.
Expected output
A complete project tree with app/__init__.py (create_app factory), app/config.py (two config classes), app/models/user.py (User with hashed password), app/blueprints/auth/routes.py (POST /register and POST /login returning access tokens), extensions.py initializing db and jwt, and a requirements.txt pinning all dependencies.
#02 · Data science team internal API
Input
Generate a minimal Flask API for an internal data science tool. Two endpoints: POST /predict that accepts a JSON body with a 'features' list and returns a 'prediction' value, and GET /health. Include input validation with marshmallow, structured JSON logging, and a stub model loader in a separate module. No database needed.
Expected output
app.py with Flask app, a schemas.py defining PredictRequestSchema with marshmallow, a model_loader.py stub that loads a pickle file path from an env variable, route handlers with validation errors returned as 400 JSON, and Python logging configured to emit JSON-formatted lines to stdout.
#03 · E-commerce microservice for order management
Input
Scaffold a Flask microservice for order management. Include blueprints for orders and products, SQLAlchemy models for Order and Product with a many-to-many relationship, pagination on GET /orders, an API key middleware that checks an X-API-Key header against an env variable, and Flask-Migrate for database migrations.
Expected output
Project with blueprints/orders/routes.py and blueprints/products/routes.py, models defining the association table, a before_request hook enforcing API key auth on all routes, paginated query using SQLAlchemy paginate(), a migrations/ folder initialized via Flask-Migrate, and a README with setup commands.
#04 · Webhook receiver for a DevOps pipeline
Input
Generate a Flask app that receives GitHub webhook POST requests. Validate the X-Hub-Signature-256 header against a secret from environment variables. Parse the JSON payload, log the event type and repository name, and push the event to a Redis list using redis-py. Return 200 on success and 403 on invalid signature.
Expected output
Single-file Flask app with a /webhook POST route, HMAC SHA-256 signature validation logic, redis.Redis client initialized from REDIS_URL env var, lpush call to a configurable list name, correct 403 response on signature mismatch, and inline comments explaining each validation step.
#05 · File upload API for a document processing app
Input
Create a Flask API that accepts PDF file uploads via POST /upload, validates file type and size under 10MB, saves the file to a local uploads/ directory with a UUID filename, stores metadata in a SQLite database with SQLAlchemy, and returns a JSON response with the file ID and original filename.
Expected output
Route using request.files, file extension and MIME type check, MAX_CONTENT_LENGTH config set to 10MB, uuid4-based filename generation, SQLAlchemy Upload model with id, original_filename, stored_filename, and created_at columns, and a 413 error handler for oversized files.

Common mistakes to avoid

  • Vague prompts produce generic output

    Prompting 'generate a Flask app' returns a hello-world single file with no structure, which is useless as a starting point. The model needs your endpoint list, chosen extensions, and project layout style to produce anything worth keeping. Treat the prompt like a spec document, not a search query.

  • Not testing database migrations before use

    AI-generated SQLAlchemy models frequently have column type mismatches or missing relationship backrefs that only surface when you run flask db migrate. Always run the migration commands and inspect the generated migration file before trusting the schema. A wrong column type in a migration is painful to fix after data exists.

  • Trusting generated secret handling

    Models commonly hardcode SECRET_KEY or JWT_SECRET_KEY as string literals in config.py or even directly in the app file. This is a critical security mistake if committed to version control. Always replace any hardcoded secret with an os.environ.get() call before the code leaves your machine.

  • Ignoring error handler completeness

    Generated error handlers often only cover 404 and 500. A production Flask API needs handlers for 400, 401, 403, 422, and 429 at minimum to return consistent JSON error shapes. Check the generated error handling section against your actual API contract and add the missing cases manually.

  • Skipping the CORS configuration

    AI-generated Flask apps rarely include CORS headers unless you ask explicitly. If a frontend will call your API from a different origin, add 'include flask-cors with CORS configured for the allowed origins' to your prompt. Debugging CORS issues after the fact when you thought the backend was done is a common time sink.

Related queries

Frequently asked questions

Can AI generate a Flask app with a database model?

Yes. Specify SQLAlchemy or another ORM in your prompt along with the model fields and relationships you need. Models like GPT-4 and Claude will generate the model class, the database initialization in your app factory, and the migration setup if you ask for Flask-Migrate. Always review foreign key and relationship definitions manually before running migrations.

What is the best AI model for generating Flask code?

GPT-4o and Claude 3.5 Sonnet consistently produce the most complete and syntactically correct Flask boilerplate based on community testing as of mid-2025. Claude tends to produce cleaner separation of concerns across files. GPT-4o tends to produce more inline comments. Gemini 1.5 Pro is a solid free alternative but occasionally uses deprecated Flask patterns.

How do I make sure the AI-generated Flask code actually runs?

Create a fresh virtual environment, install the generated requirements.txt, and run flask run immediately after generating. Fix import errors and missing dependencies before modifying any logic. Most AI-generated Flask skeletons run on the first or second attempt if your prompt was specific. Vague prompts produce code that requires more debugging.

Can I use AI to add endpoints to an existing Flask app?

Yes, but paste your existing app structure and relevant model definitions into the prompt as context. Without that context, the model will generate code that conflicts with your existing naming conventions, config keys, and extension initialization. Providing the existing __init__.py and relevant models as context produces output that integrates cleanly.

Is AI-generated Flask code production-ready?

The structure and patterns are usually sound for production use, but the generated code should not be deployed without review. Check secret key handling, input validation completeness, SQL query safety if using raw queries, and rate limiting. The boilerplate saves setup time, but the security review is still your responsibility.

How do I generate a Flask app with REST API authentication using AI?

Name the authentication method explicitly in your prompt. For token-based auth write 'use flask-jwt-extended with access and refresh tokens'. For session auth write 'use flask-login with server-side sessions'. For simple API key auth describe the header name and lookup mechanism. Ambiguous auth requests produce inconsistent implementations that mix patterns from different approaches.

Try it with a real tool

Run this prompt in one of these tools. Affiliate links help keep Gridlyx free.