Skip to main content
Version: Next

Shared packages

Shared packages let you define models and logic that can be safely imported in both server and client code. They contain the models and the protocol file, depend exclusively on the serverpod_serialization package, and have no server-only dependencies. This makes them ideal for data structures that need to be used across your full stackβ€”for example, DTOs, API request/response shapes, or domain models that flow between Flutter and your Serverpod backend with their custom logic.

Models and the protocol file are generated in the shared package's own directory when you run serverpod generate from your server project. The shared package is tied to the project through the shared_packages field in config/generator.yaml.

Setup​

To create a shared package, follow the steps below.

info

Currently, the setup of shared packages is manual. In the future, a command will be added to the Serverpod CLI to allow an easy setup.

Create the shared package​

Create a new Dart package (e.g., my_shared_package) with a minimal pubspec.yaml:

name: my_shared_package
description: Models shared between server and client
version: 1.0.0
publish_to: none

environment:
sdk: ^3.8.0

dependencies:
serverpod_serialization: SERVERPOD_VERSION
info

Use the same Serverpod version as your project. Replace SERVERPOD_VERSION with your Serverpod version (e.g., 3.4.0).

Add model files​

Place your .spy.yaml model files anywhere under the package's lib directory:

my_shared_package/
β”œβ”€β”€ lib/
β”‚ β”œβ”€β”€ my_shared_package.dart
β”‚ └── src/
β”‚ └── models/
β”‚ └── shared_model.spy.yaml
└── pubspec.yaml

Example model:

# lib/src/models/shared_model.spy.yaml
class: SharedModel
fields:
id: UuidValue, default=random
name: String
description: String?
createdAt: DateTime, default=now

Configure the server project​

Add the shared package to your server's config/generator.yaml:

shared_packages:
- ../my_shared_package

Paths are relative to the server project directory. You can list multiple shared packages.

Generate the code​

Run serverpod generate from your server directory.

$ serverpod generate

This generates the Dart classes and protocol in the shared package's lib/src/generated/ directory. After generation, a typical shared package looks like:

my_shared_package/
β”œβ”€β”€ lib/
β”‚ β”œβ”€β”€ my_shared_package.dart
β”‚ └── src/
β”‚ β”œβ”€β”€ generated/
β”‚ β”‚ β”œβ”€β”€ protocol.dart
β”‚ β”‚ └── models/
β”‚ β”‚ └── shared_model.dart
β”‚ └── models/
β”‚ └── shared_model.spy.yaml
└── pubspec.yaml

Then, add the export for the protocol.dart file to the shared package's lib/my_shared_package.dart file to make the classes available in the shared package:

export 'src/generated/protocol.dart';

Add the dependency to the server and client​

Add the shared package to both your server and client (or Flutter app) pubspec.yaml:

# In my_project_server/pubspec.yaml and my_project_client/pubspec.yaml
dependencies:
my_shared_package:
path: ../my_shared_package

Now you are ready to use the shared package in your server and client code!

Using shared models​

The shared package is nothing more than a regular Dart package that contains the models and the protocol file.

Importing the package​

You can import it in your server and client code just like any other package and use the generated classes:

import 'package:my_shared_package/my_shared_package.dart';

// Use in endpoints, Flutter widgets, etc.
final profile = UserProfile(
displayName: 'Alice',
avatarUrl: 'https://example.com/avatar.png',
);

Extending shared models​

You can define a base model in a shared package and extend it on the server to add database persistence. Shared packages cannot define table models, but the server can extend a shared model and add a table property.

In the shared package (lib/src/shared/vehicle.spy.yaml):

class: Vehicle
fields:
id: UuidValue, default=random
brand: String
model: String

On the server (lib/src/models/car.spy.yaml):

class: Car
extends: Vehicle
table: cars
fields:
year: int

The server model extends the shared Vehicle and adds a table for database persistence plus any additional fields. You can also add server-only fields with scope=serverOnly in the server subclass.

Note that the Car class will be available in the server and client packages as normal, unless it is defined as serverOnly.

Referencing shared models in server models​

Shared model names are available in the same namespace when the shared package is configured. Reference them directly in extends, fields, and other model definitions:

class: MyModel
fields:
sharedModel: SharedModel
sharedModels: List<SharedModel>

Restrictions​

Shared models support most Serverpod model features, with these exceptions:

RestrictionReason
No table propertyShared packages are not tied to a database. Use a server model that extends the shared model to add persistence.
No serverOnly on the classModels must be usable on both server and client.
No scope: serverOnly on fieldsAll fields must be serializable for the client.

If you need tables or server-only fields, define them in a server model that extends the shared model.

The shared package can also contain custom serializable classes. Register them in the server's generator.yaml under extraClasses if they need to be used in protocol serialization. See Custom serializable classes for details.