Select ORMs to compare
Pick one or more ORMs from the bar above
Connect to Database
SQL
-- via connection string
psql "postgresql://user:password@localhost:5432/mydb"
-- via parameters
psql -h localhost -p 5432 -U user -d mydb
Django ORM
import os
DATABASES = {
"default": {
"ENGINE": "django.db.backends.postgresql",
"NAME": os.environ.get("DB_NAME"),
"USER": os.environ.get("DB_USER"),
"PASSWORD": os.environ.get("DB_PASSWORD"),
"HOST": os.environ.get("DB_HOST", "localhost"),
"PORT": os.environ.get("DB_PORT", "5432"),
}
}
SQLAlchemy
import os
from sqlalchemy import create_engine
from sqlalchemy.orm import Session
engine = create_engine(os.environ["DATABASE_URL"])
SQLModel
import os
from sqlmodel import Session, create_engine
engine = create_engine(os.environ["DATABASE_URL"])
Tortoise ORM
from tortoise import Tortoise
await Tortoise.init(
db_url="postgres://user:pass@localhost:5432/mydb",
modules={"models": ["app.models"]},
)
Peewee
import os
from peewee import PostgresqlDatabase
db = PostgresqlDatabase(
os.environ.get("DB_NAME"),
user=os.environ.get("DB_USER"),
password=os.environ.get("DB_PASSWORD"),
host=os.environ.get("DB_HOST", "localhost"),
port=int(os.environ.get("DB_PORT", 5432)),
)
Prisma
import { PrismaClient } from "@prisma/client";
const prisma = new PrismaClient();
Drizzle
import { drizzle } from "drizzle-orm/node-postgres";
const db = drizzle(process.env.DATABASE_URL!);
Kysely
import { Kysely, PostgresDialect } from 'kysely'
import { Pool } from 'pg'
interface DB {
users: {
id: number
name: string
email: string
created_at: Date
}
}
const db = new Kysely<DB>({
dialect: new PostgresDialect({
pool: new Pool({
connectionString: process.env.DATABASE_URL,
}),
}),
})
TypeORM
import { DataSource } from "typeorm";
import { User } from "./entity";
const AppDataSource = new DataSource({
type: "postgres",
url: process.env.DATABASE_URL,
entities: [User],
synchronize: true,
});
await AppDataSource.initialize();
MikroORM
import { MikroORM } from "@mikro-orm/postgresql";
import { User } from "./entity";
const orm = await MikroORM.init({
dbName: process.env.DB_NAME,
user: process.env.DB_USER,
password: process.env.DB_PASSWORD,
host: process.env.DB_HOST ?? "localhost",
port: Number(process.env.DB_PORT ?? 5432),
entities: [User],
});
Sequelize
import { Sequelize } from "sequelize";
const sequelize = new Sequelize(process.env.DATABASE_URL!, {
dialect: "postgres",
logging: false,
});
await sequelize.authenticate();Define a Model
SQL
CREATE TABLE users (
id SERIAL PRIMARY KEY,
name VARCHAR(255) NOT NULL,
email VARCHAR(255) NOT NULL UNIQUE,
created_at TIMESTAMP NOT NULL DEFAULT now()
);
Django ORM
from django.db import models
class User(models.Model):
name = models.CharField(max_length=255)
email = models.EmailField(unique=True)
created_at = models.DateTimeField(auto_now_add=True)
SQLAlchemy
from datetime import datetime
from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column
from sqlalchemy import String, func
class Base(DeclarativeBase):
pass
class User(Base):
__tablename__ = "users"
id: Mapped[int] = mapped_column(primary_key=True)
name: Mapped[str] = mapped_column(String(255))
email: Mapped[str] = mapped_column(String(255), unique=True)
created_at: Mapped[datetime] = mapped_column(server_default=func.now())
SQLModel
from datetime import datetime
from sqlmodel import SQLModel, Field
class User(SQLModel, table=True):
__tablename__ = "users"
id: int | None = Field(default=None, primary_key=True)
name: str = Field(max_length=255)
email: str = Field(unique=True, max_length=255)
created_at: datetime = Field(default_factory=datetime.utcnow)
Tortoise ORM
from tortoise.models import Model
from tortoise import fields
class User(Model):
name = fields.CharField(max_length=255)
email = fields.CharField(max_length=255, unique=True)
created_at = fields.DatetimeField(auto_now_add=True)
Peewee
from datetime import datetime
from peewee import CharField, DateTimeField, Model
class User(Model):
name = CharField(max_length=255)
email = CharField(max_length=255, unique=True)
created_at = DateTimeField(default=datetime.utcnow)
class Meta:
table_name = "users"
Prisma
model User {
id Int @id @default(autoincrement())
name String
email String @unique
createdAt DateTime @default(now())
}
Drizzle
import { pgTable, serial, text, timestamp } from "drizzle-orm/pg-core";
export const users = pgTable("users", {
id: serial("id").primaryKey(),
name: text("name").notNull(),
email: text("email").notNull().unique(),
createdAt: timestamp("created_at").defaultNow().notNull(),
});
Kysely
import { Generated } from 'kysely'
export interface UserTable {
id: Generated<number>
name: string
email: string
created_at: Date
}
export interface DB {
users: UserTable
}
TypeORM
import { Entity, PrimaryGeneratedColumn, Column, CreateDateColumn } from "typeorm";
@Entity()
export class User {
@PrimaryGeneratedColumn()
id: number;
@Column()
name: string;
@Column({ unique: true })
email: string;
@CreateDateColumn()
createdAt: Date;
}
MikroORM
import { Entity, PrimaryKey, Property } from "@mikro-orm/core";
@Entity({ tableName: "users" })
export class User {
@PrimaryKey()
id!: number;
@Property({ length: 255 })
name!: string;
@Property({ length: 255, unique: true })
email!: string;
@Property({ fieldName: "created_at", onCreate: () => new Date() })
createdAt = new Date();
}
Sequelize
import {
CreationOptional,
DataTypes,
InferAttributes,
InferCreationAttributes,
Model,
Sequelize,
} from "sequelize";
const sequelize = new Sequelize(process.env.DATABASE_URL!, {
dialect: "postgres",
});
export class User extends Model<
InferAttributes<User>,
InferCreationAttributes<User>
> {
declare id: CreationOptional<number>;
declare name: string;
declare email: string;
declare createdAt: CreationOptional<Date>;
}
User.init(
{
id: {
type: DataTypes.INTEGER,
autoIncrement: true,
primaryKey: true,
},
name: {
type: DataTypes.STRING(255),
allowNull: false,
},
email: {
type: DataTypes.STRING(255),
allowNull: false,
unique: true,
},
createdAt: {
type: DataTypes.DATE,
allowNull: false,
defaultValue: DataTypes.NOW,
field: "created_at",
},
},
{
sequelize,
tableName: "users",
timestamps: false,
},
);Define Field Types
SQL
CREATE TABLE products (
id SERIAL PRIMARY KEY,
name VARCHAR(255) NOT NULL,
description TEXT NOT NULL,
price DOUBLE PRECISION NOT NULL,
quantity INTEGER NOT NULL,
in_stock BOOLEAN NOT NULL,
release_date TIMESTAMP NOT NULL,
tags JSONB NOT NULL
);
Django ORM
from django.db import models
class Product(models.Model):
name = models.CharField(max_length=255)
description = models.TextField()
price = models.FloatField()
quantity = models.IntegerField()
in_stock = models.BooleanField()
release_date = models.DateTimeField()
tags = models.JSONField()
SQLAlchemy
from datetime import datetime
from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column
from sqlalchemy import String, Text, JSON
class Base(DeclarativeBase):
pass
class Product(Base):
__tablename__ = "products"
id: Mapped[int] = mapped_column(primary_key=True)
name: Mapped[str] = mapped_column(String(255))
description: Mapped[str] = mapped_column(Text)
price: Mapped[float] = mapped_column()
quantity: Mapped[int] = mapped_column()
in_stock: Mapped[bool] = mapped_column()
release_date: Mapped[datetime] = mapped_column()
tags: Mapped[dict] = mapped_column(JSON)
SQLModel
from datetime import datetime
from sqlmodel import SQLModel, Field
from sqlalchemy import Column, JSON, Text
class Product(SQLModel, table=True):
__tablename__ = "products"
id: int | None = Field(default=None, primary_key=True)
name: str = Field(max_length=255)
description: str = Field(sa_column=Column(Text))
price: float
quantity: int
in_stock: bool
release_date: datetime
tags: dict = Field(default_factory=dict, sa_column=Column(JSON))
Tortoise ORM
from tortoise.models import Model
from tortoise import fields
class Product(Model):
name = fields.CharField(max_length=255)
description = fields.TextField()
price = fields.FloatField()
quantity = fields.IntField()
in_stock = fields.BooleanField()
release_date = fields.DatetimeField()
tags = fields.JSONField()
Peewee
from datetime import datetime
from peewee import (
BooleanField,
CharField,
DateTimeField,
FloatField,
IntegerField,
Model,
TextField,
)
from playhouse.postgres_ext import BinaryJSONField
class Product(Model):
name = CharField(max_length=255)
description = TextField()
price = FloatField()
quantity = IntegerField()
in_stock = BooleanField()
release_date = DateTimeField()
tags = BinaryJSONField(default=dict)
class Meta:
table_name = "products"
Prisma
model Product {
id Int @id @default(autoincrement())
name String
description String @db.Text
price Float
quantity Int
inStock Boolean
releaseDate DateTime
tags Json
}
Drizzle
import {
pgTable, serial, text, integer,
doublePrecision, boolean, timestamp, jsonb,
} from "drizzle-orm/pg-core";
export const products = pgTable("products", {
id: serial("id").primaryKey(),
name: text("name").notNull(),
description: text("description").notNull(),
price: doublePrecision("price").notNull(),
quantity: integer("quantity").notNull(),
inStock: boolean("in_stock").notNull(),
releaseDate: timestamp("release_date").notNull(),
tags: jsonb("tags"),
});
Kysely
import { Generated } from 'kysely'
export interface ProductTable {
id: Generated<number>
name: string
description: string
price: number
quantity: number
in_stock: boolean
release_date: Date
tags: Record<string, unknown>
}
export interface DB {
products: ProductTable
}
TypeORM
import { Entity, PrimaryGeneratedColumn, Column } from "typeorm";
@Entity()
export class Product {
@PrimaryGeneratedColumn()
id: number;
@Column()
name: string;
@Column("text")
description: string;
@Column("float")
price: number;
@Column("int")
quantity: number;
@Column()
inStock: boolean;
@Column("timestamp")
releaseDate: Date;
@Column("jsonb")
tags: any;
}
MikroORM
import { Entity, PrimaryKey, Property } from "@mikro-orm/core";
@Entity({ tableName: "products" })
export class Product {
@PrimaryKey()
id!: number;
@Property({ length: 255 })
name!: string;
@Property({ type: "text" })
description!: string;
@Property({ type: "float" })
price!: number;
@Property({ type: "int" })
quantity!: number;
@Property({ fieldName: "in_stock" })
inStock!: boolean;
@Property({ fieldName: "release_date" })
releaseDate!: Date;
@Property({ type: "json" })
tags!: Record<string, unknown>;
}
Sequelize
import {
CreationOptional,
DataTypes,
InferAttributes,
InferCreationAttributes,
Model,
Sequelize,
} from "sequelize";
const sequelize = new Sequelize(process.env.DATABASE_URL!, {
dialect: "postgres",
});
export class Product extends Model<
InferAttributes<Product>,
InferCreationAttributes<Product>
> {
declare id: CreationOptional<number>;
declare name: string;
declare description: string;
declare price: number;
declare quantity: number;
declare inStock: boolean;
declare releaseDate: Date;
declare tags: Record<string, unknown>;
}
Product.init(
{
id: {
type: DataTypes.INTEGER,
autoIncrement: true,
primaryKey: true,
},
name: { type: DataTypes.STRING(255), allowNull: false },
description: { type: DataTypes.TEXT, allowNull: false },
price: { type: DataTypes.FLOAT, allowNull: false },
quantity: { type: DataTypes.INTEGER, allowNull: false },
inStock: { type: DataTypes.BOOLEAN, allowNull: false, field: "in_stock" },
releaseDate: { type: DataTypes.DATE, allowNull: false, field: "release_date" },
tags: { type: DataTypes.JSONB, allowNull: false, defaultValue: {} },
},
{
sequelize,
tableName: "products",
timestamps: false,
},
);Nullable & Default Values
SQL
CREATE TABLE posts (
id SERIAL PRIMARY KEY,
title VARCHAR(255) NOT NULL,
content TEXT,
views INTEGER NOT NULL DEFAULT 0,
is_published BOOLEAN NOT NULL DEFAULT false,
published_at TIMESTAMP,
created_at TIMESTAMP NOT NULL DEFAULT now()
);
Django ORM
from django.db import models
class Post(models.Model):
title = models.CharField(max_length=255)
content = models.TextField(null=True, blank=True)
views = models.IntegerField(default=0)
is_published = models.BooleanField(default=False)
published_at = models.DateTimeField(null=True, blank=True)
created_at = models.DateTimeField(auto_now_add=True)
SQLAlchemy
from datetime import datetime
from typing import Optional
from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column
from sqlalchemy import String, Text, func
class Base(DeclarativeBase):
pass
class Post(Base):
__tablename__ = "posts"
id: Mapped[int] = mapped_column(primary_key=True)
title: Mapped[str] = mapped_column(String(255))
content: Mapped[Optional[str]] = mapped_column(Text)
views: Mapped[int] = mapped_column(default=0)
is_published: Mapped[bool] = mapped_column(default=False)
published_at: Mapped[Optional[datetime]] = mapped_column()
created_at: Mapped[datetime] = mapped_column(server_default=func.now())
SQLModel
from datetime import datetime
from sqlmodel import SQLModel, Field
from sqlalchemy import Column, Text
class Post(SQLModel, table=True):
__tablename__ = "posts"
id: int | None = Field(default=None, primary_key=True)
title: str = Field(max_length=255)
content: str | None = Field(default=None, sa_column=Column(Text, nullable=True))
views: int = 0
is_published: bool = False
published_at: datetime | None = None
created_at: datetime = Field(default_factory=datetime.utcnow)
Tortoise ORM
from tortoise.models import Model
from tortoise import fields
class Post(Model):
title = fields.CharField(max_length=255)
content = fields.TextField(null=True)
views = fields.IntField(default=0)
is_published = fields.BooleanField(default=False)
published_at = fields.DatetimeField(null=True)
created_at = fields.DatetimeField(auto_now_add=True)
Peewee
from datetime import datetime
from peewee import BooleanField, CharField, DateTimeField, IntegerField, Model, TextField
class Post(Model):
title = CharField(max_length=255)
content = TextField(null=True)
views = IntegerField(default=0)
is_published = BooleanField(default=False)
published_at = DateTimeField(null=True)
created_at = DateTimeField(default=datetime.utcnow)
class Meta:
table_name = "posts"
Prisma
model Post {
id Int @id @default(autoincrement())
title String
content String?
views Int @default(0)
isPublished Boolean @default(false)
publishedAt DateTime?
createdAt DateTime @default(now())
}
Drizzle
import { pgTable, serial, text, integer, boolean, timestamp } from "drizzle-orm/pg-core";
export const posts = pgTable("posts", {
id: serial("id").primaryKey(),
title: text("title").notNull(),
content: text("content"),
views: integer("views").default(0).notNull(),
isPublished: boolean("is_published").default(false).notNull(),
publishedAt: timestamp("published_at"),
createdAt: timestamp("created_at").defaultNow().notNull(),
});
Kysely
import { Generated } from 'kysely'
export interface PostTable {
id: Generated<number>
title: string
content: string | null
views: number
is_published: boolean
published_at: Date | null
created_at: Date
}
export interface DB {
posts: PostTable
}
TypeORM
import { Entity, PrimaryGeneratedColumn, Column, CreateDateColumn } from "typeorm";
@Entity()
export class Post {
@PrimaryGeneratedColumn()
id: number;
@Column()
title: string;
@Column({ nullable: true })
content: string;
@Column({ default: 0 })
views: number;
@Column({ default: false })
isPublished: boolean;
@Column({ nullable: true })
publishedAt: Date;
@CreateDateColumn()
createdAt: Date;
}
MikroORM
import { Entity, PrimaryKey, Property } from "@mikro-orm/core";
@Entity({ tableName: "posts" })
export class Post {
@PrimaryKey()
id!: number;
@Property({ length: 255 })
title!: string;
@Property({ type: "text", nullable: true })
content?: string;
@Property({ default: 0 })
views = 0;
@Property({ fieldName: "is_published", default: false })
isPublished = false;
@Property({ fieldName: "published_at", nullable: true })
publishedAt?: Date;
@Property({ fieldName: "created_at", onCreate: () => new Date() })
createdAt = new Date();
}
Sequelize
import {
CreationOptional,
DataTypes,
InferAttributes,
InferCreationAttributes,
Model,
Sequelize,
} from "sequelize";
const sequelize = new Sequelize(process.env.DATABASE_URL!, {
dialect: "postgres",
});
export class Post extends Model<
InferAttributes<Post>,
InferCreationAttributes<Post>
> {
declare id: CreationOptional<number>;
declare title: string;
declare content: string | null;
declare views: CreationOptional<number>;
declare isPublished: CreationOptional<boolean>;
declare publishedAt: Date | null;
declare createdAt: CreationOptional<Date>;
}
Post.init(
{
id: {
type: DataTypes.INTEGER,
autoIncrement: true,
primaryKey: true,
},
title: { type: DataTypes.STRING(255), allowNull: false },
content: { type: DataTypes.TEXT, allowNull: true },
views: { type: DataTypes.INTEGER, allowNull: false, defaultValue: 0 },
isPublished: {
type: DataTypes.BOOLEAN,
allowNull: false,
defaultValue: false,
field: "is_published",
},
publishedAt: { type: DataTypes.DATE, allowNull: true, field: "published_at" },
createdAt: {
type: DataTypes.DATE,
allowNull: false,
defaultValue: DataTypes.NOW,
field: "created_at",
},
},
{
sequelize,
tableName: "posts",
timestamps: false,
},
);Create / Sync Schema
SQL
-- No sync tool — you run CREATE TABLE directly
-- or use a migration tool like Flyway / Liquibase
Django ORM
python manage.py makemigrations
python manage.py migrate
SQLAlchemy
import os
from sqlalchemy import create_engine
from models import Base
engine = create_engine(os.environ["DATABASE_URL"])
Base.metadata.create_all(engine)
SQLModel
import os
from sqlmodel import SQLModel, create_engine
engine = create_engine(os.environ["DATABASE_URL"])
SQLModel.metadata.create_all(engine)
Tortoise ORM
from tortoise import Tortoise
await Tortoise.init(
db_url="postgres://user:pass@localhost:5432/mydb",
modules={"models": ["app.models"]},
)
await Tortoise.generate_schemas()
Peewee
# Assumes db and models are imported
db.connect()
db.create_tables([User, Post, Order])
db.close()
Prisma
npx prisma db push
Drizzle
npx drizzle-kit push
Kysely
# Kysely has no schema push command.
# Apply schema via migrations.
$ bun run migrate:up
TypeORM
npx typeorm schema:sync
MikroORM
$ npx mikro-orm schema:update --run
Sequelize
$ npx sequelize-cli db:migrate