Skip to content

docs: Rework the Build your first app guide for 3.5#557

Open
developerjamiu wants to merge 2 commits into
mainfrom
docs/first-app-3-5-rework
Open

docs: Rework the Build your first app guide for 3.5#557
developerjamiu wants to merge 2 commits into
mainfrom
docs/first-app-3-5-rework

Conversation

@developerjamiu
Copy link
Copy Markdown
Contributor

Reworks the "Build your first app" tutorial (the magic recipe app) for Serverpod 3.5, per #545.

What changed across the four pages:

  • Replaces docker compose + dart bin/main.dart + manual serverpod generate with serverpod start (watch mode, hot reload, embedded Postgres). The app starts once on page 1 and hot reloads through the rest.
  • Matches the actual beta.9 project template (the screens/ layout and pre-wired client) instead of the stale code snippets.
  • Migrations are created and applied from the serverpod start TUI (the M and A keys).
  • Page 4 becomes "Deploy your app", defaulting to Serverpod Cloud, with the old summary folded in as "What you've built".
  • Adds title and description frontmatter, plus "Before you start" and continuation intros, per the tutorial template.

Note: the upstream magic_recipe example repo that feeds the SNIPSTART snippets is stale for beta.9. This PR inlines correct code; the example repo still needs a separate update.

@developerjamiu developerjamiu requested a review from Swiftaxe May 27, 2026 15:38
@developerjamiu developerjamiu added documentation Improvements or additions to documentation enhancement New feature or request labels May 27, 2026
@developerjamiu developerjamiu self-assigned this May 27, 2026
Copy link
Copy Markdown
Collaborator

@Swiftaxe Swiftaxe left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Overall, a massive improvement of this guide! I added some comments to polish some details even further.

- Persistent storage with the database.
- A Flutter app that talks to all of it through the generated client.

We're excited to see what you'll build next. If you need help, ask in our [community on GitHub](https://github.com/serverpod/serverpod/discussions) or join the [Discord community](https://serverpod.dev/discord). To go deeper into any topic, browse the [Concepts](../06-concepts/01-working-with-endpoints/01-working-with-endpoints.md) section.
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Discord is the main channel for community discussions, so rearrange this to front with Discord.

);
}
}
import 'package:magic_recipe_client/magic_recipe_client.dart';
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

While most of this code example is related to the Flutter framework, which needs no explanation, this import is a serverpod concept. We should say something about why we add it.

