Smithery Logo
MCPsSkillsDocsPricing
Login
NewFlame, an assistant that learns and improves. Available onTelegramSlack
    mindrally

    sequelize

    mindrally/sequelize
    Coding
    5

    About

    SKILL.md

    Install

    • Telegram
      Telegram
    • Slack
      Slack
    • 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
    • Download skill
    ├─
    ├─
    └─
    Smithery Logo

    Give agents more agency

    Resources

    DocumentationPrivacy PolicySystem Status

    Company

    PricingAboutBlog

    Connect

    © 2026 Smithery. All rights reserved.

    About

    Guidelines for developing with Sequelize, a promise-based Node.js ORM supporting PostgreSQL, MySQL, MariaDB, SQLite, and SQL Server

    SKILL.md

    Sequelize Development Guidelines

    You are an expert in Sequelize ORM, Node.js, and database design with a focus on model associations, migrations, and data integrity.

    Core Principles

    • Sequelize is a promise-based ORM for Node.js and TypeScript
    • Supports PostgreSQL, MySQL, MariaDB, SQLite, and Microsoft SQL Server
    • Uses model definitions with DataTypes for schema declaration
    • Provides comprehensive support for associations, transactions, and hooks
    • Migrations should be used for all schema changes in production

    Database Connection

    Basic Setup

    import { Sequelize } from "sequelize";
    
    // Option 1: Connection URI
    const sequelize = new Sequelize(process.env.DATABASE_URL!, {
      dialect: "postgres",
      logging: process.env.NODE_ENV === "development" ? console.log : false,
      pool: {
        max: 10,
        min: 0,
        acquire: 30000,
        idle: 10000,
      },
    });
    
    // Option 2: Individual parameters
    const sequelize = new Sequelize({
      dialect: "postgres",
      host: process.env.DB_HOST,
      port: parseInt(process.env.DB_PORT || "5432"),
      username: process.env.DB_USERNAME,
      password: process.env.DB_PASSWORD,
      database: process.env.DB_NAME,
      logging: false,
    });
    
    // Test connection
    async function testConnection() {
      try {
        await sequelize.authenticate();
        console.log("Connection established successfully.");
      } catch (error) {
        console.error("Unable to connect to the database:", error);
      }
    }
    

    Model Definition

    Basic Model with TypeScript

    import {
      Model,
      DataTypes,
      InferAttributes,
      InferCreationAttributes,
      CreationOptional,
    } from "sequelize";
    import { sequelize } from "./database";
    
    class User extends Model<InferAttributes<User>, InferCreationAttributes<User>> {
      declare id: CreationOptional<number>;
      declare email: string;
      declare name: string | null;
      declare isActive: CreationOptional<boolean>;
      declare createdAt: CreationOptional<Date>;
      declare updatedAt: CreationOptional<Date>;
    }
    
    User.init(
      {
        id: {
          type: DataTypes.INTEGER,
          autoIncrement: true,
          primaryKey: true,
        },
        email: {
          type: DataTypes.STRING(255),
          allowNull: false,
          unique: true,
          validate: {
            isEmail: true,
          },
        },
        name: {
          type: DataTypes.STRING(255),
          allowNull: true,
        },
        isActive: {
          type: DataTypes.BOOLEAN,
          defaultValue: true,
        },
        createdAt: DataTypes.DATE,
        updatedAt: DataTypes.DATE,
      },
      {
        sequelize,
        tableName: "users",
        modelName: "User",
        underscored: true, // Use snake_case for column names
      }
    );
    
    export { User };
    

    Data Types Reference

    // String types
    DataTypes.STRING(255)      // VARCHAR(255)
    DataTypes.TEXT             // TEXT
    DataTypes.TEXT("tiny")     // TINYTEXT (MySQL)
    
    // Numeric types
    DataTypes.INTEGER          // INTEGER
    DataTypes.BIGINT           // BIGINT
    DataTypes.FLOAT            // FLOAT
    DataTypes.DOUBLE           // DOUBLE
    DataTypes.DECIMAL(10, 2)   // DECIMAL(10,2)
    
    // Boolean
    DataTypes.BOOLEAN          // BOOLEAN / TINYINT(1)
    
    // Date/Time
    DataTypes.DATE             // DATETIME/TIMESTAMP
    DataTypes.DATEONLY         // DATE
    DataTypes.TIME             // TIME
    
    // Binary
    DataTypes.BLOB             // BLOB
    
    // JSON
    DataTypes.JSON             // JSON (if supported)
    DataTypes.JSONB            // JSONB (PostgreSQL)
    
    // UUID
    DataTypes.UUID             // UUID
    DataTypes.UUIDV4           // Auto-generate UUID v4
    
    // Enum
    DataTypes.ENUM("active", "inactive", "pending")
    
    // Array (PostgreSQL only)
    DataTypes.ARRAY(DataTypes.STRING)
    

    Associations

    One-to-One

    class User extends Model {
      declare id: number;
      declare profile?: Profile;
    }
    
    class Profile extends Model {
      declare id: number;
      declare userId: number;
      declare bio: string;
      declare user?: User;
    }
    
    // Define associations
    User.hasOne(Profile, {
      foreignKey: "userId",
      as: "profile",
    });
    
    Profile.belongsTo(User, {
      foreignKey: "userId",
      as: "user",
    });
    

    One-to-Many

    class User extends Model {
      declare id: number;
      declare posts?: Post[];
    }
    
    class Post extends Model {
      declare id: number;
      declare authorId: number;
      declare title: string;
      declare author?: User;
    }
    
    // Define associations
    User.hasMany(Post, {
      foreignKey: "authorId",
      as: "posts",
    });
    
    Post.belongsTo(User, {
      foreignKey: "authorId",
      as: "author",
    });
    

    Many-to-Many

    class Post extends Model {
      declare id: number;
      declare tags?: Tag[];
    }
    
    class Tag extends Model {
      declare id: number;
      declare name: string;
      declare posts?: Post[];
    }
    
    // Define associations with junction table
    Post.belongsToMany(Tag, {
      through: "PostTags",
      foreignKey: "postId",
      otherKey: "tagId",
      as: "tags",
    });
    
    Tag.belongsToMany(Post, {
      through: "PostTags",
      foreignKey: "tagId",
      otherKey: "postId",
      as: "posts",
    });
    

    Querying

    Basic Queries

    // Find all
    const users = await User.findAll();
    
    // Find with conditions
    const activeUsers = await User.findAll({
      where: {
        isActive: true,
      },
    });
    
    // Find one
    const user = await User.findOne({
      where: { email: "user@example.com" },
    });
    
    // Find by primary key
    const user = await User.findByPk(1);
    
    // Find or create
    const [user, created] = await User.findOrCreate({
      where: { email: "user@example.com" },
      defaults: {
        name: "New User",
      },
    });
    

    Advanced Queries with Operators

    import { Op } from "sequelize";
    
    // Multiple conditions
    const users = await User.findAll({
      where: {
        [Op.and]: [
          { isActive: true },
          { createdAt: { [Op.gte]: new Date("2024-01-01") } },
        ],
      },
    });
    
    // OR condition
    const users = await User.findAll({
      where: {
        [Op.or]: [{ name: "John" }, { name: "Jane" }],
      },
    });
    
    // LIKE
    const users = await User.findAll({
      where: {
        email: { [Op.like]: "%@example.com" },
      },
    });
    
    // IN
    const users = await User.findAll({
      where: {
        id: { [Op.in]: [1, 2, 3] },
      },
    });
    
    // Comparison operators
    const users = await User.findAll({
      where: {
        id: { [Op.gt]: 10 },      // Greater than
        age: { [Op.gte]: 18 },    // Greater than or equal
        score: { [Op.lt]: 100 },  // Less than
        rank: { [Op.lte]: 5 },    // Less than or equal
        status: { [Op.ne]: "inactive" }, // Not equal
      },
    });
    

    Eager Loading (Include)

    // Load user with posts
    const user = await User.findOne({
      where: { id: 1 },
      include: [
        {
          model: Post,
          as: "posts",
        },
      ],
    });
    
    // Nested includes
    const user = await User.findOne({
      where: { id: 1 },
      include: [
        {
          model: Post,
          as: "posts",
          include: [
            {
              model: Tag,
              as: "tags",
            },
          ],
        },
      ],
    });
    
    // Include with conditions
    const users = await User.findAll({
      include: [
        {
          model: Post,
          as: "posts",
          where: {
            publishedAt: { [Op.ne]: null },
          },
          required: false, // LEFT JOIN (include users without posts)
        },
      ],
    });
    

    Pagination and Ordering

    const page = 1;
    const pageSize = 20;
    
    const { count, rows: users } = await User.findAndCountAll({
      where: { isActive: true },
      order: [
        ["createdAt", "DESC"],
        ["name", "ASC"],
      ],
      limit: pageSize,
      offset: (page - 1) * pageSize,
    });
    
    const totalPages = Math.ceil(count / pageSize);
    

    Aggregations

    // Count
    const count = await User.count({
      where: { isActive: true },
    });
    
    // Sum
    const total = await Order.sum("amount", {
      where: { status: "completed" },
    });
    
    // Max/Min
    const maxPrice = await Product.max("price");
    const minPrice = await Product.min("price");
    
    // Group by
    const stats = await Order.findAll({
      attributes: [
        "status",
        [sequelize.fn("COUNT", sequelize.col("id")), "count"],
        [sequelize.fn("SUM", sequelize.col("amount")), "total"],
      ],
      group: ["status"],
    });
    

    CRUD Operations

    Create

    // Create single record
    const user = await User.create({
      email: "user@example.com",
      name: "John Doe",
    });
    
    // Bulk create
    const users = await User.bulkCreate(
      [
        { email: "user1@example.com", name: "User 1" },
        { email: "user2@example.com", name: "User 2" },
      ],
      {
        validate: true, // Run validations on each record
      }
    );
    
    // Create with associations
    const user = await User.create(
      {
        email: "user@example.com",
        name: "John",
        profile: {
          bio: "Hello world",
        },
      },
      {
        include: [{ model: Profile, as: "profile" }],
      }
    );
    

    Update

    // Update single record
    const user = await User.findByPk(1);
    if (user) {
      user.name = "Jane Doe";
      await user.save();
    }
    
    // Update with new data
    await user.update({
      name: "Jane Doe",
      isActive: false,
    });
    
    // Bulk update
    await User.update(
      { isActive: false },
      {
        where: {
          lastLoginAt: { [Op.lt]: new Date("2024-01-01") },
        },
      }
    );
    

    Delete

    // Delete single record
    const user = await User.findByPk(1);
    if (user) {
      await user.destroy();
    }
    
    // Bulk delete
    await User.destroy({
      where: {
        isActive: false,
      },
    });
    
    // Soft delete (requires paranoid: true in model options)
    await user.destroy(); // Sets deletedAt instead of deleting
    
    // Restore soft-deleted record
    await user.restore();
    

    Transactions

    // Managed transaction (recommended)
    const result = await sequelize.transaction(async (t) => {
      const user = await User.create(
        {
          email: "user@example.com",
          name: "User",
        },
        { transaction: t }
      );
    
      const post = await Post.create(
        {
          title: "First Post",
          authorId: user.id,
        },
        { transaction: t }
      );
    
      return { user, post };
    });
    
    // Unmanaged transaction
    const t = await sequelize.transaction();
    
    try {
      const user = await User.create(
        { email: "user@example.com" },
        { transaction: t }
      );
    
      await Post.create(
        { title: "Post", authorId: user.id },
        { transaction: t }
      );
    
      await t.commit();
    } catch (error) {
      await t.rollback();
      throw error;
    }
    

    Hooks

    User.init(
      {
        // ... columns
      },
      {
        sequelize,
        hooks: {
          beforeValidate: (user) => {
            // Normalize email
            if (user.email) {
              user.email = user.email.toLowerCase().trim();
            }
          },
          beforeCreate: async (user) => {
            // Hash password
            if (user.password) {
              user.password = await bcrypt.hash(user.password, 10);
            }
          },
          afterCreate: async (user) => {
            // Send welcome email
            await sendWelcomeEmail(user.email);
          },
          beforeDestroy: async (user) => {
            // Clean up related data
            await Post.destroy({ where: { authorId: user.id } });
          },
        },
      }
    );
    
    // Or define hooks separately
    User.addHook("beforeSave", "hashPassword", async (user) => {
      if (user.changed("password")) {
        user.password = await bcrypt.hash(user.password, 10);
      }
    });
    

    Hook with Transaction Access

    User.addHook("beforeCreate", async (user, options) => {
      if (options.transaction) {
        // Use the same transaction for related operations
        await AuditLog.create(
          {
            action: "user_created",
            userId: user.id,
          },
          { transaction: options.transaction }
        );
      }
    });
    

    Validations

    User.init(
      {
        email: {
          type: DataTypes.STRING,
          allowNull: false,
          validate: {
            isEmail: {
              msg: "Must be a valid email address",
            },
            notEmpty: true,
          },
        },
        age: {
          type: DataTypes.INTEGER,
          validate: {
            min: {
              args: [0],
              msg: "Age must be non-negative",
            },
            max: {
              args: [150],
              msg: "Age must be realistic",
            },
          },
        },
        username: {
          type: DataTypes.STRING,
          validate: {
            len: {
              args: [3, 30],
              msg: "Username must be between 3 and 30 characters",
            },
            isAlphanumeric: {
              msg: "Username must contain only letters and numbers",
            },
            // Custom validator
            async isUnique(value: string) {
              const existing = await User.findOne({
                where: { username: value },
              });
              if (existing) {
                throw new Error("Username already taken");
              }
            },
          },
        },
      },
      { sequelize }
    );
    

    Migrations

    Creating Migrations

    # Generate migration
    npx sequelize-cli migration:generate --name create-users
    
    # Run migrations
    npx sequelize-cli db:migrate
    
    # Undo last migration
    npx sequelize-cli db:migrate:undo
    
    # Undo all migrations
    npx sequelize-cli db:migrate:undo:all
    

    Migration File Structure

    // migrations/20240101000000-create-users.js
    module.exports = {
      async up(queryInterface, Sequelize) {
        await queryInterface.createTable("users", {
          id: {
            type: Sequelize.INTEGER,
            autoIncrement: true,
            primaryKey: true,
          },
          email: {
            type: Sequelize.STRING(255),
            allowNull: false,
            unique: true,
          },
          name: {
            type: Sequelize.STRING(255),
            allowNull: true,
          },
          is_active: {
            type: Sequelize.BOOLEAN,
            defaultValue: true,
          },
          created_at: {
            type: Sequelize.DATE,
            allowNull: false,
            defaultValue: Sequelize.literal("CURRENT_TIMESTAMP"),
          },
          updated_at: {
            type: Sequelize.DATE,
            allowNull: false,
            defaultValue: Sequelize.literal("CURRENT_TIMESTAMP"),
          },
        });
    
        await queryInterface.addIndex("users", ["email"]);
      },
    
      async down(queryInterface) {
        await queryInterface.dropTable("users");
      },
    };
    

    Best Practices

    Use Eager Loading to Avoid N+1

    // Bad: N+1 queries
    const users = await User.findAll();
    for (const user of users) {
      const posts = await user.getPosts(); // Query per user
    }
    
    // Good: Single query with include
    const users = await User.findAll({
      include: [{ model: Post, as: "posts" }],
    });
    

    Always Use Migrations in Production

    // sequelize config
    {
      development: {
        // ...
      },
      production: {
        // ...
        migrationStorageTableName: "sequelize_migrations",
        seederStorageTableName: "sequelize_seeds",
      }
    }
    

    Use Aliases for Associations

    // Good: Using aliases for clarity
    User.hasMany(Post, { as: "posts", foreignKey: "authorId" });
    
    // Query with alias
    const user = await User.findOne({
      include: [{ model: Post, as: "posts" }],
    });
    

    Validate in Bulk Operations

    // Always validate when using bulkCreate
    await User.bulkCreate(users, { validate: true });
    

    Use Transactions for Data Integrity

    // Wrap related operations in transactions
    await sequelize.transaction(async (t) => {
      // All operations use the same transaction
      const order = await Order.create({ ... }, { transaction: t });
      await OrderItem.bulkCreate(items, { transaction: t });
      await Inventory.decrement("quantity", { ... }, { transaction: t });
    });
    

    Scope Common Queries

    User.addScope("active", {
      where: { isActive: true },
    });
    
    User.addScope("withPosts", {
      include: [{ model: Post, as: "posts" }],
    });
    
    // Use scopes
    const activeUsers = await User.scope("active").findAll();
    const usersWithPosts = await User.scope(["active", "withPosts"]).findAll();
    
    Recommended Servers
    ThinAir Data
    ThinAir Data
    Supabase
    Supabase
    StudioMeyer-Crew
    StudioMeyer-Crew
    Repository
    mindrally/skills
    Files