Download
Download the Metronic Integration Examples from our GitHub repository .
Please note that the sample project does not include the Metronic Tailwind CSS source files by default. To integrate the styles, you need to copy the Metronic Tailwind CSS source files from your downloaded Metronic folder.
Clone Integration Repository
git clone https://github.com/keenthemes/metronic-tailwind-html-integration.git
cd metronic-tailwind-html-integration/metronic-tailwind-flask
Copy Assets Folder
assets
folder from the
metronic-tailwind-html/dist
directory into your Flask project root. The resulting directory structure should look like this:
assets/
.
Automated Setup (Recommended)
# macOS/Linux
./setup.sh
# Windows
setup.bat
Start Development Server
# Using start scripts (recommended)
./start.sh # macOS/Linux
start.bat # Windows
# Or manually
python3 run.py
http://127.0.0.1:5000
to see your Flask app in action. You can explore both demo layouts:
# Demo 1 - Sidebar Layout
http://127.0.0.1:5000/demo1/
# Demo 2 - Header Layout
http://127.0.0.1:5000/demo2/
If you prefer to create a project from scratch, follow these manual steps.
Creating a Flask Project
Install Python
Use Integration Template (Recommended)
git clone https://github.com/keenthemes/metronic-tailwind-html-integration.git
cd metronic-tailwind-html-integration/metronic-tailwind-flask
Manual Project Setup (Alternative)
# Create project directory
mkdir metronic-flask
cd metronic-flask
# Create virtual environment
python -m venv venv
source venv/bin/activate # On Windows: venv\Scripts\activate
# Install Flask
pip install Flask
# Create basic structure
mkdir -p app/demo1 app/demo2 templates/demo1 templates/demo2 templates/partials
Create Application Factory
app/__init__.py
:
from flask import Flask, redirect, url_for
def create_app():
app = Flask(__name__, static_folder='../assets', static_url_path='/assets')
# Register blueprints
from app.demo1 import bp as demo1_bp
from app.demo2 import bp as demo2_bp
app.register_blueprint(demo1_bp, url_prefix='/demo1')
app.register_blueprint(demo2_bp, url_prefix='/demo2')
@app.route('/')
def index():
return redirect(url_for('demo1.index'))
return app
Create Application Entry Point
run.py
as your application entry point:
from app import create_app
app = create_app()
if __name__ == '__main__':
app.run(debug=True, host='127.0.0.1', port=5000)
Test Your Setup
python run.py
http://127.0.0.1:5000
to see your Flask app in action.
Integrate Metronic Core with Flask
Understanding the Flask Integration Structure
metronic-tailwind-flask/
├── app/ # Main application package
│ ├── __init__.py # Application factory
│ ├── config.py # Configuration management
│ ├── models.py # Mock data models
│ ├── demo1/ # Demo 1 blueprint (sidebar)
│ └── demo2/ # Demo 2 blueprint (header)
├── templates/ # Jinja2 templates
│ ├── demo1/ # Demo 1 pages
│ ├── demo2/ # Demo 2 pages
│ └── partials/ # Reusable components
├── assets/ # Metronic assets (CSS, JS, media)
├── tests/ # Test suite
├── setup.sh / setup.bat # Automated setup scripts
├── start.sh / start.bat # Development startup scripts
└── run.py # Application entry point
Application Factory Pattern
app/__init__.py
:
from flask import Flask, redirect, url_for
def create_app():
app = Flask(__name__, static_folder='../assets', static_url_path='/assets')
# Configuration
app.config.from_object('app.config.Config')
# Register blueprints
from app.demo1 import bp as demo1_bp
from app.demo2 import bp as demo2_bp
from app.main import bp as main_bp
app.register_blueprint(main_bp)
app.register_blueprint(demo1_bp, url_prefix='/demo1')
app.register_blueprint(demo2_bp, url_prefix='/demo2')
return app
Blueprint Organization
app/demo1/__init__.py
) for sidebar layout:
from flask import Blueprint, render_template
from app.models import get_dashboard_context
bp = Blueprint('demo1', __name__)
@bp.route('/')
def index():
context = get_dashboard_context()
return render_template('demo1/index.html', **context)
@bp.route('/dashboard')
def dashboard():
context = get_dashboard_context()
return render_template('demo1/index.html', **context)
app/demo2/__init__.py
) for header layout:
from flask import Blueprint, render_template
from app.models import get_analytics_context
bp = Blueprint('demo2', __name__)
@bp.route('/')
def index():
context = get_analytics_context()
return render_template('demo2/index.html', **context)
@bp.route('/analytics')
def analytics():
context = get_analytics_context()
return render_template('demo2/index.html', **context)
Configuration Management
app/config.py
:
import os
from pathlib import Path
class Config:
"""Base configuration class."""
# Flask settings
SECRET_KEY = os.environ.get('SECRET_KEY') or 'dev-secret-key-change-in-production'
# Application settings
APP_NAME = 'Metronic Flask Integration'
APP_VERSION = '1.0.0'
# Static files
STATIC_FOLDER = Path(__file__).parent.parent / 'assets'
STATIC_URL_PATH = '/assets'
# Template settings
TEMPLATES_AUTO_RELOAD = True
Create Base Templates
templates/demo1/base.html
:
<!DOCTYPE html>
<html lang="en">
<head>
{% include 'partials/head.html' %}
<title>
{% block title %}Metronic Flask{% endblock %}
</title>
</head>
<body>
<div class="d-flex flex-column flex-root">
<div class="page d-flex flex-row flex-column-fluid">
{% include 'demo1/partials/sidebar.html' %}
<div class="wrapper d-flex flex-column flex-row-fluid">
{% include 'demo1/partials/header.html' %}
<div class="content d-flex flex-column flex-column-fluid">
{% block content %}{% endblock %}
</div>
</div>
</div>
</div>
{% include 'partials/scripts.html' %}
</body>
</html>
Create Template Partials
templates/partials/head.html
:
<meta charset="utf-8"/>
<meta content="width=device-width, initial-scale=1" name="viewport"/>
<link href="{{ url_for('static', filename='media/logos/favicon.ico') }}" rel="shortcut icon"/>
<link href="{{ url_for('static', filename='css/style.bundle.css') }}" rel="stylesheet"/>
Mock Data Models
app/models.py
:
def get_dashboard_context():
"""Get context data for Demo 1 (sidebar layout)."""
return {
'user': User("Max Smith", "max@keenthemes.com", "/assets/media/avatars/300-1.jpg"),
'stats': {
'total_users': 15000,
'revenue': 75000,
'orders': 450,
'growth': 15.2
},
'recent_activities': get_recent_activities(),
'chart_data': get_chart_data()
}
def get_analytics_context():
"""Get context data for Demo 2 (header layout)."""
return {
'user': User("Sean Bean", "sean@keenthemes.com", "/assets/media/avatars/300-5.jpg"),
'analytics': {
'visitors': 24500,
'bounce_rate': 35.8,
'page_views': 125000,
'conversion': 8.2
},
'traffic_sources': get_traffic_sources(),
'performance_data': get_performance_data()
}
Testing Integration
# Run all tests
pytest
# Run with coverage report
pytest --cov=app
# Run specific test modules
pytest tests/test_demo1.py -v
pytest tests/test_demo2.py -v
# Run tests with detailed output
pytest tests/ -v --tb=short
Integrate Metronic & KtUI with Flask
Copy Metronic Assets
assets
folder from your Metronic HTML package's
dist
directory to your Flask project root:
cp -r /path/to/metronic-tailwind-html/dist/assets ./assets
Configure Static Files
app = Flask(__name__, static_folder='assets', static_url_path='/assets')
Create Head Partial
templates/partials/head.html
to include Metronic stylesheets:
<meta charset="utf-8"/>
<meta content="Metronic Flask Integration" name="description"/>
<meta content="flask, metronic, tailwind, dashboard" name="keywords"/>
<meta content="width=device-width, initial-scale=1" name="viewport"/>
<meta content="en_US" property="og:locale"/>
<meta content="article" property="og:type"/>
<meta content="Metronic Flask" property="og:title"/>
<meta content="Metronic by Keenthemes" property="og:site_name"/>
<link href="{{ url_for('static', filename='media/logos/favicon.ico') }}" rel="shortcut icon"/>
<!--begin::Fonts(mandatory for all pages)-->
<link href="https://fonts.googleapis.com/css?family=Inter:300,400,500,600,700" rel="stylesheet"/>
<!--end::Fonts-->
<!--begin::Vendor Stylesheets(used for this page only)-->
<link href="{{ url_for('static', filename='plugins/custom/datatables/datatables.bundle.css') }}" rel="stylesheet" type="text/css"/>
<!--end::Vendor Stylesheets-->
<!--begin::Global Stylesheets Bundle(mandatory for all pages)-->
<link href="{{ url_for('static', filename='css/style.bundle.css') }}" rel="stylesheet" type="text/css"/>
Create Scripts Partial
templates/partials/scripts.html
to include Metronic JavaScript:
<!--begin::Javascript-->
<script>
var hostUrl = "{{ url_for('static', filename='') }}";
</script>
<!--begin::Global Javascript Bundle(mandatory for all pages)-->
<script src="{{ url_for('static', filename='plugins/global/plugins.bundle.js') }}">
</script>
<script src="{{ url_for('static', filename='js/scripts.bundle.js') }}">
</script>
<!--end::Global Javascript Bundle-->
<!--begin::Vendors Javascript(used for this page only)-->
<script src="{{ url_for('static', filename='plugins/custom/datatables/datatables.bundle.js') }}">
</script>
<!--end::Vendors Javascript-->
<!--begin::Custom Javascript(optional)-->
<script src="{{ url_for('static', filename='js/custom/apps/user-management/users/list/table.js') }}">
</script>
<script src="{{ url_for('static', filename='js/custom/apps/user-management/users/list/export-users.js') }}">
</script>
<script src="{{ url_for('static', filename='js/custom/apps/user-management/users/list/add-user.js') }}">
</script>
<script src="{{ url_for('static', filename='js/widgets.bundle.js') }}">
</script>
<script src="{{ url_for('static', filename='js/custom/widgets.js') }}">
</script>
<script src="{{ url_for('static', filename='js/custom/apps/chat/chat.js') }}">
</script>
<script src="{{ url_for('static', filename='js/custom/utilities/modals/upgrade-plan.js') }}">
</script>
<script src="{{ url_for('static', filename='js/custom/utilities/modals/create-app.js') }}">
</script>
<script src="{{ url_for('static', filename='js/custom/utilities/modals/users-search.js') }}">
</script>
<!--end::Custom Javascript-->
<!--end::Javascript-->
Create Demo Templates
templates/demo1/index.html
:
{% extends "demo1/base.html" %}
{% block title %}Dashboard - Metronic Flask{% endblock %}
{% block content %}
<div class="app-toolbar py-3 py-lg-6" id="kt_app_toolbar">
<div class="app-container container-xxl d-flex flex-stack" id="kt_app_toolbar_container">
<div class="page-title d-flex flex-column justify-content-center flex-wrap me-3">
<h1 class="page-heading d-flex text-dark fw-bold fs-3 flex-column justify-content-center my-0">
Dashboard
</h1>
<ul class="breadcrumb breadcrumb-separatorless fw-semibold fs-7 my-0 pt-1">
<li class="breadcrumb-item text-muted">
<a class="text-muted text-hover-primary" href="{{ url_for('demo1.index') }}">
Home
</a>
</li>
<li class="breadcrumb-item">
<span class="bullet bg-gray-400 w-5px h-2px">
</span>
</li>
<li class="breadcrumb-item text-muted">
Dashboard
</li>
</ul>
</div>
</div>
</div>
<div class="app-content flex-column-fluid" id="kt_app_content">
<div class="app-container container-xxl" id="kt_app_content_container">
<!-- Dashboard content goes here -->
<div class="row g-5 g-xl-10 mb-5 mb-xl-10">
<div class="col-md-6 col-lg-6 col-xl-6 col-xxl-3 mb-md-5 mb-xl-10">
<div class="card card-flush bgi-no-repeat bgi-size-contain bgi-position-x-end h-md-50 mb-5 mb-xl-10">
<div class="card-header pt-5">
<div class="card-title d-flex flex-column">
<span class="fs-2hx fw-bold text-dark me-2 lh-1 ls-n2">
{{ stats.total_users }}
</span>
<span class="text-gray-400 pt-1 fw-semibold fs-6">
Total Users
</span>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
{% endblock %}
Update Routes with Context
from flask import Blueprint, render_template
from models import get_dashboard_stats, get_user_data
demo1_bp = Blueprint('demo1', __name__)
@demo1_bp.route('/')
def index():
stats = get_dashboard_stats()
user = get_user_data()
return render_template('demo1/index.html', stats=stats, user=user)
Development Workflow
# Daily development startup
./start.sh # macOS/Linux
start.bat # Windows
# Manual startup
python3 run.py
# Run with specific host/port
python3 run.py --host=0.0.0.0 --port=8000
# Demo 1 - Sidebar Layout (Dashboard)
http://127.0.0.1:5000/demo1/
# Demo 2 - Header Layout (Analytics)
http://127.0.0.1:5000/demo2/
# Main redirect (goes to Demo 1)
http://127.0.0.1:5000/
Customization & Next Steps
# Add new routes to blueprints
# Edit app/demo1/__init__.py or app/demo2/__init__.py
# Customize templates
# Modify files in templates/demo1/ or templates/demo2/
# Update mock data
# Edit app/models.py to add your data sources
# Add database integration
# Install SQLAlchemy: pip install Flask-SQLAlchemy
# Run tests to verify changes
pytest tests/ -v