Socket
Book a DemoInstallSign in
Socket

fraiseql

Package Overview
Dependencies
Maintainers
1
Versions
205
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

fraiseql

GraphQL for the LLM era. Simple. Powerful. Rust-fast. Production-ready GraphQL API framework for PostgreSQL with CQRS, JSONB optimization, and type-safe mutations

pipPyPI
Version
1.9.6
Maintainers
1

FraiseQL

Quality Gate Documentation Release Python License: MIT

v1.9.4 | Stable | Rust-Powered GraphQL for PostgreSQL

Python: 3.13+ | PostgreSQL: 13+

GraphQL for the LLM era. Simple. Powerful. Rust-fast.

PostgreSQL returns JSONB. Rust transforms it. Zero Python overhead.

# Complete GraphQL API in 15 lines
import fraiseql
from fraiseql.fastapi import create_fraiseql_app

@fraiseql.type(sql_source="v_user", jsonb_column="data")
class User:
    """A user in the system.

    Fields:
        id: Unique user identifier
        name: User's full name
        email: User's email address
    """
    id: int
    name: str
    email: str

@fraiseql.query
async def users(info) -> list[User]:
    """Get all users."""
    db = info.context["db"]
    return await db.find("v_user")

app = create_fraiseql_app(
    database_url="postgresql://localhost/mydb",
    types=[User],
    queries=[users]
)

Why FraiseQL?

  • ⚑ Rust Pipeline - 7-10x faster JSON transformation, zero Python overhead
  • πŸ”’ Secure by Design - Explicit field contracts prevent data leaks
  • πŸ€– AI-Native - LLMs generate correct code on first try
  • πŸ’° Save $5-48K/year - Eliminate Redis, Sentry, APM tools
  • πŸ”„ GraphQL Cascade - Automatic cache updates and side effect tracking
  • ✨ Auto-populated mutations - status, message, errors handled automatically (50-60% less boilerplate)
  • 🎯 Auto-wired query params - where, orderBy, limit, offset added automatically to list queries
  • πŸ“ Auto-documentation - Attribute docstrings become GraphQL descriptions automatically
  • πŸ” Advanced filtering - Full-text search, JSONB queries, array operations, regex
  • 🧠 Vector search - pgvector integration for semantic search, RAG, recommendations (6 distance operators)
  • πŸ“‹ GraphQL compliant - 85-90% GraphQL spec compliance with advanced fragment support

Is This For You?

βœ… Perfect if you:

  • Build high-performance APIs with PostgreSQL
  • Want 7-10x faster JSON processing
  • Need enterprise security & compliance
  • Prefer database-first architecture
  • Use LLMs for code generation

❌ Consider alternatives if:

  • You need multi-database support (PostgreSQL-only)
  • Building your first GraphQL API (use simpler frameworks)
  • Don't use JSONB columns in PostgreSQL

How It Works

Traditional GraphQL (slow):

PostgreSQL β†’ Rows β†’ ORM deserialize β†’ Python objects β†’ GraphQL serialize β†’ JSON β†’ Response
            ╰─── Unnecessary roundtrips (2 conversions) ───╯

FraiseQL (fast):

PostgreSQL β†’ JSONB β†’ Rust field selection β†’ HTTP Response
           ╰─ Zero Python overhead (1 conversion) ─╯

Why This Is Better

  • No ORM Overhead - Database returns final JSONB, Rust transforms it
  • No N+1 Queries - PostgreSQL composes everything in one query
  • Security Built-In - View defines exactly what's exposed (impossible to leak)
  • Recursion Safe - View structure prevents depth attacks naturally
  • AI-Friendly - SQL + Python are massively trained; no magic frameworks

Quick Start

pip install fraiseql
fraiseql init my-api
cd my-api
fraiseql dev

Your GraphQL API is live at http://localhost:8000/graphql πŸŽ‰

Next steps:

Real Security, Not Theatre

The Problem (ORM-based frameworks)

class User(Base):  # SQLAlchemy
    id = Column(Integer)
    email = Column(String)
    password_hash = Column(String)  # ← Sensitive!
    api_key = Column(String)        # ← Sensitive!

@strawberry.type
class UserType:
    id: int
    email: str
    # Forgot to exclude password_hash and api_key!

