Smithery Logo
MCPsSkillsDocsPricing
Login
Smithery Logo

Accelerating the Agent Economy

Resources

DocumentationPrivacy PolicySystem Status

Company

PricingAboutBlog

Connect

© 2026 Smithery. All rights reserved.

    ehtbanton

    sql-schema-generator

    ehtbanton/sql-schema-generator
    Data & Analytics

    About

    SKILL.md

    Install

    Install via Skills CLI

    or add to your agent
    • Claude Code
      Claude Code
    • Codex
      Codex
    • OpenClaw
      OpenClaw
    • Cursor
      Cursor
    • Amp
      Amp
    • GitHub Copilot
      GitHub Copilot
    • Gemini CLI
      Gemini CLI
    • Kilo Code
      Kilo Code
    • Junie
      Junie
    • Replit
      Replit
    • Windsurf
      Windsurf
    • Cline
      Cline
    • Continue
      Continue
    • OpenCode
      OpenCode
    • OpenHands
      OpenHands
    • Roo Code
      Roo Code
    • Augment
      Augment
    • Goose
      Goose
    • Trae
      Trae
    • Zencoder
      Zencoder
    • Antigravity
      Antigravity
    ├─
    ├─
    └─

    About

    Generate SQL database schema files with tables, relationships, indexes, and constraints for PostgreSQL, MySQL, or SQLite...

    SKILL.md

    SQL Schema Generator

    Generate complete, normalized SQL database schemas with tables, relationships, indexes, and constraints.

    Output Requirements

    File Output: .sql files Naming Convention: schema.sql, 001_create_tables.sql, {feature}_schema.sql Dialects: PostgreSQL (default), MySQL, SQLite

    When Invoked

    Immediately generate a complete SQL schema file. Default to PostgreSQL syntax unless otherwise specified.

    SQL Best Practices

    Naming Conventions

    • Tables: plural, snake_case (users, order_items)
    • Columns: singular, snake_case (user_id, created_at)
    • Primary keys: id or {table}_id
    • Foreign keys: {referenced_table_singular}_id
    • Indexes: idx_{table}_{column(s)}
    • Constraints: {table}_{type}_{column} (e.g., users_email_unique)

    Data Types (PostgreSQL)

    Use Case Type
    Primary Key BIGSERIAL or UUID
    Foreign Key BIGINT or UUID
    Short text VARCHAR(n)
    Long text TEXT
    Boolean BOOLEAN
    Integer INTEGER, BIGINT
    Decimal/Money NUMERIC(precision, scale)
    Date DATE
    Timestamp TIMESTAMPTZ
    JSON JSONB
    Enum Custom TYPE

    Standard Columns

    Every table should consider:

    • id - Primary key
    • created_at - Record creation timestamp
    • updated_at - Last modification timestamp
    • deleted_at - Soft delete timestamp (if applicable)

    Schema Templates

    User Authentication System

    -- Enable UUID extension (PostgreSQL)
    CREATE EXTENSION IF NOT EXISTS "uuid-ossp";
    
    -- Users table
    CREATE TABLE users (
        id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
        email VARCHAR(255) NOT NULL,
        password_hash VARCHAR(255) NOT NULL,
        first_name VARCHAR(100),
        last_name VARCHAR(100),
        avatar_url TEXT,
        email_verified_at TIMESTAMPTZ,
        is_active BOOLEAN DEFAULT true,
        created_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP,
        updated_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP,
    
        CONSTRAINT users_email_unique UNIQUE (email)
    );
    
    -- Index for email lookups
    CREATE INDEX idx_users_email ON users(email);
    CREATE INDEX idx_users_created_at ON users(created_at);
    
    -- Sessions table
    CREATE TABLE sessions (
        id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
        user_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE,
        token_hash VARCHAR(255) NOT NULL,
        ip_address INET,
        user_agent TEXT,
        expires_at TIMESTAMPTZ NOT NULL,
        created_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP,
    
        CONSTRAINT sessions_token_unique UNIQUE (token_hash)
    );
    
    CREATE INDEX idx_sessions_user_id ON sessions(user_id);
    CREATE INDEX idx_sessions_expires_at ON sessions(expires_at);
    
    -- Password reset tokens
    CREATE TABLE password_resets (
        id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
        user_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE,
        token_hash VARCHAR(255) NOT NULL,
        expires_at TIMESTAMPTZ NOT NULL,
        used_at TIMESTAMPTZ,
        created_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP,
    
        CONSTRAINT password_resets_token_unique UNIQUE (token_hash)
    );
    
    CREATE INDEX idx_password_resets_user_id ON password_resets(user_id);
    

    E-commerce Schema

    -- Customers
    CREATE TABLE customers (
        id BIGSERIAL PRIMARY KEY,
        email VARCHAR(255) NOT NULL UNIQUE,
        first_name VARCHAR(100) NOT NULL,
        last_name VARCHAR(100) NOT NULL,
        phone VARCHAR(20),
        created_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP,
        updated_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP
    );
    
    -- Addresses
    CREATE TABLE addresses (
        id BIGSERIAL PRIMARY KEY,
        customer_id BIGINT NOT NULL REFERENCES customers(id) ON DELETE CASCADE,
        type VARCHAR(20) DEFAULT 'shipping', -- shipping, billing
        line1 VARCHAR(255) NOT NULL,
        line2 VARCHAR(255),
        city VARCHAR(100) NOT NULL,
        state VARCHAR(100),
        postal_code VARCHAR(20) NOT NULL,
        country CHAR(2) NOT NULL, -- ISO 3166-1 alpha-2
        is_default BOOLEAN DEFAULT false,
        created_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP
    );
    
    CREATE INDEX idx_addresses_customer_id ON addresses(customer_id);
    
    -- Categories
    CREATE TABLE categories (
        id BIGSERIAL PRIMARY KEY,
        parent_id BIGINT REFERENCES categories(id) ON DELETE SET NULL,
        name VARCHAR(100) NOT NULL,
        slug VARCHAR(100) NOT NULL UNIQUE,
        description TEXT,
        image_url TEXT,
        sort_order INTEGER DEFAULT 0,
        is_active BOOLEAN DEFAULT true,
        created_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP
    );
    
    CREATE INDEX idx_categories_parent_id ON categories(parent_id);
    CREATE INDEX idx_categories_slug ON categories(slug);
    
    -- Products
    CREATE TABLE products (
        id BIGSERIAL PRIMARY KEY,
        sku VARCHAR(50) NOT NULL UNIQUE,
        name VARCHAR(255) NOT NULL,
        slug VARCHAR(255) NOT NULL UNIQUE,
        description TEXT,
        price NUMERIC(10, 2) NOT NULL,
        compare_at_price NUMERIC(10, 2),
        cost NUMERIC(10, 2),
        quantity INTEGER DEFAULT 0,
        weight_kg NUMERIC(8, 3),
        is_active BOOLEAN DEFAULT true,
        is_featured BOOLEAN DEFAULT false,
        metadata JSONB DEFAULT '{}',
        created_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP,
        updated_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP,
    
        CONSTRAINT products_price_positive CHECK (price >= 0),
        CONSTRAINT products_quantity_positive CHECK (quantity >= 0)
    );
    
    CREATE INDEX idx_products_sku ON products(sku);
    CREATE INDEX idx_products_slug ON products(slug);
    CREATE INDEX idx_products_is_active ON products(is_active) WHERE is_active = true;
    
    -- Product Categories (many-to-many)
    CREATE TABLE product_categories (
        product_id BIGINT NOT NULL REFERENCES products(id) ON DELETE CASCADE,
        category_id BIGINT NOT NULL REFERENCES categories(id) ON DELETE CASCADE,
        PRIMARY KEY (product_id, category_id)
    );
    
    -- Product Images
    CREATE TABLE product_images (
        id BIGSERIAL PRIMARY KEY,
        product_id BIGINT NOT NULL REFERENCES products(id) ON DELETE CASCADE,
        url TEXT NOT NULL,
        alt_text VARCHAR(255),
        sort_order INTEGER DEFAULT 0,
        is_primary BOOLEAN DEFAULT false,
        created_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP
    );
    
    CREATE INDEX idx_product_images_product_id ON product_images(product_id);
    
    -- Orders
    CREATE TYPE order_status AS ENUM (
        'pending', 'confirmed', 'processing',
        'shipped', 'delivered', 'cancelled', 'refunded'
    );
    
    CREATE TABLE orders (
        id BIGSERIAL PRIMARY KEY,
        customer_id BIGINT REFERENCES customers(id) ON DELETE SET NULL,
        order_number VARCHAR(20) NOT NULL UNIQUE,
        status order_status DEFAULT 'pending',
        subtotal NUMERIC(10, 2) NOT NULL,
        tax NUMERIC(10, 2) DEFAULT 0,
        shipping NUMERIC(10, 2) DEFAULT 0,
        discount NUMERIC(10, 2) DEFAULT 0,
        total NUMERIC(10, 2) NOT NULL,
        currency CHAR(3) DEFAULT 'USD',
        shipping_address JSONB,
        billing_address JSONB,
        notes TEXT,
        created_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP,
        updated_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP
    );
    
    CREATE INDEX idx_orders_customer_id ON orders(customer_id);
    CREATE INDEX idx_orders_order_number ON orders(order_number);
    CREATE INDEX idx_orders_status ON orders(status);
    CREATE INDEX idx_orders_created_at ON orders(created_at);
    
    -- Order Items
    CREATE TABLE order_items (
        id BIGSERIAL PRIMARY KEY,
        order_id BIGINT NOT NULL REFERENCES orders(id) ON DELETE CASCADE,
        product_id BIGINT REFERENCES products(id) ON DELETE SET NULL,
        sku VARCHAR(50) NOT NULL,
        name VARCHAR(255) NOT NULL,
        quantity INTEGER NOT NULL,
        unit_price NUMERIC(10, 2) NOT NULL,
        total NUMERIC(10, 2) NOT NULL,
    
        CONSTRAINT order_items_quantity_positive CHECK (quantity > 0)
    );
    
    CREATE INDEX idx_order_items_order_id ON order_items(order_id);
    

    SaaS Multi-tenant Schema

    -- Organizations (tenants)
    CREATE TABLE organizations (
        id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
        name VARCHAR(255) NOT NULL,
        slug VARCHAR(100) NOT NULL UNIQUE,
        plan VARCHAR(50) DEFAULT 'free',
        settings JSONB DEFAULT '{}',
        created_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP,
        updated_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP
    );
    
    CREATE INDEX idx_organizations_slug ON organizations(slug);
    
    -- Users
    CREATE TABLE users (
        id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
        email VARCHAR(255) NOT NULL UNIQUE,
        password_hash VARCHAR(255) NOT NULL,
        name VARCHAR(255),
        avatar_url TEXT,
        is_active BOOLEAN DEFAULT true,
        created_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP,
        updated_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP
    );
    
    -- Organization memberships
    CREATE TYPE member_role AS ENUM ('owner', 'admin', 'member', 'viewer');
    
    CREATE TABLE organization_members (
        id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
        organization_id UUID NOT NULL REFERENCES organizations(id) ON DELETE CASCADE,
        user_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE,
        role member_role DEFAULT 'member',
        invited_by UUID REFERENCES users(id),
        joined_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP,
    
        CONSTRAINT org_members_unique UNIQUE (organization_id, user_id)
    );
    
    CREATE INDEX idx_org_members_org_id ON organization_members(organization_id);
    CREATE INDEX idx_org_members_user_id ON organization_members(user_id);
    
    -- Projects (scoped to organization)
    CREATE TABLE projects (
        id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
        organization_id UUID NOT NULL REFERENCES organizations(id) ON DELETE CASCADE,
        name VARCHAR(255) NOT NULL,
        description TEXT,
        is_archived BOOLEAN DEFAULT false,
        created_by UUID REFERENCES users(id),
        created_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP,
        updated_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP
    );
    
    CREATE INDEX idx_projects_org_id ON projects(organization_id);
    
    -- Audit log
    CREATE TABLE audit_logs (
        id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
        organization_id UUID REFERENCES organizations(id) ON DELETE SET NULL,
        user_id UUID REFERENCES users(id) ON DELETE SET NULL,
        action VARCHAR(100) NOT NULL,
        resource_type VARCHAR(100) NOT NULL,
        resource_id UUID,
        old_values JSONB,
        new_values JSONB,
        ip_address INET,
        user_agent TEXT,
        created_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP
    );
    
    CREATE INDEX idx_audit_logs_org_id ON audit_logs(organization_id);
    CREATE INDEX idx_audit_logs_user_id ON audit_logs(user_id);
    CREATE INDEX idx_audit_logs_created_at ON audit_logs(created_at);
    

    Common Patterns

    Soft Deletes

    -- Add to table
    deleted_at TIMESTAMPTZ,
    
    -- Query active records
    WHERE deleted_at IS NULL
    
    -- Index for soft deletes
    CREATE INDEX idx_table_active ON table(id) WHERE deleted_at IS NULL;
    

    Full-Text Search (PostgreSQL)

    -- Add search vector column
    ALTER TABLE products ADD COLUMN search_vector tsvector;
    
    -- Create GIN index
    CREATE INDEX idx_products_search ON products USING gin(search_vector);
    
    -- Update trigger
    CREATE FUNCTION products_search_trigger() RETURNS trigger AS $$
    BEGIN
        NEW.search_vector := to_tsvector('english',
            coalesce(NEW.name, '') || ' ' ||
            coalesce(NEW.description, '')
        );
        RETURN NEW;
    END
    $$ LANGUAGE plpgsql;
    
    CREATE TRIGGER products_search_update
        BEFORE INSERT OR UPDATE ON products
        FOR EACH ROW EXECUTE FUNCTION products_search_trigger();
    

    Updated At Trigger

    CREATE OR REPLACE FUNCTION update_updated_at()
    RETURNS TRIGGER AS $$
    BEGIN
        NEW.updated_at = CURRENT_TIMESTAMP;
        RETURN NEW;
    END;
    $$ LANGUAGE plpgsql;
    
    -- Apply to tables
    CREATE TRIGGER update_users_updated_at
        BEFORE UPDATE ON users
        FOR EACH ROW EXECUTE FUNCTION update_updated_at();
    

    Validation Checklist

    Before outputting, verify:

    • Tables have primary keys
    • Foreign keys have appropriate ON DELETE actions
    • Unique constraints where needed
    • Check constraints for data validation
    • Indexes on foreign keys and frequently queried columns
    • Timestamps use TIMESTAMPTZ (timezone aware)
    • Naming conventions are consistent
    • No reserved word conflicts

    Example Invocations

    Prompt: "Create SQL schema for a blog with posts, comments, and tags" Output: Complete schema.sql with normalized tables, relationships, indexes.

    Prompt: "Generate PostgreSQL schema for a booking system" Output: Complete schema with users, resources, bookings, availability tables.

    Prompt: "Database schema for inventory management" Output: Complete schema with products, warehouses, stock movements, transactions.

    Recommended Servers
    Neon
    Neon
    Prisma
    Prisma
    Google BigQuery
    Google BigQuery
    Repository
    ehtbanton/claudeskillsrepo
    Files