Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion docs/06-concepts/06-database/01-connection.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
---
description: Configure Serverpod's database connection details, passwords, and connect to custom Postgres or SQLite instances.
description: The database connection is defined in Serverpod's configuration and password files, with support for custom Postgres or SQLite instances.
---

# Connection
Expand Down
18 changes: 16 additions & 2 deletions docs/06-concepts/06-database/02-models.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
---
description: Map serializable models to database tables, with support for custom ID types, non-persistent fields, JSONB storage, and column name overrides.
description: Table models map serializable classes to database tables in Serverpod, with custom ID types, non-persistent fields, JSONB storage, and column name overrides.
---

# Models
Expand All @@ -13,7 +13,9 @@ fields:
name: String
```

When the `table` keyword is added to the model, the `serverpod generate` command will generate new methods for [interacting](crud) with the database. The addition of the keyword will also be detected by the `serverpod create-migration` command that will generate the necessary [migrations](migrations) needed to update the database.
When the `table` keyword is added to the model, Serverpod generates new methods for [interacting](crud) with the database. The keyword is also picked up by the `serverpod create-migration` command, which generates the [migrations](migrations) needed to update the database.

For the full list of keywords you can use in a model file, see the [Model reference](../lookups/model-reference).

:::info
When you add a `table` to a serializable class, Serverpod will automatically add an `id` field of type `int?` to the class. You should not define this field yourself. The `id` is set when you interact with an object stored in the database.
Expand Down Expand Up @@ -125,6 +127,16 @@ When enabled, all serializable fields across all models default to `jsonb` unles

If you change the `serializationDataType` between `json` and `jsonb` at any level, the migration system will convert existing columns automatically with no data loss.

## Choosing an ID strategy

Serverpod supports two id types: `int` (the default) and `UuidValue`. The right choice depends on how the id is generated and where it is exposed.

An `int` id defaults to `serial`, which means the database assigns an auto-incrementing integer when the row is inserted. Serial ids are compact and sequential, which keeps indexes efficient and makes them a good fit for internal references. The trade-offs are that the id only exists after the row is saved, and the values are guessable and enumerable, so a sequential id in a public URL can leak how many records you have or let someone probe for others.

A `UuidValue` id is a 128-bit random value. It is not enumerable, and it can be generated before the row is inserted, which suits ids that appear in public URLs, are created offline on the client, or are merged from several sources. UUIDs are larger than integers and random rather than sequential, so index locality is slightly worse than with serial ids.

As a rule of thumb, use the default `int` serial id for internal tables, and reach for `UuidValue` when the id is public-facing, needs to exist before the row is stored, or is created across more than one system. Because a UUID can be generated on the client, never treat a client-supplied id as proof that the caller owns a record; always check that the authenticated user is allowed to use it.

## Change ID type

Changing the type of the `id` field allows you to customize the identifier type for your database tables. This is done by declaring the `id` field on table models with one of the supported types. If the field is omitted, the id field will still be created with type `int` by default.
Expand Down Expand Up @@ -167,6 +179,8 @@ fields:

When using `defaultModel=random`, the UUID will be generated when the object is created. Since an id is always assigned the `id` field can be non-nullable.

To have the server assign the id instead of the client, use `defaultPersist=random` without `defaultModel`, so the value is set on insert rather than on the client.

## Column name override

By default, the column name in the database is the same as the name of the field in the model. However, you can override this to use a different name by using the `column` keyword. For example, if you have a model property named `userName` you might want to store it in the database as `user_name`.
Expand Down
2 changes: 1 addition & 1 deletion docs/06-concepts/06-database/03-relations/01-one-to-one.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
---
description: Define one-to-one relationships between database tables using Serverpod's relation keyword, with support for object fields, ID fields, and bidirectional relations.
description: A one-to-one relationship links two tables through Serverpod's relation keyword, with object fields, ID fields, and bidirectional access.
---

# One-to-one
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
---
description: Define one-to-many relationships between database tables using Serverpod's relation keyword, with implicit and explicit definition options.
description: A one-to-many relationship links a parent row to many child rows through Serverpod's relation keyword, with implicit and explicit options.
---

# One-to-many
Expand Down
38 changes: 36 additions & 2 deletions docs/06-concepts/06-database/03-relations/03-many-to-many.md
Original file line number Diff line number Diff line change
@@ -1,12 +1,18 @@
---
description: Define many-to-many relationships between database tables using a junction model that holds foreign keys to both sides of the relation.
description: A many-to-many relationship connects multiple records on each side through a junction model that holds foreign keys to both tables.
---

# Many-to-many

Many-to-many (n:m) relationships describes a scenario where multiple records from a table can relate to multiple records in another table. An example of this would be the relationship between students and courses, where a single student can enroll in multiple courses, and a single course can have multiple students.

The Serverpod framework supports these complex relationships by explicitly creating a separate model, often called a junction or bridge table, that records the relation.
The Serverpod framework supports these relationships by explicitly creating a separate model, often called a junction or bridge table, that records the relation.

## When to use a junction table

Reach for a many-to-many relation when records on both sides can each relate to many records on the other, like students and courses. If a record on one side belongs to only one record on the other, a [one-to-many](one-to-many) relation is simpler.

A junction model also gives you a place to store data about the relationship itself. If the link between two records needs a date, a grade, or a status, those fields live on the junction model. A relationship that carries its own data always needs an explicit junction table, even when a plainer relation might otherwise do.

## Overview

Expand Down Expand Up @@ -60,3 +66,31 @@ indexes:
```

