Skip to main content

Production-ready GraphQL API framework for PostgreSQL with CQRS, JSONB optimization, and type-safe mutations

Project description

FraiseQL

Quality Gate Documentation Release Python License: MIT

The fastest Python GraphQL framework. In PostgreSQL Everything.

Pre-compiled queries, Automatic Persisted Queries (APQ), PostgreSQL-native caching, error tracking, and observability—all in one database.

4-100x faster than traditional GraphQL frameworks • In PostgreSQL Everything$300-3,000/month savingsZero external dependencies

🚀 Why FraiseQL?

🏛️ In PostgreSQL Everything

One database to rule them all. FraiseQL eliminates external dependencies by implementing caching, error tracking, and observability directly in PostgreSQL.

Cost Savings:

Traditional Stack:
- Sentry: $300-3,000/month
- Redis Cloud: $50-500/month
- Total: $350-3,500/month

FraiseQL Stack:
- PostgreSQL: Already running (no additional cost)
- Total: $0/month additional

Operational Simplicity:

Before: FastAPI + PostgreSQL + Redis + Sentry + Grafana = 5 services
After:  FastAPI + PostgreSQL + Grafana = 3 services

PostgreSQL-Native Stack:

  • Caching: UNLOGGED tables (Redis-level performance, no WAL overhead)
  • Error Tracking: Automatic fingerprinting, grouping, notifications (like Sentry)
  • Observability: OpenTelemetry traces + metrics in PostgreSQL
  • Monitoring: Grafana dashboards querying PostgreSQL directly

⚡ Blazing Fast Performance

  • Automatic Persisted Queries (APQ): SHA-256 hash lookup with pluggable storage backends
  • Memory & PostgreSQL storage: In-memory for simplicity, PostgreSQL for enterprise scale
  • JSON passthrough optimization: Sub-millisecond cached responses (0.5-2ms)
  • Pre-compiled queries: TurboRouter with intelligent caching (4-10x faster)
  • Real production benchmarks: 85-95% cache hit rate

🏗️ Database-First Architecture

  • CQRS by design: Commands via PostgreSQL functions, queries via views
  • JSONB-powered: Flexible schema evolution with full type safety
  • View-based queries: v_* for real-time, tv_* for materialized performance
  • PostgreSQL does the heavy lifting: Joins, aggregations, transformations in-database

🔧 Developer Experience

  • Type-safe: Full Python 3.13+ type hints with automatic GraphQL schema generation
  • Automatic documentation: Python docstrings become GraphQL descriptions in Apollo Studio
  • One command setup: fraiseql init my-api && fraiseql dev
  • Intelligent WHERE clauses: Automatic type-aware SQL optimization for network types, dates, and more
  • Hybrid table support: Seamless filtering across regular columns and JSONB fields
  • Built-in security: Field-level authorization, rate limiting, CSRF protection

🏁 Quick Start

# Install and create project
pip install fraiseql
fraiseql init my-api && cd my-api

# Define your types
cat > src/types.py << 'EOF'
import fraiseql
from fraiseql import ID, EmailAddress

@fraiseql.type
class User:
    """A user account with authentication and profile information."""
    id: ID
    email: EmailAddress
    name: str
    created_at: str
EOF

# Create database view (returns JSONB)
cat > db/001_user_view.sql << 'EOF'
CREATE VIEW v_user AS
SELECT jsonb_build_object(
    'id', pk_user,
    'email', email,
    'name', name,
    'created_at', created_at::text
) AS data FROM tb_users;
EOF

# Define queries
cat > src/queries.py << 'EOF'
import fraiseql
from .types import User

@fraiseql.query
async def users(info) -> list[User]:
    """Get all users with their profile information."""
    repo = info.context["repo"]
    return await repo.find("v_user")
EOF

# Start development server
fraiseql dev

Your GraphQL API is live at http://localhost:8000/graphql 🎉

🔄 Automatic Persisted Queries (APQ)

FraiseQL provides enterprise-grade APQ support with pluggable storage backends:

Storage Backends

