Skip to content

Project Structure Guide

This guide explains the recommended project structure for FraiseQL applications, created automatically by fraiseql init.

Visual Structure

my-project/
โ”œโ”€โ”€ src/                          # ๐Ÿ“ Application source code
โ”‚   โ”œโ”€โ”€ main.py                  # ๐Ÿš€ GraphQL schema & FastAPI app
โ”‚   โ”œโ”€โ”€ types/                   # ๐Ÿท๏ธ  GraphQL type definitions
โ”‚   โ”‚   โ”œโ”€โ”€ user.py             #   โ””โ”€ User, Post, Comment types
โ”‚   โ”‚   โ”œโ”€โ”€ post.py
โ”‚   โ”‚   โ””โ”€โ”€ __init__.py
โ”‚   โ”œโ”€โ”€ queries/                 # ๐Ÿ” Custom query resolvers
โ”‚   โ”‚   โ”œโ”€โ”€ user_queries.py     #   โ””โ”€ Complex business logic
โ”‚   โ”‚   โ””โ”€โ”€ __init__.py
โ”‚   โ”œโ”€โ”€ mutations/              # โœ๏ธ  Mutation handlers
โ”‚   โ”‚   โ”œโ”€โ”€ user_mutations.py   #   โ””โ”€ Data modification ops
โ”‚   โ”‚   โ””โ”€โ”€ __init__.py
โ”‚   โ””โ”€โ”€ __init__.py
โ”œโ”€โ”€ tests/                       # ๐Ÿงช Test suite
โ”‚   โ”œโ”€โ”€ test_user.py            #   โ””โ”€ Unit & integration tests
โ”‚   โ””โ”€โ”€ conftest.py
โ”œโ”€โ”€ migrations/                  # ๐Ÿ—ƒ๏ธ  Database evolution
โ”‚   โ”œโ”€โ”€ 001_initial_schema.sql  #   โ””โ”€ Versioned schema changes
โ”‚   โ””โ”€โ”€ 002_add_indexes.sql
โ”œโ”€โ”€ .env                         # ๐Ÿ” Environment config
โ”œโ”€โ”€ .gitignore                  # ๐Ÿšซ Git ignore rules
โ”œโ”€โ”€ pyproject.toml              # ๐Ÿ“ฆ Dependencies & config
โ””โ”€โ”€ README.md                   # ๐Ÿ“– Project documentation

Overview

FraiseQL projects follow a database-first architecture with clear separation of concerns. The structure emphasizes: - Database-first design: Schema and views come first - Modular organization: Separate directories for different concerns - Scalable patterns: Easy to grow from minimal to enterprise

Template Selection Guide

Choose the right starting template based on your project needs:

๐Ÿš€ Quickstart (No Template)

Best for: Learning FraiseQL, prototypes, experimentation What you get: Single-file app with basic CRUD operations When to use: First time with FraiseQL, proof-of-concepts Evolution path: Migrate to minimal template when growing

๐Ÿ“ฆ Minimal Template

Best for: Simple applications, MVPs, small projects Features: - Single-file GraphQL schema - Basic CRUD operations - PostgreSQL integration - Development server setup Example: Todo app, simple blog, basic API

๐Ÿ—๏ธ Standard Template

Best for: Production applications, medium complexity Features: - Multi-file organization (types, queries, mutations) - User authentication & authorization - Query result caching - Comprehensive testing setup - Migration system Example: SaaS app, e-commerce platform, content management

๐Ÿข Enterprise Template

Best for: Large-scale applications, high traffic Features: - Multi-tenant architecture - Advanced caching (APQ, result caching) - Monitoring & observability - Microservices-ready structure - Performance optimizations Example: Enterprise platforms, high-traffic APIs

Evolution Path

Quickstart โ†’ Minimal โ†’ Standard โ†’ Enterprise
    โ†“          โ†“         โ†“          โ†“
 Learning   Simple    Production  Scale
Prototypes   Apps       Apps      Apps

Migration Tips: - Quickstart โ†’ Minimal: Use fraiseql init and move code to organized structure - Minimal โ†’ Standard: Split into multiple files, add authentication - Standard โ†’ Enterprise: Add multi-tenancy, advanced caching, monitoring

Best Practices by Template

Quickstart Best Practices

  • โœ… Keep it simple - single file for learning
  • โœ… Focus on GraphQL concepts over architecture
  • โœ… Use for experimentation and prototyping
  • โŒ Don't use for production applications
  • โŒ Don't add complex business logic