Result: One mistake = data leak.

The Solution (FraiseQL)

-- PostgreSQL view defines what's exposed
CREATE VIEW v_user AS
SELECT id,
  jsonb_build_object('id', id, 'email', email) as data
FROM tb_user;
-- password_hash and api_key aren't in JSONB = impossible to leak

Result: Structure defines the contract. No way to accidentally expose fields.

Chaos Engineering & Resilience Testing

FraiseQL separates testing into two workflows:

AspectStandard CI/CDChaos Engineering
Duration15-20 min45-60 min
PurposeCorrectnessResilience
TriggerEvery PRManual/Weekly
TestsUnit + Integration71 chaos scenarios
Blocks MergesYes βœ…No (informational)
EnvironmentLightweightReal PostgreSQL + Docker

Standard CI/CD: Validates that features work correctly Chaos Tests: Validates that system recovers from failures

β†’ Learn about chaos engineering strategy

Advanced Features

Specialized Type System (50+ scalar types)

from fraiseql.types import EmailAddress, PhoneNumber, IPv4, Money, LTree

@fraiseql.type(sql_source="v_users")
class User:
    email: EmailAddress      # Validated emails
    phone: PhoneNumber       # International phone numbers
    ip: IPv4                 # IP addresses with subnet operations
    balance: Money           # Currency with precision
    location: LTree          # Hierarchical paths

Trinity Identifiers

Three ID types for different purposes:

  • pk_user (int): Internal DB key, not exposed
  • id (UUID): Public API, stable, never changes
  • identifier (str): Human-readable slug, SEO-friendly

GraphQL Cascade

Automatic cache invalidation when mutations change related data:

mutation {
  createPost(input: {...}) {
    post { id title }
    cascade {
      updated { __typename }     # What changed
      invalidations { queryName } # Which queries to invalidate
    }
  }
}

Enterprise Security Features

  • KMS Integration: Vault, AWS KMS, GCP Cloud KMS
  • Security Profiles: STANDARD, REGULATED, RESTRICTED (government-grade)
  • SBOM Generation: Automated compliance (FedRAMP, NIS2, HIPAA, PCI-DSS)
  • Audit Logging: Cryptographic chain (SHA-256 + HMAC)
  • Row-Level Security: PostgreSQL RLS integration
  • Rate Limiting: Per-endpoint and per-GraphQL operation

πŸ” Security Configuration

Cost Savings: Replace 4 Services with 1 Database

ServiceCostFraiseQL ApproachSavings
Redis (caching)$50-500/moPostgreSQL UNLOGGED tables$600-6,000/yr
Sentry (error tracking)$300-3,000/moPostgreSQL error logging$3,600-36,000/yr
APM Tool$100-500/moPostgreSQL traces$1,200-6,000/yr
Total$450-4,000/moPostgreSQL only ($50/mo)$5,400-48,000/yr

πŸ“‹ Software Bill of Materials (SBOM)

  • Automated generation via fraiseql sbom generate
  • Global compliance: US EO 14028, EU NIS2/CRA, PCI-DSS 4.0, ISO 27001
  • CycloneDX 1.5 format with cryptographic signing
  • CI/CD integration for continuous compliance

πŸ”‘ Key Management Service (KMS)

  • HashiCorp Vault: Production-ready with transit engine
  • AWS KMS: Native integration with GenerateDataKey
  • GCP Cloud KMS: Envelope encryption support
  • Local Provider: Development-only with warnings

πŸ›‘οΈ Security Profiles

  • STANDARD: Default protections for general applications
  • REGULATED: PCI-DSS/HIPAA/SOC 2 compliance
  • RESTRICTED: Government, defence, critical infrastructure
    • πŸ‡ΊπŸ‡Έ FedRAMP, DoD, NIST 800-53
    • πŸ‡ͺπŸ‡Ί NIS2 Essential Entities, EU CRA
    • πŸ‡¨πŸ‡¦ CPCSC (defence contractors)
    • πŸ‡¦πŸ‡Ί Essential Eight Level 3
    • πŸ‡ΈπŸ‡¬ Singapore CII operators

πŸ“Š Observability

  • OpenTelemetry tracing with sensitive data sanitization
  • Security event logging
  • Audit trail support