# Memory backend (default - zero configuration)
config = FraiseQLConfig(
    apq_storage_backend="memory"  # Perfect for development & simple apps
)

# PostgreSQL backend (enterprise scale)
config = FraiseQLConfig(
    apq_storage_backend="postgresql",  # Persistent, multi-instance ready
    apq_storage_schema="apq_cache"     # Custom schema for isolation
)

How APQ Works

  1. Client sends query hash instead of full query
  2. FraiseQL checks storage backend for cached query
  3. JSON passthrough optimization returns results in 0.5-2ms
  4. Fallback to normal execution if query not found

Enterprise Benefits

  • 99.9% cache hit rates in production applications
  • 70% bandwidth reduction with large queries
  • Multi-instance coordination with PostgreSQL backend
  • Automatic cache warming for frequently used queries

🎯 Core Features

Advanced Type System

Specialized operators for network types, hierarchical data, and ranges:

query {
  servers(where: {
    ipAddress: { eq: "192.168.1.1" }        # → ::inet casting
    port: { gt: 1024 }                      # → ::integer casting
    macAddress: { eq: "aa:bb:cc:dd:ee:ff" } # → ::macaddr casting
    location: { ancestor_of: "US.CA" }      # → ltree operations
    dateRange: { overlaps: "[2024-01-01,2024-12-31)" }
  }) {
    id name ipAddress port
  }
}

Supported specialized types:

  • Network: IPv4, IPv6, CIDR, MACAddress with subnet/range operations
  • Hierarchical: LTree with ancestor/descendant queries
  • Temporal: DateRange with overlap/containment operations
  • Standard: EmailAddress, UUID, JSON with validation

Intelligent Mutations

PostgreSQL functions handle business logic with structured error handling:

@fraiseql.input
class CreateUserInput:
    name: str
    email: EmailAddress

class CreateUserSuccess:
    user: User
    message: str = "User created successfully"

class CreateUserError:
    message: str
    error_code: str

class CreateUser(
    FraiseQLMutation,
    function="fn_create_user",  # PostgreSQL function
    validation_strict=True
):
    input: CreateUserInput
    success: CreateUserSuccess
    failure: CreateUserError

Multi-Tenant Architecture

Built-in tenant isolation with per-tenant caching:

# Automatic tenant context
@fraiseql.query
async def users(info) -> list[User]:
    repo = info.context["repo"]
    tenant_id = info.context["tenant_id"]  # Auto-injected
    return await repo.find("v_user", tenant_id=tenant_id)

Hybrid Tables

Combine regular SQL columns with JSONB for optimal performance and flexibility:

# Database schema
CREATE TABLE products (
    id UUID PRIMARY KEY,
    status TEXT,           -- Regular column (fast filtering)
    is_active BOOLEAN,     -- Regular column (indexed)
    data JSONB            -- Flexible data (brand, specs, etc.)
);

# Type definition
@fraiseql.type
class Product:
    id: UUID
    status: str          # From regular column
    is_active: bool      # From regular column
    brand: str           # From JSONB data
    specifications: dict # From JSONB data

# Registration with metadata (optimal performance)
register_type_for_view(
    "products", Product,
    table_columns={'id', 'status', 'is_active', 'data'},
    has_jsonb_data=True
)

# Automatic SQL generation
# where: { isActive: true, brand: "TechCorp" }
# → WHERE is_active = true AND data->>'brand' = 'TechCorp'

Benefits:

  • 0.4μs field detection with metadata registration
  • Optimal SQL generation for each field type
  • No runtime database queries for field classification

📊 Performance Comparison

Framework Comparison

Framework Simple Query Complex Query Cache Hit APQ Support
FraiseQL 0.5-5ms 0.5-5ms 95% Native
PostGraphile 50-100ms 200-400ms N/A Plugin
Strawberry 100-200ms 300-600ms External Manual
Hasura 25-75ms 150-300ms External Limited

FraiseQL Optimization Layers