The unique index on the combination of `studentId` and `courseId` ensures that a student can only be enrolled in a particular course once. If omitted a student would be allowed to be enrolled in the same course multiple times.

## Managing junction records

To link a student to a course, create an `Enrollment` row with both foreign keys set and insert it:

```dart
var enrollment = Enrollment(
studentId: student.id!,
courseId: course.id!,
);
await Enrollment.db.insertRow(session, enrollment);
```

The `studentId` and `courseId` fields are the foreign keys Serverpod generated from the two relations. To remove the link, delete the junction row:

```dart
await Enrollment.db.deleteRow(session, enrollment);
```

Because `Student` and `Course` each hold a one-to-many relation to `Enrollment`, the generated `attach` and `detach` methods also operate on those relations. See [relation queries](../relation-queries#update) for the attach and detach API.

## Common errors

A few mistakes come up often when setting up a junction table:

- **Referencing the generated foreign-key fields.** Defining `student: Student?, relation(...)` generates an implicit `studentId` column on the junction table. Use these generated `<field>Id` names in indexes and filters, as the unique index above does. There is no separate field for you to declare.
- **Relation names must match on both sides.** The `name` argument pairs the two halves of a relation, so `course_enrollments` on `Course.enrollments` has to match `course_enrollments` on `Enrollment.course`. A mismatch is reported as a missing named relation when you run code generation.
- **Keep the relation fields persisted.** The relation fields on the junction are database columns. Marking one `!persist` drops the column, so the foreign key it backs can no longer be stored or queried.
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
---
description: Define self-referential relationships where a table has a foreign key pointing to its own primary key, supporting one-to-one, one-to-many, and many-to-many patterns.
description: A self-referential relationship points a table's foreign key back to its own primary key, supporting one-to-one, one-to-many, and many-to-many patterns.
---

# Self-relations
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
---
description: Control how updates and deletes propagate across related tables using the onUpdate and onDelete referential action properties.
description: Referential actions control how updates and deletes propagate across related tables through the onUpdate and onDelete properties.
---

# Referential actions
Expand Down
2 changes: 1 addition & 1 deletion docs/06-concepts/06-database/03-relations/06-modules.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
---
description: Create relations between your own database tables and tables from Serverpod modules using a bridge table approach.
description: Module relations connect your own database tables to tables from Serverpod modules through a bridge table.
---

# Relations with modules
Expand Down
2 changes: 1 addition & 1 deletion docs/06-concepts/06-database/04-indexing.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
---
description: Add indexes to Serverpod database tables to improve query performance, including unique, GIN, HNSW, and IVFFLAT vector indexes.
description: Indexes on Serverpod database tables improve query performance, including unique, GIN, HNSW, and IVFFLAT vector indexes.
---

# Indexing
Expand Down
2 changes: 1 addition & 1 deletion docs/06-concepts/06-database/05-crud.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
---
description: Create, read, update, and delete database rows in Serverpod using the generated static db methods on your model classes.
description: The generated db methods on each model class create, read, update, and delete database rows in Serverpod.
---

# CRUD
Expand Down
2 changes: 1 addition & 1 deletion docs/06-concepts/06-database/06-filter.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
---
description: Build type-safe database filter expressions in Serverpod using column operations, logical operators, and relation filters.
description: Database filter expressions in Serverpod are type-safe, built from column operations, logical operators, and relation filters.
---

# Filter
Expand Down
4 changes: 2 additions & 2 deletions docs/06-concepts/06-database/07-relation-queries.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
---
description: Query, filter, sort, and paginate relational data in Serverpod using include, includeList, attach, and detach methods.
description: Relation queries in Serverpod fetch, filter, sort, and paginate related data through include, includeList, attach, and detach methods.
---

# Relation queries (Joins)
Expand Down Expand Up @@ -174,7 +174,7 @@ var user = await Company.db.findById(

The example above retrieves the next 10 employees starting from the 11th record:

Using these methods in conjunction provides a powerful way to query, filter, and sort relational data efficiently.
Combined, these methods let you query, filter, and sort relational data efficiently.

## Update

Expand Down
2 changes: 1 addition & 1 deletion docs/06-concepts/06-database/08-sort.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
---
description: Sort database query results by one or more columns in Serverpod using orderBy and orderByList, with support for relational fields and aggregated counts.
description: Serverpod sorts query results by one or more columns with orderBy and orderByList, including relational fields and aggregated counts.
---

# Sort
Expand Down
2 changes: 1 addition & 1 deletion docs/06-concepts/06-database/08-transactions.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
---
description: Group database operations into atomic transactions in Serverpod, with support for isolation levels, savepoints, and rollback.
description: Transactions group database operations into an atomic unit in Serverpod, with isolation levels, savepoints, and rollback.
---

# Transactions
Expand Down
2 changes: 1 addition & 1 deletion docs/06-concepts/06-database/09-pagination.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
---
description: Paginate database query results in Serverpod using limit and offset, or implement cursor-based pagination for frequently updated datasets.
description: Serverpod paginates query results with limit and offset, or cursor-based pagination for frequently updated datasets.
---

# Pagination
Expand Down
2 changes: 1 addition & 1 deletion docs/06-concepts/06-database/10-raw-access.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
---
description: Execute raw SQL queries directly against the database using Serverpod's unsafe query methods with support for named and positional parameter binding.
description: Serverpod's unsafe query methods run raw SQL directly against the database, with named and positional parameter binding.
---

# Raw access
Expand Down
29 changes: 23 additions & 6 deletions docs/06-concepts/06-database/11-migrations.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
---
description: Create and apply database migrations in Serverpod to keep your schema in sync as your models evolve, including repair migrations for out-of-sync databases.
description: Database migrations keep your Serverpod schema in sync as your models evolve, with repair migrations to recover a database that has drifted out of sync.
---

# Migrations

Serverpod comes bundled with a simple-to-use but powerful migration system that helps you keep your database schema up to date as your project evolves. Database migrations provide a structured way of upgrading your database while maintaining existing data.
Serverpod comes with a migration system that helps you keep your database schema up to date as your project evolves. Database migrations provide a structured way of upgrading your database while maintaining existing data.

A migration is a set of database operations (e.g. creating a table, adding a column, etc.) required to update the database schema to match the requirements of the project. Each migration handles both initializing a new database and rolling an existing one forward from a previous state.

Expand Down Expand Up @@ -69,11 +69,18 @@ This would create a migration named `<timestamp>-v1-0-0`:
│ └── 20231205080937028-v1-0-0
```

### Add data in a migration
### Writing custom SQL

Since the migrations are written in SQL, it is possible to add data to the database in a migration. This can be useful if you want to add initial data to the database.
Migrations are plain SQL, so you can edit a generated `migration.sql` to do work the generator does not produce on its own, such as seeding reference data, backfilling a new column, or transforming existing data alongside a schema change.

The developer is responsible for ensuring that any added SQL statements are compatible with the database schema and rolling forward from the previous migrations.
Open the `migration.sql` file in the migration's directory and add your statements. Serverpod applies the file as-is when it rolls the database forward.

Custom SQL is worth reaching for when:

- Initial or reference data needs to be in place as soon as the schema exists.
- A schema change requires moving or transforming existing data, for example splitting one column into two.

You own the correctness of anything you add. Make sure it matches the schema at that point in the migration history and rolls forward cleanly from the previous migration. Serverpod does not validate hand-written SQL. Once a migration has been applied, treat it as immutable and create a new migration for further changes instead of editing it.

### Migrations directory structure

Expand All @@ -100,7 +107,7 @@ For each migration, five files are created:

### During development

`serverpod start` applies your migrations for you. With the `serverpod start` terminal focused:
The `serverpod start` command applies your migrations for you. With its terminal focused:

- Pending migrations are applied automatically on the first boot.
- Press **A** to apply new migrations as you create them.
Expand All @@ -123,6 +130,10 @@ This is useful if migrations are applied as part of an automated process.

If migrations are applied at the same time as repair migration, the repair migration is applied first.

### On Serverpod Cloud

Serverpod Cloud applies migrations for you. Every deploy starts the server with `--apply-migrations`, so any pending migrations run before the server serves requests. If a migration fails, the deploy fails; fix the migration and redeploy. See [Cloud database](/cloud/concepts/database#migrations-run-on-every-deploy) for the full flow.

## Creating a repair migration

If the database has been manually modified the database schema may be out of sync with the migration system. In this case, a repair migration can be created to bring the database schema up to date with the migration system.
Expand Down Expand Up @@ -235,3 +246,9 @@ Then apply the repair migration, any repair migration will only be applied once:
```bash
$ dart run bin/main.dart --apply-repair-migration
```

## Troubleshooting

**Check the flag name when migrations do not apply.** The flag is `--apply-migrations`, plural. Passing the singular `--apply-migration` fails to parse, so Serverpod logs `Failed to parse command line arguments. Using default values.` and falls back to defaults. Migrations are not applied, and any other flags on the same command are dropped as well. If migrations are not running, check the flag spelling first.

**Deleting a migration does not undo it.** Removing a migration directory does not roll the schema back. To undo a migration, create a repair migration targeting the version you want to return to and apply it, as described in [Rolling back migrations](#rolling-back-migrations). Only the schema is reverted; data is not.
2 changes: 1 addition & 1 deletion docs/06-concepts/06-database/12-runtime-parameters.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
---
description: Fine-tune PostgreSQL query behavior per transaction or globally using Serverpod's runtime parameters, particularly for vector similarity search optimization.
description: Runtime parameters tune PostgreSQL query behavior per transaction or globally in Serverpod, notably for vector similarity search.
---

# Runtime parameters
Expand Down
2 changes: 1 addition & 1 deletion docs/06-concepts/06-database/13-row-locking.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
---
description: Lock specific database rows within a transaction in Serverpod to safely handle concurrent updates and prevent conflicting writes.
description: Row locking holds specific database rows within a transaction in Serverpod, so concurrent updates do not conflict.
---

# Row locking
Expand Down
2 changes: 1 addition & 1 deletion docs/06-concepts/06-database/14-client-side-database.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
---
description: Use a SQLite database on the Flutter client with the same ORM interface as the server, including CRUD, relations, and transactions.
description: The client-side database runs SQLite on the Flutter client with the same ORM interface as the server, including CRUD, relations, and transactions.
---

# Client-side database
Expand Down
2 changes: 1 addition & 1 deletion docs/06-concepts/06-database/15-exceptions.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
---
description: Serverpod wraps database failures in typed exceptions. Learn when each database exception is thrown and how to handle them.
description: Serverpod wraps database failures in typed exceptions that signal when a query fails and how your code should handle it.
---

# Database exceptions
Expand Down
Loading