SQL to Sequelize Model Converter

Convert SQL CREATE TABLE statements to Sequelize model definitions for PostgreSQL, MySQL, and SQLite.

Output:

What is SQL to Sequelize Model Converter?

Sequelize is one of the oldest and most established promise-based ORMs for Node.js, supporting PostgreSQL, MySQL, MariaDB, SQLite, and Microsoft SQL Server through a single API. A Sequelize model maps a JavaScript/TypeScript class (or a plain object definition) to a database table, and Sequelize handles building SQL, running migrations, and managing associations between tables. Sequelize gives you two ways to declare a model, and understanding the difference matters when reading converted output. The classic style is sequelize.define("User", { ...attributes }), which returns a model and is concise for JavaScript projects. The modern style — recommended for TypeScript — is class User extends Model { } followed by User.init({ ...attributes }, { sequelize, modelName: "User" }). The class-extension form lets you declare instance properties with TypeScript types (using InferAttributes and InferCreationAttributes) so you get type-checked field access, whereas define() returns a loosely typed model. Both produce the same runtime behaviour; they differ in type safety and where you can attach instance methods. Every attribute in a Sequelize model is described with a DataTypes value — DataTypes.STRING, DataTypes.INTEGER, DataTypes.BOOLEAN, DataTypes.DATE, DataTypes.JSONB, and so on — plus options like allowNull, defaultValue, primaryKey, autoIncrement, and unique. Relationships are NOT declared inside the attributes; instead you call association methods after defining the models: User.hasMany(Post) and Post.belongsTo(User). This converter maps your SQL columns to the correct DataTypes and constraint options, and turns REFERENCES into the references config plus the matching belongsTo/hasMany association so you can wire up your models quickly when migrating an existing SQL database to Sequelize.

How to Use

  1. Select your database dialect (PostgreSQL, MySQL, or SQLite). The dialect affects defaults like how SERIAL vs AUTO_INCREMENT maps to autoIncrement: true and which DataTypes variants are emitted.
  2. Choose output language: TypeScript (class extends Model + init) or JavaScript (sequelize.define). Pick TypeScript if you want typed attributes via InferAttributes.
  3. Paste your SQL CREATE TABLE statements. Each table becomes one model definition.
  4. Click "Generate Sequelize Model" to produce the model code with DataTypes mappings and association hints.
  5. Save each model and import them into your app, then call the generated belongsTo/hasMany associations after all models are defined (associations must run once every model class exists).

Why Use This Tool?

Maps SQL column types to Sequelize DataTypes — VARCHAR(n) → DataTypes.STRING(n), INTEGER → DataTypes.INTEGER, BIGINT → DataTypes.BIGINT, NUMERIC → DataTypes.DECIMAL, JSONB → DataTypes.JSONB, TIMESTAMP → DataTypes.DATE
Translates constraints to model options: NOT NULL → allowNull: false, UNIQUE → unique: true, DEFAULT → defaultValue, PRIMARY KEY → primaryKey: true
Emits autoIncrement: true for SERIAL / AUTO_INCREMENT / IDENTITY primary keys
Turns REFERENCES into a references: { model, key } config and suggests the belongsTo / hasMany association pair
Outputs both classic sequelize.define() (JavaScript) and the typed class + init() form (TypeScript) so it fits either codebase

Tips & Best Practices

  • Define associations separately, after every model is loaded. Sequelize associations like User.hasMany(Post) must run when both model classes already exist. Putting them inside a define() call or before the other model is imported causes "X is not associated to Y" errors at query time.
  • Sequelize adds createdAt and updatedAt automatically unless you set timestamps: false in the model options. If your SQL table already has created_at/updated_at columns, either map them with field: "created_at" and set timestamps: true, or you will get duplicate/conflicting columns.
  • DataTypes.STRING is VARCHAR(255) by default — always pass the length from your SQL (DataTypes.STRING(100)) so a migration does not silently widen or truncate the column. Use DataTypes.TEXT for unbounded text.
  • For booleans on MySQL, Sequelize uses TINYINT(1); on PostgreSQL it uses BOOLEAN. The converter handles this, but be aware reading a MySQL TINYINT(1) back gives true/false, while a raw query gives 0/1.
  • underscored: true in model options auto-converts camelCase attribute names to snake_case column names. This is the cleanest way to keep JS-style userId in code while storing user_id in the database, instead of adding field: "user_id" on every column.

Frequently Asked Questions

What is the complete SQL type to Sequelize DataTypes mapping?

VARCHAR(n)/CHAR(n) → DataTypes.STRING(n), TEXT/TINYTEXT/MEDIUMTEXT/LONGTEXT → DataTypes.TEXT, INTEGER/INT/SMALLINT → DataTypes.INTEGER, BIGINT → DataTypes.BIGINT, TINYINT(1)/BOOLEAN/BOOL → DataTypes.BOOLEAN, FLOAT/REAL → DataTypes.FLOAT, DOUBLE/DOUBLE PRECISION → DataTypes.DOUBLE, DECIMAL/NUMERIC(p,s) → DataTypes.DECIMAL(p,s), DATE/DATETIME → DataTypes.DATEONLY (for DATE) and DataTypes.DATE (for DATETIME/TIMESTAMP), TIMESTAMP/TIMESTAMPTZ → DataTypes.DATE, TIME → DataTypes.TIME, JSON → DataTypes.JSON, JSONB → DataTypes.JSONB (PostgreSQL only), UUID → DataTypes.UUID, BLOB/BYTEA/VARBINARY → DataTypes.BLOB, ENUM(...) → DataTypes.ENUM(...).

