Lift is in Preview!
Limitations include missing features, limited performance and stability issues.
Read more

Declarative data modeling & database schema migrations

Lift lets you design a declarative data model for your application and automatically generates safe & resilient database migrations.

Follow Lift on GitHub

Your Databases as Code

Codify your database schema in a universal, human-readable modeling language. Your datamodel becomes the source of truth for your database.

Extend safely with before & after hooks

Hook into a migration with custom scripts to migrate data and call 3rd party APIs. Failures rollback automatically.

Supports MySQL, Postgres & MongoDB

Target multiple databases in one datamodel (schema) and perform migrations across multiple databases in a single run.

Built for CI/CD Workflows

Lift can be used as across your team to organize migrations in a safe and transparent way.

Preview raw database commands

Worried about too much magic? Lift provides the raw database actions before migrating so you’re always in control of your database.

Quickly spin up new databases

When your datamodel files are the source of truth for your databases, it’s easy to create fresh databases for different environments or testing.

Basic

datasource pg {
  provider = "postgres"
  url      = "postgres://localhost:5432"
}

model User {
  id          Int     @id
  email       String  @unique
  name        String?
  role        Role    @default(USER)
  posts       Post[]
}

model Post {
  id          Int       @id
  createdAt   DateTime  @default(now())
  updatedAt   DateTime  @updatedAt
  author      User
  title       String
  published   Boolean   @default(false)
}

enum Role {
  USER
  ADMIN
}

Embeds

datasource pg {
  provider = "postgres"
  url      = "postgres://localhost:5432"
}

model User {
  id        String
  customer  StripeCustomer?
}

embed StripeCustomer {
  id     String
  cards  Source[]
}

enum Card {
  Visa        = 'VISA'
  Mastercard  = 'MASTERCARD'
}

embed Sources {
  type Card
}
datasource pg {
  provider = "postgres"
  url      = "postgres://localhost:5432"
}
    
model User {
  id        String
  customer  embed {
    id     String
    cards  embed {
      type Card
    }[]
  }?
}

