Serverpod 1.2, “Cyberpunk” — A leap forward for Dart on the backend
Database relations and migrations, supercharged tooling: CLI upgrade, VS Code extension, integration with Dart DevTools, and much more.
The wait is over! Welcome to Serverpod 1.2, codenamed “Cyberpunk”. This release is not just an update, it’s a bold leap in making server-side development with Dart easier, more delightful, and more powerful than ever.
In this release, we added over 60 new features, more than 2000 automated tests, and over 100 fixes.
Our release event is now available on Youtube. Watch it here or continue reading below.
From the start, Serverpod has been about making your server-side story as compelling as your client-side one. We bridge the gap between server and client, creating a seamless, integrated world where your ideas can flow freely. With Serverpod, you write less code but achieve more, empowering you to focus on what truly matters — building incredible applications. We are thrilled to share that Serverpod is now 4,500+ developers strong, reimagining server-side development together.
Curious about what’s new? Keep reading to dive into what the Serverpod community poured their hearts (and code!) into for this latest version.
What’s new in Serverpod 1.2?
Database relations
Serverpod 1.2 makes managing even the most complex relationships (one-to-one, one-to-many, and many-to-many relations) in the database simple, with type-safe Dart code. The models will work seamlessly with the rest of the Serverpod’s ecosystem, including caching, streaming, and serialization.
The new ‘relation’ keyword is used to express an object relationship between two serializable entities stored in the database. This keyword informs the Serverpod code generator that an object relation is desired. Depending on how the type of the relation is defined, the Serverpod code generator automatically generates the ORM (Object-Relational Mapping) methods to manage these relationships.
class: Company
table: company
fields:
name: String
address: Address?, relation
class: Customer
table: customer
fields:
name: String
orders: List<Order>?, relation
A simple class definition is interpreted as a one relation
(e.g. a book having one author) and a list is interpreted as a many relation
(e.g. a book having multiple chapters).
If the same relation should be queryable from both sides, i.e., two objects point towards each other, the relation can be given a name (e.g. a customer having any orders and each order belonging to one customer).
class: Customer
table: customer
fields:
name: String
orders: List<Order>?, relation(name=customer_order)
class: Order
table: order
fields:
name: String
address: Customer?, relation(name=customer_order)
To improve type safety and support these new functionalities, the internal workings of Serverpod’s database methods have undergone a rework. The new methods are now accessed under a static “db” field within the generated models. The older ones are planned for deprecation, but everything is still backward compatible.
Database migrations
The support for handling database migrations is also added in this release. Upon startup, the integrity of the database is checked. Any subsequent additions or modifications to database models trigger the automatic generation of a migration path, including all necessary SQL queries.
Use the create-migration
command to generate migrations that update your database schema based on changes in your project.
These migrations can be applied seamlessly through the server by adding the --apply-migrations
flag. This makes it easy to apply migrations in any environment where a Serverpod server is running. In the example below, the new “maintenance” role is utilized when applying the migration. In this role, the server applies the migration and then gracefully shuts down.
If the database schema ever gets out of sync with the migration system, through manual modifications, or you would like to roll back to an older database schema, repair migrations can be used. This will create a unique migration from your live database schema to an already existing migration.
Now, let’s explore Serverpod’s new query capabilities.
Relational queries have never been so simple in Dart. Serverpod’s fluent API makes it intuitively easy to traverse relations in queries. This enables us to filter on, order by, or include data from related objects in the database.
When working with an entity that has a relation, it becomes easy to filter data based on properties of the related information by directly accessing the fields of the related data while constructing a query. The process of including the related data in the query result is made simple with the introduction of the new “include” parameter in the query method.
var companies = await Company.db.find(
session,
// Find all companies in Sweden
where: (company) => company.address.country.name.equals('Sweden'),
// Include the address
include: Company.include(
address: Address.include(),
),
);
for (var company in companies) {
var address = company.address;
// ...
}
In the above example, we only retrieve companies that are located in Sweden, and with the retrieved data, we include their address information. The address information is then accessible through the address field of the company retrieved.
Now, consider the below example for querying a one-to-many relationship.
Customer.db.find(
session,
// Find all customers with more than ten purchases
where: (customer) => customer.purchases.count > 10,
// Include three highest-grossing purchases
include: Customer.include(
purchases: Purchase.includeList(
limit: 3,
orderBy: (purchase) => purchase.cost,
orderDescending: true,
),
),
)
The query only retrieves customers that have made more than ten purchases, included with the data of their three highest-grossing orders.
The query syntax is powered by an internal SQL query builder, ensuring optimal performance. To learn more on how these can help you build your app, visit our updated documentation.
Supercharged tooling
CLI Commands: Smarter than ever
Serverpod’s CLI now gives you clear, concise feedback, pinpointing issues with laser precision. No more hunting through logs for clues.
The protocol file linter is now more robust, preventing silent failures. For example, attempting to duplicate table names across protocol files triggers an immediate error, providing precise details on the location:
This applies to class names, index names, and more.
VSCode: We have a new extension
Our new VSCode plugin ensures that errors surface exactly where they occur in your code, in real-time as you type (like a helpful code co-pilot).
This feature is built on the language server protocol, extending its benefits beyond VSCode users to any editor with LSP support.
Launch the Serverpod language server from the CLI using the command:
serverpod language-server
Serverpod Insights: Now in Dart DevTools
We’ve teamed up with Google to bring Serverpod Insights to the Dart DevTools’ new plugin system.
Simply fire up DevTools with the --observe
flag, while having the latest Serverpod version installed. You’ll find the dedicated Serverpod tab, granting access to all your favourite Serverpod Insights
features.
In essence, these enhancements not only save time and elevate code quality but also supercharge your overall development workflow.
Serverpod 1.2 is the culmination of a shared journey. It’s not just lines of code or lines of release notes; it’s the sum of every insightful discussion, every helping hand on the discussion board, and every bug report filed.
We want to take a moment to thank the vibrant Serverpod community. Your commitment has played a vital role in shaping Serverpod into what it is today, and we wouldn’t have reached this milestone without each one of you.
Ready to build next-level server-side apps? Learn more about Serverpod at Serverpod.dev or watch the Serverpod 1.2, “Cyberpunk” release video here.