Chapters

Hide chapters

Flutter Apprentice

Fourth Edition · Flutter 3.16.9 · Dart 3.2.6 · Android Studio 2023.1.1

Section II: Everything’s a Widget

Section 2: 5 chapters
Show chapters Hide chapters

Section IV: Networking, Persistence & State

Section 4: 6 chapters
Show chapters Hide chapters

15. Saving Data Locally
Written by Kevin D Moore

Heads up... You’re accessing parts of this content for free, with some sections shown as scrambled text.

Heads up... You’re accessing parts of this content for free, with some sections shown as scrambled text.

Unlock our entire catalogue of books and courses, with a Kodeco Personal Plan.

Unlock now

So far, you have a great app that can search the internet for recipes, bookmark the ones you want to make and show a list of ingredients to buy at the store. But what happens if you close the app, go to the store and try to look up your ingredients? They’re gone! As you might have guessed, having an in-memory repository means that the data doesn’t persist after your app closes.

One of the best ways to persist data is with a database. Android, iOS, macOS, Windows and the web provide the SQLite database system access. This allows you to insert, read, update and remove structured data that are persisted on disk.

In this chapter, you’ll learn about using the Drift and sqlbrite packages.

By the end of the chapter, you’ll know:

  • How to insert, fetch and remove recipes or ingredients.
  • How to use the sqlbrite library and receive updates via streams.
  • How to leverage the features of the Drift library when working with databases.

Databases

Databases have been around for a long time, but being able to put a full-blown database on a phone is pretty amazing.

What is a database? Think of it like a file cabinet containing folders with sheets of paper. A database has tables, file folders that store data, and sheets of paper.

Column 2 Column 1 Key Table Column 2 Column 1 Key Table Column 1 Column 2 Key Table Database

Database tables have columns defining data, which are then stored in rows. One of the most popular database management languages is Structured Query Language, commonly known as SQL.

You use SQL commands to get the data in and out of the database.

Using SQL

The SQLite database system on Android and iOS is an embedded engine that runs in the same process as the app. SQLite is lightweight, taking up less than 500 KB on most systems.

Writing Queries

One of the most important parts of SQL is writing a query. A query is a question or inquiry about a data set. To make a query, use the SELECT command followed by any columns you want the database to return, then the table name. For example:

Adding Data

You can add data using the INSERT statement:

Deleting Data

To delete data, use the DELETE statement:

Updating Data

You use UPDATE to update your data. You won’t need this command for this app, but for reference, the syntax is:

sqlbrite

The sqlbrite library is a reactive stream wrapper around sqflite. It allows you to set up streams so you can receive events when there’s a change in your database. In the previous chapter, you created watchAllRecipes() and watchAllIngredients(), which return a Stream. To create these streams from a database, sqlbrite uses a similar approach.

Adding a Database to Recipe Finder

If you’re following along with your app, open it and keep using it with this chapter. If not, locate this chapter’s projects folder and open the starter folder.

Fadugs 3 Yoyizj 3 Sof Xikxe Qujezf 3 Zebonx 9 Sos Sohso Nidecz 9 Voxocv 6 Hib Lobzo Rimapuq Attsidoaxpc Huhawexe Gubaziwawl

Adding Libraries

Open pubspec.yaml and add the following packages after the flutter_riverpod package:

Using the Drift Library

Drift is a package that’s intentionally similar to Android’s Room library.

Database Classes

For your next step, you need to create a set of classes that will describe and create the database, tables and Data Access Objects (DAOs). Below is a diagram showing how your database will look.

Kevzo NanoqiyeOznojdac BayezodoIxvadnel NgBoqita CwAkgpeneexh TarunoYue EhntulaoqcVee Caxwi Jiyikeju RimeqeSocarete

Creating Recipe and Ingredient Tables

To create a table in Drift, you need to create a class that extends Table. To define the table, you just use get calls that define the columns for the table.

Defining the Ingredient Table

Now, find and replace // TODO: Add DbIngredient table definition here with the following:

Creating the Database Class

Drift uses annotations. The first one you need is @DriftDatabase. This specifies the tables and Data Access Objects (DAO) to use.

Creating the DAO Classes

Your first step is to create the RecipeDao class. You’ll see more red squiggles, just ignore them for now. With recipe_db.dart still open, replace // TODO: Add RecipeDao here with the following:

Generating the Part File

Now, you need to create the Drift part file. In Terminal, run:

Converting Your Drift Recipes

At the end of recipe_db.dart, replace // TODO: Add dbRecipeToModelRecipe here with:

Creating Classes for Ingredients

Next, you’ll do the same for the ingredients models. Replace // TODO: Add dbIngredientToIngredient and ingredientToInsertableDbIngredient here with the following:

Updating watchAllRecipes()

Now that you’ve written the conversion methods, you can update watchAllRecipes().

Creating the Drift Repository

Now that you have the Drift database code written, you need to write a repository to handle it. You’ll create a class named DBRepository that implements Repository:

Cogodolatt QuwingCokemewerp SwGivumipujf

Implementing the Repository

As you did in past chapters, you’ll now add all the missing methods following the TODO: indications. Replace // TODO: Add findAllRecipes() with:

Finding Recipes and Ingredients

The find methods are a bit easier, but they still need to convert each database class to a model class.

Inserting Recipes and Ingredients

To insert a recipe, you first insert the recipe itself and then insert all its ingredients. Replace // TODO: Add insertRecipe() with:

Methods for Deleting Recipes and Ingredients

Deleting is much easier. You need to call the DAO methods. Replace // TODO: Add Delete methods with:

Replacing the Repository

Now, you just have to replace your memory repository with your shiny new db repository.

Running the App

Stop the running app, build and run. Try performing searches, adding bookmarks, checking the groceries and deleting bookmarks. It will work just the same as with MemoryRepository, with the added value that bookmarks are persisted across application runs. Try running on Mac, Windows or the web.

Key Points

  • Databases persist data locally to the device.
  • Data stored in databases are available after the app restarts.
  • The Drift package is more powerful, easier to set up and you interact with the database via Dart classes that have clear responsibilities.

Where to Go From Here?

To learn about:

Have a technical question? Want to report a bug? You can ask questions and report bugs to the book authors in our official book forum here.
© 2026 Kodeco Inc.

You’re accessing parts of this content for free, with some sections shown as scrambled text. Unlock our entire catalogue of books and courses, with a Kodeco Personal Plan.

Unlock now