/// Holds the last result or null if no result exists yet.
class _RecipeScreenState extends State<RecipeScreen> {
/// The recipe currently shown, or null if there's none yet.
Recipe? _recipe;
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is the first time we use a type in Flutter that was generated by Serverpod. It deserves at least a sentence. See the comment above about the import.


:::info
On the server, you can do things you don't want to do in the app, like calling an API secured by a secret key or accessing a database. The server can also do things that are impossible in the app, like sending push notifications or emails.
The server is the right place for work you can't or shouldn't do in the app, such as calling an API secured by a secret key, accessing a database, or sending push notifications and emails. Here, it keeps your Gemini API key off the client.
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sometimes we call the serverpod application and 'app', so let's be specific about what type of app here:

Suggested change
The server is the right place for work you can't or shouldn't do in the app, such as calling an API secured by a secret key, accessing a database, or sending push notifications and emails. Here, it keeps your Gemini API key off the client.
The server is the right place for work you can't or shouldn't do in the Flutter app, such as calling an API secured by a secret key, accessing a database, or sending push notifications and emails. Here, it keeps your Gemini API key off the client.

## Before you start

- [Serverpod installed](../04-get-started/01-installation.md). Run `serverpod version` to confirm it works.
- A free Gemini API key. Create one on [Google AI Studio](https://aistudio.google.com/app/apikey); it's free, but you need to sign in with a Google account.
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We leave the user without guidance on how to create an API key. Consider adding a screenshot and instructions, or just linking to a high-quality guide maintained by the Google AI Studio team, to explain the steps.

You've built and deployed a full-stack app with Flutter and Serverpod:

- A custom endpoint that calls an external API from the server.
- A typed data model shared between the server and the app.
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
- A typed data model shared between the server and the app.
- A typed data model shared between the server and the Flutter app.


:::info
For methods to be recognized by Serverpod, they need to return a typed `Future` or `Stream`, where the type must be `void` `bool`, `int`, `double`, `String`, `UuidValue`, `Duration`, `DateTime`, `ByteData`, `Uri`, `BigInt`, or a [serializable model](../06-concepts/02-models/01-models.md). The first parameter must be a `Session` object. You can pass any serializable types as parameters, and even use `List`, `Map`, `Set` or Dart records as long as they are typed.
Endpoint methods take a `Session` as their first parameter and return a typed `Future` or `Stream`. You can pass and return primitive types or any [serializable model](../06-concepts/02-models/01-models.md). The class name's `Endpoint` suffix is dropped on the client, so `RecipeEndpoint` is called through `client.recipe`. See [How it works](../04-get-started/03-how-it-works.md) for how that call reaches the server.
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some minor simplification of the language:

Suggested change
Endpoint methods take a `Session` as their first parameter and return a typed `Future` or `Stream`. You can pass and return primitive types or any [serializable model](../06-concepts/02-models/01-models.md). The class name's `Endpoint` suffix is dropped on the client, so `RecipeEndpoint` is called through `client.recipe`. See [How it works](../04-get-started/03-how-it-works.md) for how that call reaches the server.
Endpoint methods take a `Session` as their first parameter and return a typed `Future` or `Stream`. You can pass and return primitive types or any model defined in a .spy.yaml file. The class name's `Endpoint` suffix is dropped on the client, so `RecipeEndpoint` is called via `client.recipe`. See [How it works](../04-get-started/03-how-it-works.md) for how that call reaches the server.

# Create data models

Serverpod ships with a powerful data modeling system that uses easy-to-read definition files in YAML. It generates Dart classes with all the necessary code to serialize and deserialize the data and connect to the database. This allows you to define your data models for the server and the app in one place, eliminating any inconsistencies. The models give you fine-grained control over the visibility of properties and how they interact with each other.
On the [previous page](./01-creating-endpoints.md) your endpoint returned a plain string. Here you'll define a `Recipe` model so the server returns structured, typed data instead. You define the model once in YAML, and Serverpod generates the Dart class plus all the serialization that moves it between server and client.
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
On the [previous page](./01-creating-endpoints.md) your endpoint returned a plain string. Here you'll define a `Recipe` model so the server returns structured, typed data instead. You define the model once in YAML, and Serverpod generates the Dart class plus all the serialization that moves it between server and client.
On the [previous page](./01-creating-endpoints.md) your endpoint returned a plain string. Here you'll define a `Recipe` model so the server returns structured, typed data instead. You define the model once in YAML, and Serverpod generates the Dart class plus all the serialization needed between server and client.

Then enter some ingredients and tap **Generate Recipe**. The app calls your endpoint and displays the result:

Try out the app by clicking the button to get a new recipe. The app will call the endpoint on the server and display the result in the app.
![Example Flutter App](/img/getting-started/endpoint-chrome-result.png)
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The button says "Send to server", while the code and guide set it to "Generate Recipe". Update the screenshot.

# Manage the database

In this section, we will build upon the models we created in the previous section and add a database to store the recipes that users create in the app. This will allow our application to persist data between sessions.
Right now your recipes disappear when the app reloads. Here you'll store them in the database so they persist, and list previously generated recipes in the app. Serverpod maps your model to a table and gives you a typed API to read and write rows, without writing any SQL.
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
Right now your recipes disappear when the app reloads. Here you'll store them in the database so they persist, and list previously generated recipes in the app. Serverpod maps your model to a table and gives you a typed API to read and write rows, without writing any SQL.
Right now your recipes disappear when the Flutter app reloads. Here you'll store them in the database so they persist, and list previously generated recipes in the app. Serverpod maps your model to a table and gives you a typed API to read and write rows, without writing any SQL.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants