Building Offline Maps with MBTiles and Flutter

Summary
Summary
Summary
Summary

This tutorial explains preparing MBTiles, reading them in Flutter with sqflite/sqlite3, and rendering raster tiles using a custom TileProvider in flutter_map. It covers storage strategies (bundled vs downloadable), coordinate handling (TMS vs XYZ), download validation, and performance tips for offline-first mobile development.

This tutorial explains preparing MBTiles, reading them in Flutter with sqflite/sqlite3, and rendering raster tiles using a custom TileProvider in flutter_map. It covers storage strategies (bundled vs downloadable), coordinate handling (TMS vs XYZ), download validation, and performance tips for offline-first mobile development.

This tutorial explains preparing MBTiles, reading them in Flutter with sqflite/sqlite3, and rendering raster tiles using a custom TileProvider in flutter_map. It covers storage strategies (bundled vs downloadable), coordinate handling (TMS vs XYZ), download validation, and performance tips for offline-first mobile development.

This tutorial explains preparing MBTiles, reading them in Flutter with sqflite/sqlite3, and rendering raster tiles using a custom TileProvider in flutter_map. It covers storage strategies (bundled vs downloadable), coordinate handling (TMS vs XYZ), download validation, and performance tips for offline-first mobile development.

Key insights:
Key insights:
Key insights:
Key insights:
  • Preparing MBTiles: Verify tile format, metadata, and coordinate scheme; include bounds and zoom ranges in metadata.

  • Integrating MBTiles In Flutter: MBTiles is a SQLite DB — use sqflite/sqlite3 to fetch tile blobs by z/x/y and return Uint8List.

  • Displaying Tiles With flutter_map: Implement a custom TileProvider that returns MemoryImage from tile blobs and handle TMS vs XYZ flips.

  • Handling Offline Storage And Updates: Choose bundled MBTiles for static apps or downloadable, versioned files with validation for updates.

  • Performance Strategies: Partition large datasets, limit decoded image memory, and validate MBTiles before swapping into production.

Introduction

Offline maps are vital for many mobile development scenarios: field inspection, remote navigation, and low-connectivity apps. MBTiles is a compact SQLite-based format that packages tiled map data (vector or raster) into a single file. In this tutorial you'll learn how to prepare MBTiles, integrate them into a Flutter app, display tiles with flutter_map, and manage storage and updates. The approach focuses on reliability, small code samples, and practical tips for production apps.

Preparing MBTiles

Create or obtain MBTiles using tools like TileMill, tippecanoe (for vector MBTiles), or mbutil. Key considerations:

  • Tile format: raster PNG/JPEG tiles work out-of-the-box; vector tiles (Mapbox Vector Tiles) require a renderer.

  • Coordinate scheme: MBTiles uses z/x/y (TMS vs XYZ); confirm tile row orientation and convert if necessary.

  • Metadata: include bounds, minzoom, maxzoom, and format in the metadata table for easier validation.

To inspect an MBTiles file, open it with any SQLite client and query the tiles and metadata tables. Example SQL to check tiles:

SELECT count(1) FROM tiles WHERE zoom_level BETWEEN 0 AND 14

Store MBTiles in the app bundle for static content, or download to the device file system for dynamic updates.

Integrating MBTiles In Flutter

Flutter apps can read MBTiles using the sqflite or sqlite3 packages. The MBTiles file is just a SQLite DB; tiles are stored in the tiles table as blob data. A minimal Dart function to fetch a tile blob by z/x/y looks like this:

import 'package:sqflite/sqflite.dart';

Future<Uint8List?> fetchTile(Database db, int z, int x, int y) async {
  final row = await db.rawQuery(
    'SELECT tile_data FROM tiles WHERE zoom_level=? AND tile_column=? AND tile_row=?',
    [z, x, y],
  );
  return row.isNotEmpty ? row.first['tile_data'] as Uint8List : null;
}

Open the MBTiles file with openDatabase, pointing to the file on disk. If you ship MBTiles inside assets, copy it to the app's documents directory at first run to enable SQLite writes (if needed).

Displaying Tiles With flutter_map

flutter_map (Leaflet port) is lightweight and supports custom TileProviders. You can implement a TileProvider that queries MBTiles and returns ImageProviders or raw bytes. Key points:

  • For raster MBTiles, return a MemoryImage from the blob and map tile coordinates.

  • For vector MBTiles, you need a renderer like maplibre-gl, or convert vector tiles into raster at build time.

  • Account for TMS vs XYZ by flipping Y when necessary: tmsY = (1 << z) - 1 - y.

Example TileProvider that returns raster tiles from MBTiles (simplified):