πŸ”’ Advanced Security Controls

  • Rate limiting for API endpoints and GraphQL operations
  • CSRF protection for mutations and forms
  • Security headers middleware for defense in depth
  • Input validation and sanitization
  • Field-level authorization with role inheritance
  • Row-level security via PostgreSQL RLS

πŸ“‹ KMS Architecture

Code Examples

Complete CRUD API

@fraiseql.input
class CreateUserInput:
    email: str  # AI sees exact input structure
    name: str

@fraiseql.success
class UserCreated:
    user_id: str  # AI sees success response
    # Note: @success auto-injects: status, message, updated_fields, id

@fraiseql.error
class ValidationError:
    error: str    # AI sees failure cases
    code: str = "VALIDATION_ERROR"

@fraiseql.mutation(function="fn_create_user", schema="public")
class CreateUser:
    input: CreateUserInput
    success: UserCreated
    failure: ValidationError  # Note: Use 'failure' field, not '@failure' decorator

# That's it! FraiseQL automatically:
# 1. Calls public.fn_create_user(input) with input as dict
# 2. Parses JSONB result into UserCreated or ValidationError

Why AI Loves This

  • βœ… SQL + Python - Massively trained languages (no proprietary DSLs)
  • βœ… JSONB everywhere - Clear data structures, obvious contracts
  • βœ… Database functions - Complete context in one file
  • βœ… Explicit logging - AI can trace execution without debugging
  • βœ… No abstraction layers - What you see is what executes

Real Impact: Claude Code, GitHub Copilot, and ChatGPT generate correct FraiseQL code on first try.

πŸ“– Core Concepts

New to FraiseQL? Understanding these core concepts will help you make the most of the framework:

πŸ“š Concepts & Glossary - Essential terminology and mental models:

  • CQRS Pattern - Separate read models (views) from write models (functions)
  • Trinity Identifiers - Three-tier ID system (pk_*, id, identifier) for performance and UX
  • JSONB Views - PostgreSQL composes data once, eliminating N+1 queries
  • Database-First Architecture - Start with PostgreSQL, GraphQL follows
  • Explicit Sync Pattern - Table views (tv_*) for complex queries

Quick links:

✨ See How Simple It Is

Complete CRUD API in 20 Lines

from uuid import UUID
from fraiseql import type, query, mutation, input, success

@fraiseql.type(sql_source="v_note", jsonb_column="data")
class Note:
    id: int
    title: str
    content: str | None

@fraiseql.query
async def notes(info) -> list[Note]:
    return await info.context["db"].find("v_note")

@fraiseql.query
async def note(info, id: UUID) -> Note | None:
    """Get a note by ID."""
    db = info.context["db"]
    return await db.find_one("v_note", id=id)

# Step 3: Define mutations
@fraiseql.input
class CreateNoteInput:
    title: str
    content: str | None = None

@fraiseql.mutation
class CreateNote:
    input: CreateNoteInput
    success: Note

app = create_fraiseql_app(
    database_url="postgresql://localhost/mydb",
    types=[Note],
    queries=[notes],
    mutations=[CreateNote]
)

Database-First Pattern

-- PostgreSQL view (composable, no N+1)
CREATE VIEW v_user AS
SELECT id,
  jsonb_build_object(
    'id', id,
    'name', name,
    'email', email,
    'posts', (
      SELECT jsonb_agg(...)
      FROM tb_post p
      WHERE p.user_id = tb_user.id
    )
  ) as data
FROM tb_user;
# Python type mirrors the view
@fraiseql.type(sql_source="v_user", jsonb_column="data")
class User:
    id: int
    name: str
    email: str
    posts: list[Post]  # Nested relations! No N+1 queries!

# Step 3: Query it
@fraiseql.query
async def users(info) -> list[User]:
    db = info.context["db"]
    return await db.find("v_user")

No ORM. No complex resolvers. PostgreSQL composes data, Rust transforms it.

Mutations with Business Logic

CREATE OR REPLACE FUNCTION fn_publish_post(p_post_id UUID) RETURNS JSONB AS $$
DECLARE
    v_post RECORD;