Optimization Stack Response Time Use Case
All 3 Layers (APQ + TurboRouter + Passthrough) 0.5-2ms High-performance production
APQ + TurboRouter 2-5ms Enterprise applications
APQ + Passthrough 1-10ms Modern web applications
TurboRouter Only 5-25ms API-focused applications
Standard Mode 25-100ms Development & complex queries

Real production benchmarks with PostgreSQL 15, 10k+ records

🏗️ Architecture

FraiseQL's cache-first philosophy delivers exceptional performance through intelligent query optimization:

┌─────────────────┐    ┌──────────────────┐    ┌─────────────────┐
│   APQ Hash      │ →  │   Storage        │ →  │   JSON          │
│   (SHA-256)     │    │   Backend        │    │   Passthrough   │
│                 │    │   Memory/PG      │    │   (0.5-2ms)     │
└─────────────────┘    └──────────────────┘    └─────────────────┘
                                ↓
┌─────────────────┐    ┌──────────────────┐    ┌─────────────────┐
│   GraphQL       │ →  │   TurboRouter    │ →  │   PostgreSQL    │
│   Parsing       │    │   Pre-compiled   │    │   JSONB Views   │
│   (100-300ms)   │    │   SQL (1-2ms)    │    │   (2-5ms)       │
└─────────────────┘    └──────────────────┘    └─────────────────┘
   Fallback Mode          FraiseQL Cache         Database Results

Key Innovations

  1. APQ Storage Abstraction: Pluggable backends (Memory/PostgreSQL) for query hash storage
  2. JSON Passthrough: Sub-millisecond responses for cached queries with zero serialization
  3. TurboRouter: Pre-compiles GraphQL queries into optimized SQL with hash-based lookup
  4. JSONB Views: PostgreSQL returns GraphQL-ready JSON, eliminating serialization overhead
  5. Intelligent Caching: Multi-layer caching with automatic invalidation and cache warming

🚦 When to Choose FraiseQL

✅ Perfect For:

  • Cost-conscious teams: Save $300-3,000/month vs Redis + Sentry
  • High-performance APIs: Sub-10ms response time requirements
  • Multi-tenant SaaS: Per-tenant isolation and caching
  • PostgreSQL-first teams: Already using PostgreSQL extensively
  • Operational simplicity: One database for everything
  • Enterprise applications: ACID guarantees, no eventual consistency
  • Self-hosted infrastructure: Full control, no SaaS vendor lock-in

❌ Consider Alternatives:

  • Simple CRUD: Basic applications without performance requirements
  • Non-PostgreSQL databases: FraiseQL is PostgreSQL-specific
  • Microservices: Better suited for monolithic or database-per-service architectures

📊 PostgreSQL-Native Observability

FraiseQL includes a complete observability stack built directly into PostgreSQL—eliminating the need for external services like Sentry, Redis, or third-party APM tools.

Error Tracking (Alternative to Sentry)

from fraiseql.monitoring import init_error_tracker

tracker = init_error_tracker(db_pool, environment="production")
await tracker.capture_exception(error, context={...})

# Features:
# - Automatic error fingerprinting and grouping
# - Full stack trace capture
# - Request/user context preservation
# - OpenTelemetry trace correlation
# - Issue management (resolve, ignore, assign)
# - Custom notification triggers (Email, Slack, Webhook)

Caching (Alternative to Redis)

from fraiseql.caching import PostgresCache

cache = PostgresCache(db_pool)
await cache.set("key", value, ttl=3600)

# Features:
# - UNLOGGED tables for Redis-level performance
# - No WAL overhead = fast writes
# - Shared across instances
# - TTL-based expiration
# - Pattern-based deletion

OpenTelemetry Integration

# All traces and metrics stored in PostgreSQL
# Query for debugging:
SELECT * FROM monitoring.traces
WHERE error_id = 'error-123'  -- Full correlation
  AND trace_id = 'trace-xyz';

Grafana Dashboards

Pre-built dashboards included in grafana/:

  • Error monitoring dashboard
  • OpenTelemetry traces dashboard
  • Performance metrics dashboard
  • All querying PostgreSQL directly