class MbtilesProvider extends TileProvider {
  final Database db;
  MbtilesProvider(this.db);
  @override
  ImageProvider getImage(Coords coords, TileLayerOptions options) {
    final z = coords.z.toInt(); final x = coords.x.toInt(); final y = ((1<<z)-1 - coords.y.toInt());
    return FutureImageProvider(fetchTile(db, z, x, y));
  }
}

Integrate with flutter_map TileLayerOptions using tileProvider: MbtilesProvider(db).

Handling Offline Storage And Updates

Storage strategies:

  • Bundled MBTiles: simplest, immutable, good for static maps. Place file in assets and copy to app storage on first run.

  • Downloadable MBTiles: fetch over HTTP, verify checksum, write to a versioned filename, and migrate atomically.

Updates and partial downloads:

  • Use separate MBTiles per region or zoom-range to support incremental downloads.

  • Serve metadata (bounds, size, zoom levels) from your backend so the app decides what to download.

  • Perform downloads in background isolates and validate files with SQLite PRAGMA quick_check or a hash before swapping.

Performance tips:

  • Keep MBTiles compact. Use appropriate tile compression and vector simplification.

  • Limit max in-memory decoded images; rely on platform image caching and evict large caches manually if memory spikes.

  • For very large MBTiles, consider a tiled file structure and on-demand opening of databases to reduce file descriptor usage.

Security and integrity:

  • Validate downloaded MBTiles before using.

  • Run queries with prepared statements to avoid injection risk (less relevant for local files but still good practice).

Vibe Studio

Vibe Studio, powered by Steve’s advanced AI agents, is a revolutionary no-code, conversational platform that empowers users to quickly and efficiently create full-stack Flutter applications integrated seamlessly with Firebase backend services. Ideal for solo founders, startups, and agile engineering teams, Vibe Studio allows users to visually manage and deploy Flutter apps, greatly accelerating the development process. The intuitive conversational interface simplifies complex development tasks, making app creation accessible even for non-coders.

Conclusion

Packaging MBTiles with Flutter gives predictable, offline-first maps for mobile development. Use sqflite or sqlite3 to read tiles, a custom TileProvider in flutter_map to render them, and a careful storage/update strategy for reliability. This approach minimizes network dependency, improves user experience in low-connectivity environments, and scales from small region packs to larger global datasets when partitioned sensibly. Start by producing small test MBTiles, wire a simple provider, then add download, validation, and cache policies for production-ready offline maps.

Introduction

Offline maps are vital for many mobile development scenarios: field inspection, remote navigation, and low-connectivity apps. MBTiles is a compact SQLite-based format that packages tiled map data (vector or raster) into a single file. In this tutorial you'll learn how to prepare MBTiles, integrate them into a Flutter app, display tiles with flutter_map, and manage storage and updates. The approach focuses on reliability, small code samples, and practical tips for production apps.

Preparing MBTiles

Create or obtain MBTiles using tools like TileMill, tippecanoe (for vector MBTiles), or mbutil. Key considerations:

  • Tile format: raster PNG/JPEG tiles work out-of-the-box; vector tiles (Mapbox Vector Tiles) require a renderer.

  • Coordinate scheme: MBTiles uses z/x/y (TMS vs XYZ); confirm tile row orientation and convert if necessary.

  • Metadata: include bounds, minzoom, maxzoom, and format in the metadata table for easier validation.

To inspect an MBTiles file, open it with any SQLite client and query the tiles and metadata tables. Example SQL to check tiles:

SELECT count(1) FROM tiles WHERE zoom_level BETWEEN 0 AND 14

Store MBTiles in the app bundle for static content, or download to the device file system for dynamic updates.

Integrating MBTiles In Flutter

Flutter apps can read MBTiles using the sqflite or sqlite3 packages. The MBTiles file is just a SQLite DB; tiles are stored in the tiles table as blob data. A minimal Dart function to fetch a tile blob by z/x/y looks like this:

import 'package:sqflite/sqflite.dart';

Future<Uint8List?> fetchTile(Database db, int z, int x, int y) async {
  final row = await db.rawQuery(
    'SELECT tile_data FROM tiles WHERE zoom_level=? AND tile_column=? AND tile_row=?',
    [z, x, y],
  );
  return row.isNotEmpty ? row.first['tile_data'] as Uint8List : null;
}

Open the MBTiles file with openDatabase, pointing to the file on disk. If you ship MBTiles inside assets, copy it to the app's documents directory at first run to enable SQLite writes (if needed).

Displaying Tiles With flutter_map

