Why Async Matters More Than Ever
Modern software waits. It waits for network responses, database queries, file reads, user input. How your language handles that waiting determines whether your app is silky smooth or frustratingly laggy.
Dart was designed from the ground up for asynchronous programming. It’s not bolted on like JavaScript’s Promises were — it’s woven into the language’s DNA through `Future`, `Stream`, `async/await`, and `Isolate`. And in 2027, with AI-native apps making concurrent API calls and processing real-time streams, understanding Dart’s async model deeply is non-negotiable.
Let’s go beyond the basics.
Futures and async/await
The `schema.prisma` file uses Prisma Schema Language (PSL) — a clean, human-readable DSL. According to the Prisma Schema Reference, every model maps directly to a MySQL database table.
The Surface Level
// prisma/schema.prisma
datasource db {
provider = "mysql"
url = env("DATABASE_URL")
}
model Post {
id Int @id @default(autoincrement())
title String @db.VarChar(255)
content String? @db.Text
published Boolean @default(false)
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
authorId Int
author User @relation(fields: [authorId], references: [id])
@@map("posts")
}
MySQL Tip
Field Attributes
| Attribute | Purpose | MySQL Example |
|---|---|---|
| @id | Primary key | id Int @id |
| @default() | Default value | @default(autoincrement()) |
| @unique | Unique constraint | email String @unique |
| @updatedAt | Auto-update timestamp | updatedAt DateTime @updatedAt |
| @map() | Map to DB column name | @map("user_name") |
| @db.VarChar(n) | MySQL VARCHAR type | name String @db.VarChar(100) |
| @db.Text | MySQL TEXT type | content String? @db.Text |
| @db.TinyInt(1) | MySQL boolean/tinyint | active Boolean @db.TinyInt(1) |
Block Attributes
model User {
id Int @id @default(autoincrement())
email String @db.VarChar(191)
username String @db.VarChar(100)
role Role @default(USER)
@@unique([email, username]) // Composite unique constraint
@@index([email]) // Speed up email queries (MySQL index)
@@index([role, createdAt(sort: Desc)]) // Composite index with sort
@@map("users") // Maps to "users" table in MySQL
}
enum Role {
USER
ADMIN
MODERATOR
}
MySQL Note
Pro Tip
`@@index` is crucial for performance. Add indexes on any field used in `WHERE` clauses or `ORDER BY`. (prisma.io/docs/concepts/components/prisma-schema/indexes)
Relations
One-to-Many (Most Common)
model User {
id Int @id @default(autoincrement())
email String @unique @db.VarChar(191)
posts Post[]
@@map("users")
}
model Post {
id Int @id @default(autoincrement())
title String @db.VarChar(255)
authorId Int
author User @relation(fields: [authorId], references: [id],
onDelete: Cascade)
@@index([authorId]) // ← Always index foreign keys in MySQL!
@@map("posts")
}
MySQL Best Practice
One-to-One
model User {
id Int @id @default(autoincrement())
profile Profile?
@@map("users")
}
model Profile {
id Int @id @default(autoincrement())
bio String @db.Text
userId Int @unique
user User @relation(fields: [userId], references: [id],
onDelete: Cascade)
@@map("profiles")
}
Many-to-Many (Implicit)
model Post {
id Int @id @default(autoincrement())
tags Tag[]
@@map("posts")
}
model Tag {
id Int @id @default(autoincrement())
name String @unique @db.VarChar(100)
posts Post[]
@@map("tags")
}
Tip
Prisma Migrate vs `db push`
prisma db push |
prisma migrate dev |
|
|---|---|---|
| Use For | Prototyping / local dev | Production / team projects |
| Migration Files | Not created | Created & versioned |
| Data Loss Risk | May reset DB | Safe, reviewable SQL |
| CI/CD Ready | No | Yes |
| MySQL Support | Full | Full |
// prisma/schema.prisma
generator client {
provider = "prisma-client-js"
output = "../src/generated/prisma"
}
datasource db {
provider = "mysql"
}
model User {
id Int @id @default(autoincrement())
email String @unique
name String?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
post Post[]
@@map("users")
}
model Post {
id Int @id @default(autoincrement())
title String @db.VarChar(255)
content String? @db.Text
published Boolean @default(false)
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
authorId Int
author User @relation(fields: [authorId], references: [id])
@@map("posts")
}
// migration
// npx prisma migrate dev --name init
This creates `prisma/migrations/[timestamp]_init/migration.sql` — review it:
-- CreateTable
CREATE TABLE `users` (
`id` INTEGER NOT NULL AUTO_INCREMENT,
`email` VARCHAR(191) NOT NULL,
`name` VARCHAR(191) NULL,
`createdAt` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
`updatedAt` DATETIME(3) NOT NULL,
UNIQUE INDEX `users_email_key`(`email`),
PRIMARY KEY (`id`)
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
Seeding the Database
// prisma/seed.ts
import { PrismaClient } from '@prisma/client';
const prisma = new PrismaClient();
async function main() {
// Upsert to avoid duplicate errors on repeated seed runs
const alice = await prisma.user.upsert({
where: { email: '[email protected]' },
update: {},
create: {
email: '[email protected]',
name: 'Alice Johnson',
posts: {
create: [
{ title: 'Hello Prisma!', published: true },
{ title: 'Getting Started with MySQL' },
],
},
},
});
console.log('Seeded:', alice);
}
main()
.catch(console.error)
.finally(() => prisma.$disconnect());
"scripts": {
"seed": "ts-node --project tsconfig.prisma.json prisma/seed.ts"
}
npm run seed
Explore project snapshots or discuss custom web solutions.
Prisma Studio
npx prisma studio
# Opens at http://localhost:5555
# Port might be different. Use port based on your output
Give me six hours to chop down a tree and I will spend the first four sharpening the axe.
Frequently Asked Questions
Prisma Migrate only applies additive changes automatically. If a migration would cause data loss (e.g., dropping a column), it warns you and may reset your dev DB. Production uses `prisma migrate deploy` — which never resets data.
Yes! Use `prisma db pull` to introspect your existing MySQL database and generate a `schema.prisma` automatically.
Prisma handles this automatically — all generated tables use `utf8mb4_unicode_ci`. If you're using an existing database, ensure your MySQL server is configured with `character_set_server = utf8mb4`.
Yes. MySQL natively supports ENUM columns. Define: `enum Role { USER ADMIN }` in `schema.prisma` and Prisma maps it to a MySQL `ENUM` column.
Use `@map()` to decouple your Prisma field name from the MySQL column name: `firstName String @map("first_name")`. This lets you rename in your code without touching the DB column — avoiding destructive migrations.
Comments are closed