BEGIN
    -- Get post with user info (Trinity pattern: JOIN on pk_user)
    SELECT p.*, u.email as user_email
    INTO v_post
    FROM tb_post p
    JOIN tb_user u ON p.fk_user = u.pk_user  -- βœ… Trinity: INTEGER FK to pk_user
    WHERE p.id = p_post_id;

    -- Validate post exists
    IF NOT FOUND THEN
        RETURN jsonb_build_object('success', false, 'error', 'Post not found');
    END IF;

    -- Validate not already published
    IF v_post.published_at IS NOT NULL THEN
        RETURN jsonb_build_object('success', false, 'error', 'Post already published');
    END IF;

    -- Update post
    UPDATE tb_post
    SET published_at = NOW()
    WHERE id = p_post_id;

    -- Sync projection table
    PERFORM fn_sync_tv_post(p_post_id);

    -- Log event
    INSERT INTO audit_log (action, details)
    VALUES ('post_published', jsonb_build_object('post_id', p_post_id, 'user_email', v_post.user_email));

    -- Return success
    RETURN jsonb_build_object('success', true, 'post_id', p_post_id);
END;
$$ LANGUAGE plpgsql;

Business logic, validation, logging - all in the database function. Crystal clear for humans and AI.

Selective CASCADE Querying

Request only the CASCADE data you need:

mutation CreatePost($input: CreatePostInput!) {
  createPost(input: $input) {
    post { id title }

    # Option 1: No CASCADE (smallest payload)
    # Just omit the cascade field

    # Option 2: Metadata only
    cascade {
      metadata { affectedCount }
    }

    # Option 3: Full CASCADE
    cascade {
      updated { __typename id entity }
      deleted { __typename id }
      invalidations { queryName }
      metadata { affectedCount }
    }
  }
}

Performance: Not requesting CASCADE reduces response size by 2-10x.

πŸ’° In PostgreSQL Everything

Replace 4 services with 1 database.

Cost Savings Calculator

Traditional StackFraiseQL StackAnnual Savings
PostgreSQL: $50/moPostgreSQL: $50/mo-
Redis Cloud: $50-500/moβœ… In PostgreSQL$600-6,000/yr
Sentry: $300-3,000/moβœ… In PostgreSQL$3,600-36,000/yr
APM Tool: $100-500/moβœ… In PostgreSQL$1,200-6,000/yr
Total: $500-4,050/moTotal: $50/mo$5,400-48,000/yr

How It Works

Caching (Replaces Redis)

from fraiseql.caching import PostgresCache

cache = PostgresCache(db_pool)
await cache.set("user:123", user_data, ttl=3600)

# Uses PostgreSQL UNLOGGED tables
# - No WAL overhead = fast writes
# - Shared across instances
# - TTL-based expiration
# - Pattern-based deletion