enum Card {
  Visa        = 'VISA'
  Mastercard  = 'MASTERCARD'

One to One

datasource pg {
  provider = "postgres"
  url      = "postgres://localhost:5432"
}

// Alphabetical order determines on which side the foreign key is stored. 
// Here, it's on `Customer` because that preceeds `User` alphabetically.
model User {
  id        Int           @id
  customer  Customer?
  name      String
}

model Customer {
  id       Int     @id
  user     User?   // stores a foreign key
  address  String
}
datasource pg {
  provider = "postgres"
  url      = "postgres://localhost:5432"
}
    
// The @relation attribute can be used to specify the side of the foreign key.
// Here, it's explicitly stored on the `User` model.
model User {
  id        Int           @id
  customer  Customer?     @relation(references: [id]) // stores a foreign key
  name      String
}

model Customer {
  id       Int     @id
  user     User?
  address  String
}

One to Many

datasource pg {
  provider = "postgres"
  url      = "postgres://localhost:5432"
}
    
model Writer {
  id      Int     @id
  blogs   Blog[]
}

model Blog {
  id      Int     @id
  author  Writer
}

Many to Many

datasource pg {
  provider = "postgres"
  url      = "postgres://localhost:5432"
}
    
// Many-to-many relation with an implicit relation table called `_BlogtoWriter`
model Blog {
  id       Int       @id
  authors  Writer[]
}

model Writer {
  id      Int     @id
  blogs   Blog[]
}
datasource pg {
  provider = "postgres"
  url      = "postgres://localhost:5432"
}
    
// Explicit many-to-many relation with a relation table
// (Coming soon)
model Blog {
  id       Int       @id
  authors  Writer[]
}

model Writer {
  id      Int     @id
  blogs   Blog[]
}

model BlogsWriters {
  blog      Blog
  author    Writer
  is_owner  Boolean
  @@unique([author, blog])
}

Self-relations

datasource pg {
  provider = "postgres"
  url      = "postgres://localhost:5432"
}
    
model Employee {
  id         Int       @id
  reportsTo  Employee
}

Connecting data sources

// Connect to a PostgreSQL database via an environment variable
datasource pg {
  provider = 'postgresql'
  url      = env('POSTGRES_URL')
}
// Connect to a local MongoDB database
datasource mgo {
  provider = 'mongodb'
  url      = 'http://user1:myPassword@localhost:27017/admin'
}

Native DB types

datasource pg {
  provider = 'postgres'
  url      = 'postgres://localhost:5432/jack?sslmode=false'
}

datasource ms {
  provider = 'mysql'
  url      = 'mysql://localhost:5522/jack'
}

type PGCitext = String @pg.Citext
type PGUUID   = String @pg.UUID

embed Point2D {
  X Int
  Y Int
  @@pg.Point
  @@ms.Point
}

model User {
  id         UUID
  email      Citext
  name       String  @pg.varchar(8)
  location1  Point2D
}

Switching environments

datasource db {
  enabled   = bool(env('SQLITE_URL'))
  provider  = 'sqlite'
  url       = env('SQLITE_URL')
}

datasource db {
  enabled   = bool(env('POSTGRES_URL'))
  provider  = 'postgresql'
  url       = env('POSTGRES_URL')
}

model User {
  id         Int    @id @db.int
  first_name String @unique
}

Basic

datasource pg {
  provider = "postgres"
  url      = "postgres://localhost:5432"
}

model User {
  id          Int     @id
  email       String  @unique
  name        String?
  role        Role    @default(USER)
  posts       Post[]
}

model Post {
  id          Int       @id
  createdAt   DateTime  @default(now())
  updatedAt   DateTime  @updatedAt
  author      User
  title       String
  published   Boolean   @default(false)
}

enum Role {
  USER
  ADMIN
}

Embeds

datasource pg {
  provider = "postgres"
  url      = "postgres://localhost:5432"
}

model User {
  id        String
  customer  StripeCustomer?
}

embed StripeCustomer {
  id     String
  cards  Source[]
}

enum Card {
  Visa        = 'VISA'
  Mastercard  = 'MASTERCARD'
}

embed Sources {
  type Card
}
datasource pg {
  provider = "postgres"
  url      = "postgres://localhost:5432"
}
    
model User {
  id        String
  customer  embed {
    id     String
    cards  embed {
      type Card
    }[]
  }?
}

enum Card {
  Visa        = 'VISA'
  Mastercard  = 'MASTERCARD'

Declarative data modeling

Lift auto-generates database migrations by diffing schema definition. Learn more in the docs.
Defining Models
Relations
Config

Get started with Lift ...

Run $ npm install -g prisma2 to install Lift. You can then start connecting your database by running $ prisma2 init.
How does lift fit into Prisma ecosystem?
$ npm install -g prisma
$ prisma lift

1 model User {
2 id String
3 email String
- name String

+ first_name String
+ last_name String

6 post Post[]
7 }

... or explore an example project

Learn more about how Lift stores your migration history and the main migration workflows by exploring a practical example.

FAQ

Am I locked-in when using Lift? Is it easy to migrate off it?

There's absolutely no lock-in with Lift. To stop using Lift, you can simply delete your Prisma schema file, all existing migration folders on your file system and the migrations table in your database/schema.

How do I see details about how Lift migrates my database schema?

Each migration is represented via its own directory on your file system. The name of each directory contains a timestamp so that the order of all migrations in the project history can be maintained. Each of these migration directories contains detailled information about the respective migration, for example which steps are executed (and in what order) as well as a human-friendly markdown file that summarizes the most important information about the migration, such as the source and the target data model definition of the migration. This information can also be found in the migrations table in your database/schema.

Also, the lift CLI constantly prints the migration statements and more information when you're running its commands.

How can I extend a migration with custom functionality, e.g. running a script?

Every migration can be extended with before/after hooks. You can simply put executable scripts into a migration folder that are named before and/or after (or before{.sh/js} and/or after{.sh/js}) and they will be picked up automatically by Lift when you're runningprisma2 lift up.

Is Lift production-ready? Should I start using it?

Lift is not yet production-ready, it has a number of severe limitations that don't make it suitable for production uses. You can track the progress of the release process on isprisma2ready.com.

While it shouldn't be used for critical applications yet, Photon is definitely in a usable state. You can help us accelerate the release process by using it and sharing your feedback with us.