Example Projects: Todo App Quickstart

Minimal Template Best Practices

  • โœ… Single-file schema for simple domains
  • โœ… Clear type definitions with descriptions
  • โœ… Basic error handling and validation
  • โœ… Database-first design principles
  • โŒ Don't mix concerns in main.py
  • โŒ Don't skip input validation

Example Projects: Simple Blog, Basic API

Standard Template Best Practices

  • โœ… Separate types, queries, and mutations
  • โœ… Comprehensive test coverage
  • โœ… Authentication and authorization
  • โœ… Query result caching
  • โœ… Proper error handling
  • โŒ Don't put business logic in resolvers
  • โŒ Don't skip database migrations

Example Projects: Blog with Auth, E-commerce

Enterprise Template Best Practices

  • โœ… Multi-tenant data isolation
  • โœ… Advanced performance optimizations
  • โœ… Comprehensive monitoring
  • โœ… Microservices communication patterns
  • โœ… Automated testing and deployment
  • โŒ Don't compromise on security
  • โŒ Don't skip performance monitoring

Example Projects: Enterprise Blog, Multi-tenant App

Directory Structure

my-project/
โ”œโ”€โ”€ src/                    # Application source code
โ”‚   โ”œโ”€โ”€ main.py            # GraphQL schema and FastAPI app
โ”‚   โ”œโ”€โ”€ types/             # GraphQL type definitions
โ”‚   โ”‚   โ”œโ”€โ”€ user.py        # User type
โ”‚   โ”‚   โ”œโ”€โ”€ post.py        # Post type
โ”‚   โ”‚   โ””โ”€โ”€ __init__.py
โ”‚   โ”œโ”€โ”€ queries/           # Custom query resolvers
โ”‚   โ”‚   โ”œโ”€โ”€ user_queries.py
โ”‚   โ”‚   โ””โ”€โ”€ __init__.py
โ”‚   โ”œโ”€โ”€ mutations/         # Mutation handlers
โ”‚   โ”‚   โ”œโ”€โ”€ user_mutations.py
โ”‚   โ”‚   โ””โ”€โ”€ __init__.py
โ”‚   โ””โ”€โ”€ __init__.py
โ”œโ”€โ”€ tests/                 # Test files
โ”‚   โ”œโ”€โ”€ test_user.py
โ”‚   โ””โ”€โ”€ conftest.py
โ”œโ”€โ”€ migrations/            # Database schema changes
โ”‚   โ”œโ”€โ”€ 001_initial_schema.sql
โ”‚   โ””โ”€โ”€ 002_add_indexes.sql
โ”œโ”€โ”€ .env                   # Environment configuration
โ”œโ”€โ”€ .gitignore            # Git ignore rules
โ”œโ”€โ”€ pyproject.toml        # Python dependencies and config
โ””โ”€โ”€ README.md             # Project documentation

Directory Purposes

src/ - Application Code

Purpose: Contains all Python application code organized by responsibility.

  • main.py: Entry point with GraphQL schema definition and FastAPI app
  • types/: GraphQL type definitions using @fraiseql.type decorators
  • queries/: Custom query resolvers for complex business logic
  • mutations/: Mutation handlers for data modification operations

tests/ - Test Suite

Purpose: Comprehensive test coverage for reliability.

  • Unit tests for individual functions
  • Integration tests for database operations
  • API tests for GraphQL endpoints
  • Performance tests for critical paths

migrations/ - Database Evolution

Purpose: Version-controlled database schema changes.

  • SQL files for schema modifications
  • Named with timestamps or sequential numbers
  • Applied with fraiseql migrate command

Configuration Files

  • .env: Environment variables (database URLs, secrets)
  • pyproject.toml: Python dependencies and tool configuration
  • .gitignore: Excludes sensitive files from version control

File Organization Patterns

Type Definitions (src/types/)

# src/types/user.py
import fraiseql
from fraiseql import fraise_field
from fraiseql.types import ID

@fraiseql.type
class User:
    """A user in the system."""
    id: ID = fraise_field(description="User ID")
    username: str = fraise_field(description="Unique username")
    email: str = fraise_field(description="Email address")
    created_at: str = fraise_field(description="Account creation date")

Query Resolvers (src/queries/)

# src/queries/user_queries.py
import fraiseql
from fraiseql import fraise_field
from fraiseql import fraise_field

from ..types.user import User