What is the difference between sequelize.define() and class extends Model?

sequelize.define("User", {...}) is the classic factory form: short, untyped, and returns a model you use directly. class User extends Model {} with User.init({...}, { sequelize }) is the modern form that supports declaring typed instance properties (declare id: number) using InferAttributes<User> and InferCreationAttributes<User>, giving full TypeScript type checking on field access and on User.create(). Both create equivalent models at runtime — choose class+init for TypeScript projects and define() for quick JavaScript scripts.

How do I set up associations like belongsTo and hasMany?

A SQL foreign key user_id INTEGER REFERENCES users(id) maps to two association calls: Post.belongsTo(User, { foreignKey: "user_id" }) on the child, and User.hasMany(Post, { foreignKey: "user_id" }) on the parent. belongsTo means the FK column lives on this model (Post); hasMany/hasOne means the FK lives on the other model. Use hasOne instead of hasMany when the relationship is one-to-one. These calls also add helper methods like post.getUser() and user.getPosts().

How does Sequelize compare to TypeORM and Prisma?

Sequelize is the most battle-tested and dialect-flexible of the three, with a mature migration CLI, but its TypeScript types were retrofitted and feel less ergonomic than newer tools. TypeORM is decorator-based and integrates with NestJS. Prisma is schema-first with the strongest type safety and a generated client. Choose Sequelize for legacy support, multi-dialect needs, or projects already invested in it; choose Prisma for greenfield TypeScript projects wanting top type safety.

Why are createdAt and updatedAt appearing that I did not define?

Sequelize enables automatic timestamps by default, adding createdAt and updatedAt columns and managing them on create/update. To disable, set timestamps: false in the model options. To map them to existing snake_case columns, keep timestamps: true and set createdAt: "created_at", updatedAt: "updated_at" (or use underscored: true). To add soft deletes, set paranoid: true, which adds a deletedAt column and filters soft-deleted rows automatically.

Is my SQL data sent to a server?

No. All conversion runs entirely in your browser. Your SQL schema never leaves your device.

Real-world Examples

Single table: a products table as a typed Sequelize model

A products table with an auto-increment id, a unique SKU, a decimal price, and a JSONB attributes column. This shows DataTypes mapping, allowNull/unique options, and the class + init TypeScript form with typed attributes.

Input
CREATE TABLE products (
  id SERIAL PRIMARY KEY,
  sku VARCHAR(50) UNIQUE NOT NULL,
  name VARCHAR(200) NOT NULL,
  price DECIMAL(10,2) NOT NULL DEFAULT 0,
  in_stock BOOLEAN NOT NULL DEFAULT true,
  attributes JSONB
);
Output
import { DataTypes, Model, InferAttributes, InferCreationAttributes, CreationOptional } from "sequelize";
import { sequelize } from "./db";

class Product extends Model<InferAttributes<Product>, InferCreationAttributes<Product>> {
  declare id: CreationOptional<number>;
  declare sku: string;
  declare name: string;
  declare price: number;
  declare inStock: boolean;
  declare attributes: object | null;
}

Product.init(
  {
    id: { type: DataTypes.INTEGER, primaryKey: true, autoIncrement: true },
    sku: { type: DataTypes.STRING(50), allowNull: false, unique: true },
    name: { type: DataTypes.STRING(200), allowNull: false },
    price: { type: DataTypes.DECIMAL(10, 2), allowNull: false, defaultValue: 0 },
    inStock: { type: DataTypes.BOOLEAN, allowNull: false, defaultValue: true, field: "in_stock" },
    attributes: { type: DataTypes.JSONB, allowNull: true },
  },
  { sequelize, tableName: "products", timestamps: false }
);

export default Product;

Related tables: comments belonging to posts with associations

A comments table referencing posts. This demonstrates the references config inside the attribute plus the belongsTo / hasMany association pair you must add after both models are defined.

Input
CREATE TABLE comments (
  id SERIAL PRIMARY KEY,
  post_id INTEGER NOT NULL REFERENCES posts(id),
  author VARCHAR(100) NOT NULL,
  body TEXT NOT NULL,
  created_at TIMESTAMP NOT NULL DEFAULT NOW()
);
Output
import { DataTypes, Model } from "sequelize";
import { sequelize } from "./db";
import Post from "./Post";

class Comment extends Model {}

Comment.init(
  {
    id: { type: DataTypes.INTEGER, primaryKey: true, autoIncrement: true },
    postId: {
      type: DataTypes.INTEGER,
      allowNull: false,
      field: "post_id",
      references: { model: "posts", key: "id" },
    },
    author: { type: DataTypes.STRING(100), allowNull: false },
    body: { type: DataTypes.TEXT, allowNull: false },
    createdAt: { type: DataTypes.DATE, allowNull: false, defaultValue: DataTypes.NOW, field: "created_at" },
  },
  { sequelize, tableName: "comments", timestamps: false }
);

// Wire up associations after all models are loaded:
Comment.belongsTo(Post, { foreignKey: "post_id" });
Post.hasMany(Comment, { foreignKey: "post_id" });

export default Comment;

Related Tools