iTranslated by AI
[Flutter] Seeding Initial Data with Isar
Goal
I want to pre-register necessary initial data when the app is first launched!
- Note: I'm assuming that data will be loaded from a JSON file prepared within the app, rather than via an API.
Method Tried
isar/samples: Sample apps using Isar
In the repository above, since the sample was loading and registering data from assets/quotes.json when no initial data existed, I'll try to follow that approach.
Environment Setup
In this case, I will use fvm and work in the following environment:
macOS Monterey Version 12.1 Apple M1
iOS 15.0 iPhone 13 Simulator
Flutter SDK version: 2.10.3
Dart SDK version: 2.16.1
First, create an empty Flutter project and add the following Isar-related packages:
dependencies:
isar: 2.2.1
isar_flutter_libs: 2.2.1 # contains the binaries
path_provider: ^2.0.9
dev_dependencies:
isar_generator: 2.2.1
build_runner: any
Creating the Spot Schema
In this step, we will create the following Spot schema and register its initial data.
(I'll proceed with a plausible scenario where "famous spots around the world need to be registered in advance.")
import 'package:isar/isar.dart';
part 'spot.g.dart';
@Collection()
class Spot {
int? id;
@Index()
late String name;
late double longitude;
late double latitude;
late DateTime createdAt;
late DateTime updatedAt;
}
Run build_runner to generate spot.g.dart.
$ flutter pub run build_runner build
Initializing Isar
void main() async {
WidgetsFlutterBinding.ensureInitialized();
final dir = await getApplicationSupportDirectory();
final isar = await Isar.open(
schemas: [SpotSchema], directory: dir.path, inspector: true);
runApp(const MyApp());
}
- Note: I have set
inspector: trueto allow referencing it with the Isar Inspector.
Loading asset JSON and writing to DB
Future<void> _loadSpots(Isar isar) async {
try {
final bytes = await rootBundle.load('assets/spots.json');
final jsonStr = const Utf8Decoder().convert(bytes.buffer.asUint8List());
final json = jsonDecode(jsonStr) as List;
final now = DateTime.now();
final spots = json.map((e) => Spot()
..name = e['name']
..longitude = double.parse(e['longitude'])
..latitude = double.parse(e['latitude'])
..createdAt = now
..updatedAt = now);
isar.writeTxn((isar) async {
await isar.spots.putAll(spots.toList());
});
} catch (e) {
debugPrint(e.toString());
}
}
void main() async {
WidgetsFlutterBinding.ensureInitialized();
final dir = await getApplicationSupportDirectory();
final isar = await Isar.open(
schemas: [SpotSchema], directory: dir.path, inspector: true);
await _loadSpots(isar); // ← Added
runApp(const MyApp());
}
Regarding _loadSpots, it is a slightly customized version of this from the Isar samples, and the logic is the same.
The content of assets/spots.json is a simple structure:
[
{
"name": "Athens",
"longitude": "23.718989",
"latitude": "37.973620"
},
{
"name": "Istanbul",
"longitude": "29.006069",
"latitude": "41.065960"
},
{
"name": "Vienna",
"longitude": "16.364571",
"latitude": "48.201841"
}
]
Add assets/spots.json to your pubspec.yaml.
flutter:
assets:
- assets/spots.json
Now, let's launch the app and check if it has been registered via the Isar Inspector.

As shown above, the data set in the JSON has been successfully registered! ✨
Using importJson provided by Isar
Actually, Isar provides importJson, importJsonRaw, importJsonSync, and importJsonRawSync which look like they can be used to import from JSON files.
Let's try this too 👀
Modify the previous _loadSpots to the following:
Future<void> _loadSpots(Isar isar) async {
try {
final bytes = await rootBundle.load('assets/spots.json');
final jsonStr = const Utf8Decoder().convert(bytes.buffer.asUint8List());
final json = jsonDecode(jsonStr) as List;
final now = DateTime.now().microsecondsSinceEpoch;
final importJson = json
.map((e) => {
'name': e['name'],
'latitude': double.parse(e['latitude']),
'longitude': double.parse(e['longitude']),
'createdAt': now,
'updatedAt': now,
})
.toList();
isar.writeTxn((isar) async {
await isar.spots.importJson(importJson);
});
} catch (e) {
debugPrint(e.toString());
}
}
In this case, since we have createdAt and updatedAt, we cannot import directly using importJsonRaw, so we use importJson.
Let's compare if there is a performance difference between registering with putAll and this method 👀
When I tried registering 10,000 items in my environment:
-
59msecwithimportJson -
90msecwithputAll
importJson might be better when registering large amounts of data or when you can import directly.
Skipping if already registered
Finally, we will implement it so that if the data is already registered, the initial data loading part is skipped.
There are likely several patterns for this, such as using SharedPreferences to determine if it's already registered using a flag or checking based on the record count. In this case, I implemented it to skip if at least one record exists. ↓
final isar = await Isar.open(
schemas: [SpotSchema], directory: dir.path, inspector: true);
final exists = await isar.spots.count() > 0;
if (!exists) {
debugPrint('Loading spots...');
await _loadSpots(isar);
}
Discussion