@fraiseql.type
class UserQueries:
    """User-related query operations."""

    users: list[User] = fraise_field(description="List all users")
    user_by_username: User | None = fraise_field(description="Find user by username")

    async def resolve_users(self, info):
        db = info.context["db"]
        return await db.find("v_user", "users", info)

    async def resolve_user_by_username(self, info, username: str):
        db = info.context["db"]
        return await db.find_one("v_user", username=username)

Mutation Handlers (src/mutations/)

# src/mutations/user_mutations.py
import fraiseql
from fraiseql import fraise_field
from fraiseql import fraise_field
from fraiseql.types import ID

from ..types.user import User

@input
class CreateUserInput:
    """Input for creating a new user."""
    username: str = fraise_field(description="Desired username")
    email: str = fraise_field(description="Email address")

@fraiseql.type
class UserMutations:
    """User-related mutation operations."""

    create_user: User = fraise_field(description="Create a new user account")

    async def resolve_create_user(self, info, input: CreateUserInput):
        db = info.context["db"]
        result = await db.execute_function("fn_create_user", {
            "username": input.username,
            "email": input.email
        })
        return await db.find_one("v_user", id=result["id"])

Main Application (src/main.py)

# src/main.py
import os

import fraiseql
from fraiseql import fraise_field
from fraiseql import fraise_field

from .types.user import User
from .queries.user_queries import UserQueries
from .mutations.user_mutations import UserMutations

@fraiseql.type
class QueryRoot(UserQueries):
    """Root query type combining all query operations."""
    pass

@fraiseql.type
class MutationRoot(UserMutations):
    """Root mutation type combining all mutation operations."""
    pass

# Create the FastAPI app
app = fraiseql.create_fraiseql_app(
    queries=[QueryRoot],
    mutations=[MutationRoot],
    database_url=os.getenv("FRAISEQL_DATABASE_URL"),
)

if __name__ == "__main__":
    import uvicorn
    uvicorn.run(app, host="0.0.0.0", port=8000, reload=True)

Database Organization

Schema Files (migrations/)

migrations/
โ”œโ”€โ”€ 001_initial_schema.sql     # Core tables and views
โ”œโ”€โ”€ 002_add_user_auth.sql      # Authentication tables
โ”œโ”€โ”€ 003_add_indexes.sql        # Performance indexes
โ””โ”€โ”€ 004_add_audit_triggers.sql # Audit logging

Naming Conventions

Tables: - tb_entity - Base tables (e.g., tb_user, tb_post) - tb_entity_history - Audit/history tables

Views: - v_entity - Regular views for queries - tv_entity - Materialized views for performance

Functions: - fn_operation_entity - Mutation functions (e.g., fn_create_user)

Scaling Patterns

From Minimal to Standard

  1. Split main.py: Move types to src/types/
  2. Add authentication: Create user management
  3. Add caching: Enable query result caching
  4. Add tests: Comprehensive test coverage

From Standard to Enterprise

  1. Multi-tenancy: Add tenant isolation
  2. Advanced caching: APQ and result caching
  3. Monitoring: Add observability
  4. Microservices: Split into services

Best Practices

Code Organization

  • One type per file in src/types/
  • Group related operations in query/mutation files
  • Use clear, descriptive names
  • Add docstrings to all public functions

Database Design

  • Design views for query patterns, not storage
  • Use functions for complex business logic
  • Index columns used in WHERE clauses
  • Plan for growth and partitioning

Testing Strategy

  • Unit tests for pure functions
  • Integration tests for database operations
  • API tests for GraphQL endpoints
  • Performance tests for critical queries

Configuration Management

  • Use .env for environment-specific settings
  • Never commit secrets to version control
  • Document all configuration options
  • Use sensible defaults

Tooling Integration

Development Tools

# Start development server
fraiseql dev

# Run tests
pytest

# Format code
ruff format

# Type checking
mypy

Production Deployment

  • Use environment variables for configuration
  • Set up proper logging and monitoring
  • Configure database connection pooling
  • Enable caching and performance optimizations

Migration from Quickstart

When your quickstart project grows:

  1. Run fraiseql init: Create proper structure
  2. Move code: Migrate from single file to organized modules
  3. Add tests: Create comprehensive test suite
  4. Add migrations: Version control database changes
  5. Configure CI/CD: Set up automated testing and deployment

This structure provides a solid foundation that scales from simple prototypes to complex, production-ready applications.