Error Tracking (Replaces 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
# - OpenTelemetry trace correlation
# - Custom notifications (Email, Slack, Webhook)

Observability (Replaces APM)

-- All traces and metrics stored in PostgreSQL
SELECT * FROM monitoring.traces
WHERE error_id = 'error-123'
  AND trace_id = 'trace-xyz';

Grafana Dashboards Pre-built dashboards in grafana/ query PostgreSQL directly:

  • Error monitoring dashboard
  • Performance metrics dashboard
  • OpenTelemetry traces dashboard

Operational Benefits

  • βœ… 70% fewer services to deploy and monitor
  • βœ… One database to backup (not 4 separate systems)
  • βœ… No Redis connection timeouts or cluster issues
  • βœ… No Sentry quota surprises or rate limiting
  • βœ… ACID guarantees for everything (no eventual consistency)
  • βœ… Self-hosted - full control, no vendor lock-in

πŸ—οΈ Architecture Deep Dive

Rust-First Execution

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”    β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”    β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚   GraphQL       β”‚ β†’  β”‚   PostgreSQL     β”‚ β†’  β”‚   Rust          β”‚
β”‚   Request       β”‚    β”‚   JSONB Query    β”‚    β”‚   Transform     β”‚
β”‚                 β”‚    β”‚                  β”‚    β”‚   (7-10x faster)β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜    β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜    β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                                                         ↓
                                                β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
                                                β”‚   FastAPI       β”‚
                                                β”‚   HTTP Response β”‚
                                                β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Unified path for all queries:

  • GraphQL query arrives at FastAPI
  • Python resolver calls PostgreSQL view/function
  • PostgreSQL returns pre-composed JSONB
  • Rust pipeline transforms JSONB based on GraphQL selection
  • FastAPI returns bytes directly (zero Python serialization)

CQRS Pattern

FraiseQL implements Command Query Responsibility Segregation:

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚         GraphQL API                 β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚   QUERIES        β”‚   MUTATIONS      β”‚
β”‚   (Reads)        β”‚   (Writes)       β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚  v_* views       β”‚  fn_* functions  β”‚
β”‚  tv_* tables     β”‚  tb_* tables     β”‚
β”‚  JSONB ready     β”‚  Business logic  β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Queries use views:

  • v_* - Real-time views with JSONB computation
  • tv_* - Denormalized tables with generated JSONB columns (for complex queries)

Mutations use functions:

  • fn_* - Business logic, validation, side effects
  • tb_* - Base tables for data storage

πŸ“Š Detailed Architecture Diagrams

Key Innovations

1. Exclusive Rust Pipeline

  • PostgreSQL β†’ Rust β†’ HTTP (no Python JSON processing)
  • 7-10x faster JSON transformation vs Python
  • No GIL contention, compiled performance

2. JSONB Views

  • Database composes data once
  • Rust selects fields based on GraphQL query
  • No N+1 query problems

3. Table Views (tv_*)

-- Denormalized JSONB table with explicit sync
CREATE TABLE tv_user (
    id INT PRIMARY KEY,
    data JSONB NOT NULL,  -- Regular column, not generated
    updated_at TIMESTAMPTZ DEFAULT NOW()
);

-- Sync function populates tv_* from v_* view
CREATE FUNCTION fn_sync_tv_user(p_user_id INT) RETURNS VOID AS $$
BEGIN
    INSERT INTO tv_user (id, data)
    SELECT id, data FROM v_user WHERE id = p_user_id
    ON CONFLICT (id) DO UPDATE SET
        data = EXCLUDED.data,
        updated_at = NOW();
END;
$$ LANGUAGE plpgsql;

-- Mutations call sync explicitly
CREATE FUNCTION fn_create_user(p_name TEXT) RETURNS JSONB AS $$
DECLARE v_user_id INT;
BEGIN
    INSERT INTO tb_user (name) VALUES (p_name) RETURNING id INTO v_user_id;
    PERFORM fn_sync_tv_user(v_user_id);  -- ← Explicit sync call
    RETURN (SELECT data FROM tv_user WHERE id = v_user_id);
END;
$$ LANGUAGE plpgsql;

Benefits: Instant lookups, embedded relations, explicitly synchronized

4. Zero-Copy Response

  • Direct RustResponseBytes to FastAPI
  • No Python serialization overhead
  • Optimal for high-throughput APIs

🎯 How FraiseQL Is Different

Execution Path Comparison

FrameworkData FlowJSON ProcessingRecursion ProtectionSecurity Model
FraiseQLPostgreSQL JSONB β†’ Rust β†’ HTTPβœ… Rust (compiled)βœ… View-enforcedβœ… Explicit contracts
Strawberry + SQLAlchemyPostgreSQL β†’ ORM β†’ Python dict β†’ JSON❌ Python (2 steps)⚠️ Middleware required❌ ORM over-fetching risk
HasuraPostgreSQL β†’ Haskell β†’ JSON⚠️ Haskell⚠️ Middleware required⚠️ Complex permission system
PostGraphilePostgreSQL β†’ Node.js β†’ JSON⚠️ JavaScript⚠️ Middleware required⚠️ Plugin-based

FraiseQL's Unique Advantages

  • βœ… Database returns final structure (JSONB views)
  • βœ… Rust handles field selection (compiled performance)
  • βœ… No Python in hot path (zero serialization overhead)
  • βœ… No ORM abstraction (SQL functions are business logic)
  • βœ… Built-in recursion protection (view defines max depth, no middleware needed)
  • βœ… Secure by design (explicit field contracts prevent data leaks)
  • βœ… AI-readable (clear contracts, full context visible)
  • βœ… PostgreSQL-native (caching, monitoring, APQ in one database)

🎯 Advanced Features

Automatic Persisted Queries (APQ)

Enterprise-grade APQ with pluggable storage backends:

from fraiseql import FraiseQLConfig

# Memory backend (zero configuration)
config = FraiseQLConfig(apq_storage_backend="memory")

# PostgreSQL backend (multi-instance coordination)
config = FraiseQLConfig(
    apq_storage_backend="postgresql",
    apq_storage_schema="apq_cache"
)

How it works:

  • Client sends query hash instead of full query
  • FraiseQL checks storage backend for cached query
  • PostgreSQL β†’ Rust β†’ HTTP (same fast path)
  • Bandwidth reduction with large queries

⚑ APQ Details

Specialized Type System

Advanced operators for network types, hierarchical data, ranges, and nested arrays:

query {
  servers(where: {
    ipAddress: { eq: "192.168.1.1" }          # β†’ ::inet casting
    port: { gt: 1024 }                        # β†’ ::integer casting
    location: { ancestor_of: "US.CA" }        # β†’ ltree operations
    dateRange: { overlaps: "[2024-01-01,2024-12-31)" }

    # Nested array filtering with logical operators
    printServers(where: {
      AND: [
        { operatingSystem: { in: ["Linux", "Windows"] } }
        { OR: [
            { nTotalAllocations: { gte: 100 } }
            { NOT: { ipAddress: { isnull: true } } }
          ]
        }
      ]
    }) {
      hostname operatingSystem
    }
  }) {
    id name ipAddress port
  }
}

50+ Specialized Scalar Types:

Financial & Trading:

  • CUSIP, ISIN, SEDOL, MIC, LEI - Security identifiers
  • Money, Percentage, ExchangeRate - Financial values
  • CurrencyCode, StockSymbol - Trading symbols

Network & Infrastructure:

  • IPv4, IPv4, CIDR, MACAddress - Network addresses with subnet operations
  • Hostname, DomainName, Port, EmailAddress - Internet identifiers
  • APIKey, HashSHA256 - Security tokens

Geospatial & Location:

  • Coordinate, Latitude, Longitude - Geographic coordinates with distance calculations
  • PostalCode, Timezone - Location data

Business & Logistics:

  • ContainerNumber, FlightNumber, TrackingNumber, VIN - Asset identifiers
  • IBAN, LicensePlate - Financial & vehicle identifiers
  • PhoneNumber, LocaleCode, LanguageCode - Contact & localization

Technical & Data:

  • UUID, JSON, Date, DateTime, Time, DateRange - Standard types with validation
  • LTree - Hierarchical data with ancestor/descendant queries
  • SemanticVersion, Color, MIMEType, File, Image - Specialized formats
  • HTML, Markdown - Rich text content

Advanced Filtering: Full-text search, JSONB queries, array operations, regex, vector similarity search on all types

Scalar Type Usage Examples

from fraiseql import type
from fraiseql.types import (
    EmailAddress, PhoneNumber, Money, Percentage,
    CUSIP, ISIN, IPv4, MACAddress, LTree, DateRange
)

@fraiseql.type(sql_source="v_financial_data")
class FinancialRecord:
    id: int
    email: EmailAddress           # Validated email addresses
    phone: PhoneNumber           # International phone numbers
    balance: Money               # Currency amounts with precision
    margin: Percentage           # Percentages (0.00-100.00)
    security_id: CUSIP | ISIN    # Financial instrument identifiers

@fraiseql.type(sql_source="v_network_device")
class NetworkDevice:
    id: int
    ip_address: IPv4             # IPv4 addresses with subnet operations
    mac_address: MACAddress      # MAC addresses with validation
    location: LTree              # Hierarchical location paths
    maintenance_window: DateRange # Date ranges with overlap queries
# Advanced filtering with specialized types
query {
  financialRecords(where: {
    balance: { gte: "1000.00" }           # Money comparison
    margin: { between: ["5.0", "15.0"] }   # Percentage range
    security_id: { eq: "037833100" }       # CUSIP validation
  }) {
    id balance margin security_id
  }

  networkDevices(where: {
    ip_address: { inSubnet: "192.168.1.0/24" }  # CIDR operations
    location: { ancestor_of: "US.CA.SF" }       # LTree hierarchy
    maintenance_window: { overlaps: "[2024-01-01,2024-12-31)" }
  }) {
    id ip_address location
  }
}

πŸ“– Nested Array Filtering Guide

Enterprise Security

from fraiseql import authorized

@fraiseql.authorized(roles=["admin", "editor"])
@fraiseql.mutation
class DeletePost:
    """Only admins and editors can delete posts."""
    input: DeletePostInput
    success: DeleteSuccess
    failure: PermissionDenied

# Features:
# - Field-level authorization with role inheritance
# - Row-level security via PostgreSQL RLS
# - Unified audit logging with cryptographic chain (SHA-256 + HMAC)
# - Multi-tenant isolation
# - Rate limiting and CSRF protection

Trinity Identifiers

Three types of identifiers per entity for different purposes:

@fraiseql.type(sql_source="v_post")
class Post(TrinityMixin):
    """
    Trinity Pattern:
    - pk_post (int): Internal SERIAL key (NOT exposed, only in database)
    - id (UUID): Public API key (exposed, stable)
    - identifier (str): Human-readable slug (exposed, SEO-friendly)
    """

    # GraphQL exposed fields
    id: UUID                  # Public API (stable, secure)
    identifier: str | None    # Human-readable (SEO-friendly, slugs)
    title: str
    content: str
    # ... other fields

    # pk_post is NOT a field - accessed via TrinityMixin.get_internal_pk()

Why three?

  • pk_*: Fast integer joins (PostgreSQL only, never in GraphQL schema)
  • id: Public API stability (UUID, exposed, never changes)
  • identifier: Human-friendly URLs (exposed, SEO, readability)

πŸš€ Get Started in 5 Minutes

# Install
pip install fraiseql

# Create project
fraiseql init my-api
cd my-api

# Setup database
createdb my_api
psql my_api < schema.sql

# Start server
fraiseql dev

Your GraphQL API is live at http://localhost:8000/graphql πŸŽ‰

Next Steps

Prerequisites

  • Python 3.13+ (required for Rust pipeline integration and advanced type features)
  • PostgreSQL 13+

πŸ“– Detailed Installation Guide - Platform-specific instructions, troubleshooting

🚦 Is FraiseQL Right for You?

βœ… Perfect For

  • PostgreSQL-first teams already using PostgreSQL extensively
  • Performance-critical APIs requiring efficient data access
  • Multi-tenant SaaS with per-tenant isolation needs
  • Cost-conscious startups ($5-48K annual savings vs traditional stack)
  • AI-assisted development teams using Claude/Copilot/ChatGPT
  • Operational simplicity - one database for everything
  • Self-hosted infrastructure - full control, no vendor lock-in

❌ Consider Alternatives

  • Multi-database support - FraiseQL is PostgreSQL-specific
  • Simple CRUD APIs - Traditional REST may be simpler
  • Non-PostgreSQL databases - FraiseQL requires PostgreSQL
  • Microservices - Better for monolithic or database-per-service

πŸ› οΈ 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

Learn More

Contributing

git clone https://github.com/fraiseql/fraiseql
cd fraiseql && make setup-dev
prek install  # 7-10x faster than pre-commit

β†’ Contributing Guide

About

FraiseQL is created by Lionel Hamayon (@evoludigit).

The Idea: What if PostgreSQL returned JSON directly instead of Python serializing it? No ORM. No N+1 queries. No Python overhead. Just Rust transforming JSONB to HTTP.

The Result: A GraphQL framework that's 7-10x faster and designed for the LLM era.

License

MIT License - see LICENSE

πŸ“„ License

MIT License - see LICENSE for details.

πŸ“‹ Project Navigation

Version Overview

VersionLocationStatusPurposeFor Users?
v1.9.4Root levelStableAPQ security fixes + ID Policy configurationβœ… Production Ready
Rust Pipelinefraiseql_rs/IntegratedIncluded in v1.9.4+βœ… Stable

New to FraiseQL? β†’ First Hour Guide β€’ Project Structure

πŸ“– Complete Version Roadmap

Ready to build the most efficient GraphQL API in Python?

pip install fraiseql && fraiseql init my-api

πŸš€ PostgreSQL β†’ Rust β†’ Production

Keywords

graphql

FAQs

Did you know?

Socket

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Install

Related posts