Build scalable, maintainable, performant web applications one block at a time. This is the app framework that powers vedicreader.com, a modern web application for reading Vedic texts. Live Demo
Lego is a modular Python web framework designed to help developers build modern web applications with a component-based approach. It combines the power of FastHTML and MonsterUI with a comprehensive set of built-in features to create performant, maintainable web applications.
- Complete Auth Pipeline: Login, registration, password reset, email verification
- Social Authentication: Configurable Google and GitHub OAuth integration
- Resend Integration: Modern email service for auth communications
- Intelligent Logging:
quick_lgrautomatically finds the calling file, creates a log file, and returns info, error, and warning functions- Configurable file and stream logging with rotation support
- Flexible Caching:
- Both Redis and SQLite implementations built-in
- Simple decorator-based caching with TTL and auto-refresh
- Automated Backups:
- Scheduled backups with age-based retention policies
- Compression and archiving capabilities
- Cloud Storage:
- Optional cloning to cloud buckets via rclone
- Support for various cloud providers
- Modern UI Components:
- Responsive UI components with MonsterUI
- Light/dark mode and customizable themes
- Database Support:
- SQLite Database: Simple database integration with WAL mode for performance
- FastSQL Support: Can replace FastLite to load PostgreSQL or other databases normally loaded through SQLAlchemy
# Clone the repository
git clone https://github.com/karthik777/lego.git
cd lego
# Using uv (recommended)
uv venv
uv pip install -e .- Start the server
python main.py- Visit your application
Open your browser and navigate to: http://localhost:5001
lego/
βββ main.py # Main application entry point
βββ lego/
β βββ auth/ # Authentication module
β β βββ app.py # Auth routes and connections
β β βββ cfg.py # Auth configuration
β β βββ data.py # Auth data models and logic
β β βββ ui.py # Auth UI components
β βββ core/ # Core functionality
β β βββ backups.py # Backup and cloud storage
β β βββ cache.py # Caching implementations
β β βββ cfg.py # Core configuration
β β βββ logging.py # Logging utilities
β β βββ ui.py # UI components and helpers
βββ config-templates/ # Configuration templates for deployment
β βββ cloudflare.ini # Cloudflare DNS validation config
β βββ default.conf # Nginx configuration for SWAG
β βββ rclone.conf # Rclone configuration for cloud storage
β βββ tunnelconfig.yml # Cloudflare Tunnel configuration
βββ data/ # Application data
β βββ db/ # Database files
β βββ logs/ # Log files
βββ static/ # Static assets
βββ Dockerfile # Docker container definition
βββ docker-compose.yml # Docker Compose configuration
βββ pyproject.toml # Project dependencies
Lego is built on the concept of modular, composable blocks. Each block can:
- Set configuration defaults and extend its config with other configs
- Be completely standalone (own config, database, dependencies)
- Build on top of other blocks (use existing databases, config from one or more components)
- Partially depend on other blocks (use some of the blocks' config or helper methods)
- Reusability: Blocks can be reused across different applications
- Scalability: Add new features without modifying existing code
- Maintainability: Clean separation of concerns for easier debugging and testing
- Performance: Optimize each block for speed and efficiency
- Flexibility: Mix and match blocks to create custom applications
- Security: Isolate sensitive data and logic in separate blocks
- Consistency: Follow a consistent structure and coding style across blocks
- Environment Generation: Generate environment files, SQLite DB automatically from defaults
This approach allows you to create reusable components that can be mixed and matched to build different applications while maintaining clean separation of concerns.
Lego follows a modular approach where each feature is a "block" that can be connected to the main application:
-
Create a new directory for your block (e.g.,
myblock/) -
Create the following files in your block:
__init__.py- Export yourconnectfunctionapp.py- Define your routes andconnectfunctioncfg.py- Configuration for your blockui.py- Create UI componentsdata.py- Define data models and logic
-
Connect your block in
app.py:
import myblock
# connect your blocks. you can override the routes in blocks placed before the last one
myblock.connect(app)The auth block provides a complete authentication system that can be easily connected to your app:
# In auth/app.py
def connect(app, prefix="/a"):
setup_oath(app)
app.before.append(before)
Routes.base = prefix
app.get("/")(welcome)
app.get(Routes.login)(login)
app.post(Routes.login)(process_login)
# ... more routesfrom lego.core.logging import quick_lgr
# Automatically creates a logger based on the current file
info, error, warn = quick_lgr()
info("This is an info message")from lego.core.cache import cache
@cache(ttl=3600) # Cache for 1 hour
def expensive_function(param1, param2):
# Function result will be cached
return complex_calculation(param1, param2)from lego.core.backups import run_backup, clone
# Create a backup with age-based retention
run_backup(src="data/important", max_ages="2,14,60")
# Clone to cloud storage
clone(src="static", bucket="my-app-assets")from lego.core import RouteOverrides
# Override default login and logout routes
RouteOverrides.lgn = "/custom-login"
RouteOverrides.lgt = "/custom-logout"
RouteOverrides.home = "/dashboard"
# Add routes to skip authentication
RouteOverrides.skip = ["/public", "/api/health"]from lego.core.utils import scheduler
# Schedule a job to run every day at 8:00 and 20:00
scheduler.add_job(my_function, trigger='cron', hour='8,20', minute=0)
# Schedule a job to run every 24 hours
scheduler.add_job(my_function, trigger='interval', hours=24, id='daily_job')
# Schedule a job to run once after 5 minutes
scheduler.add_job(my_function, trigger='date', run_date=datetime.now() + timedelta(minutes=5))from lego.core.utils import minjs, mincss, loadX
# Minify JavaScript
minified_js = minjs(js_code)
# Minify CSS
minified_css = mincss(css_code)
# Load a file with variable substitution and minification
js_content = loadX('path/to/file.js', kw={'variable': 'value'}, minify=True)from lego.core.ui import landing, base, navbar
# Create a landing page
def my_landing_page(req):
content = Div("Welcome to my app", cls="text-center")
return landing(content, title="My App")
# Create a base layout with navbar
def my_page(req):
content = Div("Page content", cls="p-4")
return base(content, title="My App", style="glass")
# Create a custom navbar
custom_navbar = navbar(usr=user_data, title="My App", style="shining")from lego.core.utils import init_js_then_use
# Initialize a JavaScript library and use it once loaded
def my_component():
script, code = init_js_then_use(
script_src="/static/js/chart.js",
pkg_name_in_js="Chart",
js_code="new Chart(document.getElementById('chart'), config);"
)
return Div(script, code, id="chart")The themes.js file provides easy front-end caching through localStorage:
// Store a value in localStorage
storeState('key', 'value');
// Get a value from localStorage
const value = getState('key');
// Remove a value from localStorage
removeState('key');
// Set theme-related properties
setTheme('dark');
setMode('auto');
setFont('large');Lego uses Nginx for static file serving because it's faster than any Python framework:
# In config-templates/default.conf
location /static/ {
alias /config/static/;
try_files $uri $uri/ =404;
expires 1y;
add_header Cache-Control "public, max-age=31536000";
gzip location;
gzip_types text/css application/javascript image/svg+xml;
access_log off;
}During development, use the Tailwind CLI to watch for changes and generate the CSS:
npx tailwindcss@3 -i ./lego/core/css/tailwind.input.css -o ./lego/core/css/theme.css --watchThis ensures that the output theme.css file includes all the classes used in your templates.
Lego leverages several powerful front-end frameworks:
- Underscore.js: Utility library for functional programming
- Surreal.js: DOM manipulation and event handling
- HTMX: AJAX, CSS Transitions, WebSockets without JavaScript
- Lenis: Smooth scrolling library
Lego intentionally does not use ruff, PEP 8, or other standard Python formatting tools. Instead, it embraces a functional programming approach with these principles:
- No Fluff: Succinct code that focuses on functionality over form
- Mobile-Friendly: Code that's easier to read on mobile devices with fewer lines and less indentation
- Maintainability: Less code means less maintenance and fewer bugs
- Functional Programming: Pure functions that are easier to test, reason about, and reuse
- Testing Benefits: When functional code is used across the codebase, you get testing for free as functions are naturally tested through usage
- Readability Over Convention: Prioritizes human readability over strict adherence to formatting conventions
Lego comes with a complete Docker setup for easy deployment, including:
- Multi-stage build with uv for efficient dependency management
- SWAG (Secure Web Application Gateway) for SSL/TLS and reverse proxy
- Redis for caching
- Cloudflare Tunnel integration for secure remote access
# Clone the repository
git clone https://github.com/karthik777/lego.git
cd lego
# Create a .env file with your configuration
cp .env.example .env
# Edit .env with your settings
nano .env
# Start the containers
docker-compose up -dThe config-templates directory contains configuration files that are used during deployment:
- default.conf: Nginx configuration for the SWAG container, setting up SSL and proxying requests to the app
- cloudflare.ini: Configuration for Cloudflare DNS validation when obtaining SSL certificates
- rclone.conf: Configuration for cloud storage integration with services like Cloudflare R2
- tunnelconfig.yml: Configuration for Cloudflare Tunnel, enabling secure remote access without opening ports
When using the SWAG container, these files need to be copied to the appropriate locations. Remember to copy the actual key values:
# Copy the Nginx configuration
cp config-templates/default.conf /etc/swag/nginx/site-confs/
# Copy the Cloudflare DNS validation configuration
cp config-templates/cloudflare.ini /etc/swag/dns-conf/
# Copy the Cloudflare Tunnel configuration
cp config-templates/tunnelconfig.yml /etc/swag/The Docker Compose setup will automatically mount these directories and use environment variables to populate the configuration files.
Lego can be deployed on serverless infrastructure by:
- Using fsspec for Remote Storage: Modify the
get_pathfunction incore/cfg.pyto point to remote buckets:
# Example modification of get_path to use fsspec for remote storage
import fsspec
def get_path(nm, sf='', mk=False):
# Use fsspec to point to a remote bucket (S3, GCS, etc.)
remote_path = f"s3://my-bucket/{sf}/{nm}"
fs = fsspec.filesystem('s3')
if mk and not fs.exists(remote_path):
fs.touch(remote_path)
return remote_path- π Deployment to Fly.io: Native SQLite support
- π¨ Email integration: Self-hosted email server with emailwiz
- ποΈ PostgreSQL support: Additional database option
- π Admin dashboard: Built-in interface for managing application data
- π§ͺ Testing utilities: Helpers for testing blocks and components
- π Documentation generator: Automatic documentation for blocks and APIs
Lego is designed for:
- Web Developers who want a modular, component-based approach to building web applications
- Python Developers looking for a modern alternative to traditional web frameworks
- Rapid Prototypers who need to quickly build functional web applications with authentication
- Teams that want to organize code into reusable, maintainable blocks
MIT