flutter_map (Leaflet port) is lightweight and supports custom TileProviders. You can implement a TileProvider that queries MBTiles and returns ImageProviders or raw bytes. Key points:

  • For raster MBTiles, return a MemoryImage from the blob and map tile coordinates.

  • For vector MBTiles, you need a renderer like maplibre-gl, or convert vector tiles into raster at build time.

  • Account for TMS vs XYZ by flipping Y when necessary: tmsY = (1 << z) - 1 - y.

Example TileProvider that returns raster tiles from MBTiles (simplified):

class MbtilesProvider extends TileProvider {
  final Database db;
  MbtilesProvider(this.db);
  @override
  ImageProvider getImage(Coords coords, TileLayerOptions options) {
    final z = coords.z.toInt(); final x = coords.x.toInt(); final y = ((1<<z)-1 - coords.y.toInt());
    return FutureImageProvider(fetchTile(db, z, x, y));
  }
}

Integrate with flutter_map TileLayerOptions using tileProvider: MbtilesProvider(db).

Handling Offline Storage And Updates

Storage strategies:

  • Bundled MBTiles: simplest, immutable, good for static maps. Place file in assets and copy to app storage on first run.

  • Downloadable MBTiles: fetch over HTTP, verify checksum, write to a versioned filename, and migrate atomically.

Updates and partial downloads:

  • Use separate MBTiles per region or zoom-range to support incremental downloads.

  • Serve metadata (bounds, size, zoom levels) from your backend so the app decides what to download.

  • Perform downloads in background isolates and validate files with SQLite PRAGMA quick_check or a hash before swapping.

Performance tips:

  • Keep MBTiles compact. Use appropriate tile compression and vector simplification.

  • Limit max in-memory decoded images; rely on platform image caching and evict large caches manually if memory spikes.

  • For very large MBTiles, consider a tiled file structure and on-demand opening of databases to reduce file descriptor usage.

Security and integrity:

  • Validate downloaded MBTiles before using.

  • Run queries with prepared statements to avoid injection risk (less relevant for local files but still good practice).

Vibe Studio

Vibe Studio, powered by Steve’s advanced AI agents, is a revolutionary no-code, conversational platform that empowers users to quickly and efficiently create full-stack Flutter applications integrated seamlessly with Firebase backend services. Ideal for solo founders, startups, and agile engineering teams, Vibe Studio allows users to visually manage and deploy Flutter apps, greatly accelerating the development process. The intuitive conversational interface simplifies complex development tasks, making app creation accessible even for non-coders.

Conclusion

Packaging MBTiles with Flutter gives predictable, offline-first maps for mobile development. Use sqflite or sqlite3 to read tiles, a custom TileProvider in flutter_map to render them, and a careful storage/update strategy for reliability. This approach minimizes network dependency, improves user experience in low-connectivity environments, and scales from small region packs to larger global datasets when partitioned sensibly. Start by producing small test MBTiles, wire a simple provider, then add download, validation, and cache policies for production-ready offline maps.

Build Flutter Apps Faster with Vibe Studio

Build Flutter Apps Faster with Vibe Studio

Build Flutter Apps Faster with Vibe Studio

Build Flutter Apps Faster with Vibe Studio

Vibe Studio is your AI-powered Flutter development companion. Skip boilerplate, build in real-time, and deploy without hassle. Start creating apps at lightning speed with zero setup.

Vibe Studio is your AI-powered Flutter development companion. Skip boilerplate, build in real-time, and deploy without hassle. Start creating apps at lightning speed with zero setup.

Vibe Studio is your AI-powered Flutter development companion. Skip boilerplate, build in real-time, and deploy without hassle. Start creating apps at lightning speed with zero setup.

Vibe Studio is your AI-powered Flutter development companion. Skip boilerplate, build in real-time, and deploy without hassle. Start creating apps at lightning speed with zero setup.

Other Insights

Other Insights

Other Insights

Other Insights

Join a growing community of builders today

Join a growing community of builders today

Join a growing community of builders today

Join a growing community of builders today

Join a growing community of builders today

28-07 Jackson Ave

Walturn

New York NY 11101 United States

© Steve • All Rights Reserved 2025

28-07 Jackson Ave

Walturn

New York NY 11101 United States

© Steve • All Rights Reserved 2025

28-07 Jackson Ave

Walturn

New York NY 11101 United States

© Steve • All Rights Reserved 2025

28-07 Jackson Ave

Walturn

New York NY 11101 United States

© Steve • All Rights Reserved 2025

28-07 Jackson Ave

Walturn

New York NY 11101 United States

© Steve • All Rights Reserved 2025

28-07 Jackson Ave

Walturn

New York NY 11101 United States

© Steve • All Rights Reserved 2025