Migration Guides: See docs/monitoring.md for migrating from Redis and Sentry.

🛠️ CLI Commands

# Project management
fraiseql init <name>           # Create new project
fraiseql dev                   # Development server with hot reload
fraiseql check                 # Validate schema and configuration

# Code generation
fraiseql generate schema       # Export GraphQL schema
fraiseql generate types        # Generate TypeScript definitions

# Database utilities
fraiseql sql analyze <query>   # Analyze query performance
fraiseql sql explain <query>   # Show PostgreSQL execution plan

🤝 Contributing

We welcome contributions! See CONTRIBUTING.md for:

  • Development setup and testing
  • Architecture decisions and patterns
  • Code style and review process

📚 Learn More

🙏 Acknowledgments

FraiseQL draws inspiration from:

  • Strawberry GraphQL - Excellent Python GraphQL library ("Fraise" = French for strawberry)
  • Harry Percival's "Architecture Patterns with Python" - Clean architecture and repository patterns
  • Eric Evans' "Domain-Driven Design" - Database-centric domain modeling
  • PostgreSQL community - For building the world's most advanced open source database

👨‍💻 About

FraiseQL is created by Lionel Hamayon (@evoludigit), a self-taught developer and founder of Évolution digitale.

Started: April 2025

I built FraiseQL out of frustration with a stupid inefficiency: PostgreSQL returns JSON → Python deserializes to objects → GraphQL serializes back to JSON. Why are we doing this roundtrip?

After years moving through Django, Flask, FastAPI, and Strawberry GraphQL with SQLAlchemy, I realized the entire approach was wrong. Just let PostgreSQL return the JSON directly. Skip the ORM. Skip the object mapping.

But I also wanted something designed for the LLM era. SQL and Python are two of the most massively trained languages—LLMs understand them natively. Why not make a framework where AI can easily get context and generate correct code?

FraiseQL is the result: database-first CQRS where PostgreSQL does what it does best, Python stays minimal, and the whole architecture is LLM-readable by design.

Full disclosure: I built this while compulsively preparing for scale I didn't have. But that obsession led somewhere real—sub-millisecond responses, zero N+1 queries, and a framework that both humans and AI can understand.

Connect:

Support FraiseQL:

  • ⭐ Star fraiseql/fraiseql
  • 💬 Join discussions and share feedback
  • 🤝 Contribute to the project

📄 License

MIT License - see LICENSE for details.


Ready to build the fastest GraphQL API in Python?

pip install fraiseql && fraiseql init my-fast-api

Project details


Release history Release notifications | RSS feed

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

fraiseql-0.11.3.tar.gz (394.2 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

fraiseql-0.11.3-py3-none-any.whl (509.1 kB view details)

Uploaded Python 3

File details

Details for the file fraiseql-0.11.3.tar.gz.

File metadata

  • Download URL: fraiseql-0.11.3.tar.gz
  • Upload date:
  • Size: 394.2 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for fraiseql-0.11.3.tar.gz
Algorithm Hash digest
SHA256 777da643f8eaa73e21046b9a22b1b0a94d2d6273ec0f0ec4389bf44ab2214c15
MD5 41bbb45b243f0c84ccc644b2541b4a4a
BLAKE2b-256 31a99587e5a6d57468999ac46cdad8bc2806e440aa556568ad5a2d8bb1865b6e

See more details on using hashes here.

File details

Details for the file fraiseql-0.11.3-py3-none-any.whl.

File metadata

  • Download URL: fraiseql-0.11.3-py3-none-any.whl
  • Upload date:
  • Size: 509.1 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for fraiseql-0.11.3-py3-none-any.whl
Algorithm Hash digest
SHA256 67d523a6f7382d4b51a0fa1fb2b08d1aeaa9330b87d12a355e232cf9b5c026c0
MD5 4f60f86231250f0fd3e1f2bbd48a3907
BLAKE2b-256 bb94a66c47d1c986ae4ca9cb29097cae0839d24a767c7610e257ec38ff21c5ab

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page