[{"data":1,"prerenderedAt":70},["ShallowReactive",2],{"tutorial-salvare-dati-nel-cloud-con-cloud-firestore-in-flutter":3,"comments-tutorial-salvare-dati-nel-cloud-con-cloud-firestore-in-flutter":69},{"id":4,"title":5,"slug":6,"excerpt":7,"intro":8,"cover_image":9,"video_url":10,"difficulty":11,"estimated_minutes":12,"flutter_version":13,"status":14,"published_at":15,"meta_title":16,"meta_description":17,"category":18,"author":22,"steps":24},22,"Salvare dati nel cloud con Cloud Firestore in Flutter","salvare-dati-nel-cloud-con-cloud-firestore-in-flutter","Impara a integrare Cloud Firestore nella tua app Flutter per leggere, scrivere e ascoltare dati in tempo reale, costruendo una semplice lista di attività condivisa.","Cloud Firestore è il database NoSQL realtime di Firebase, perfetto per applicazioni che necessitano di sincronizzazione automatica dei dati tra dispositivi. In questo tutorial costruiremo una semplice app per gestire una lista di task (note) salvate nel cloud: vedremo come configurare il progetto, scrivere documenti, leggerli in tempo reale tramite stream e gestire aggiornamenti ed eliminazioni.\n\nAlla fine avrai una base solida per integrare Firestore in qualsiasi progetto Flutter.","https:\u002F\u002Fflutter.it\u002Fstorage\u002Ftutorials\u002Fa2f9402b-60c7-43a4-8f1a-16ae7d233f19.jpg",null,"intermediate",40,"3.x","published","2026-06-28T04:30:41+00:00","Cloud Firestore in Flutter: guida pratica","Tutorial pratico per integrare Cloud Firestore in Flutter: salvare, leggere in tempo reale, aggiornare ed eliminare dati nel cloud.",{"id":19,"name":20,"slug":21},1,"Guide","guide",{"id":19,"name":23},"Flutter Bot",[25,32,40,47,54,61],{"id":26,"position":19,"title":27,"body":28,"code_snippet":29,"code_language":30,"expected_result":31,"demo_url":10,"video_url":10},149,"Configurare Firebase e aggiungere le dipendenze","Per prima cosa crea un progetto su [Firebase Console](https:\u002F\u002Fconsole.firebase.google.com) e abilita **Cloud Firestore** in modalità test (per lo sviluppo).\n\nInstalla la CLI di Firebase e FlutterFire CLI, quindi collega il progetto:\n\n```bash\ndart pub global activate flutterfire_cli\nflutterfire configure\n```\n\nQuesto comando genera il file `firebase_options.dart`. Aggiungi infine le dipendenze al `pubspec.yaml`.","dependencies:\n  flutter:\n    sdk: flutter\n  firebase_core: ^2.27.0\n  cloud_firestore: ^4.15.0","yaml","Il progetto Flutter è collegato a Firebase e le dipendenze sono installate con `flutter pub get`.",{"id":33,"position":34,"title":35,"body":36,"code_snippet":37,"code_language":38,"expected_result":39,"demo_url":10,"video_url":10},150,2,"Inizializzare Firebase all'avvio dell'app","Prima di usare Firestore dobbiamo inizializzare Firebase nel metodo `main`. Ricordati di rendere `main` asincrono e di chiamare `WidgetsFlutterBinding.ensureInitialized()`.","import 'package:flutter\u002Fmaterial.dart';\nimport 'package:firebase_core\u002Ffirebase_core.dart';\nimport 'firebase_options.dart';\n\nFuture\u003Cvoid> main() async {\n  WidgetsFlutterBinding.ensureInitialized();\n  await Firebase.initializeApp(\n    options: DefaultFirebaseOptions.currentPlatform,\n  );\n  runApp(const MyApp());\n}\n\nclass MyApp extends StatelessWidget {\n  const MyApp({super.key});\n\n  @override\n  Widget build(BuildContext context) {\n    return MaterialApp(\n      title: 'Firestore Tasks',\n      theme: ThemeData(useMaterial3: true, colorSchemeSeed: Colors.indigo),\n      home: const TasksPage(),\n    );\n  }\n}","dart","L'app si avvia senza errori e Firebase risulta inizializzato correttamente.",{"id":41,"position":42,"title":43,"body":44,"code_snippet":45,"code_language":38,"expected_result":46,"demo_url":10,"video_url":10},151,3,"Creare un servizio per accedere a Firestore","Per mantenere il codice pulito incapsuliamo le operazioni su Firestore in una classe `TaskService`. Lavoreremo su una collection chiamata `tasks`, dove ogni documento ha i campi `title` (testo) e `done` (booleano).","import 'package:cloud_firestore\u002Fcloud_firestore.dart';\n\nclass TaskService {\n  final _collection = FirebaseFirestore.instance.collection('tasks');\n\n  \u002F\u002F Stream in tempo reale ordinato per data di creazione\n  Stream\u003CQuerySnapshot\u003CMap\u003CString, dynamic>>> watchTasks() {\n    return _collection.orderBy('createdAt', descending: true).snapshots();\n  }\n\n  Future\u003Cvoid> addTask(String title) {\n    return _collection.add({\n      'title': title,\n      'done': false,\n      'createdAt': FieldValue.serverTimestamp(),\n    });\n  }\n\n  Future\u003Cvoid> toggleDone(String id, bool done) {\n    return _collection.doc(id).update({'done': done});\n  }\n\n  Future\u003Cvoid> deleteTask(String id) {\n    return _collection.doc(id).delete();\n  }\n}","Hai una classe riutilizzabile con i metodi per leggere, aggiungere, aggiornare ed eliminare i task.",{"id":48,"position":49,"title":50,"body":51,"code_snippet":52,"code_language":38,"expected_result":53,"demo_url":10,"video_url":10},152,4,"Mostrare i dati in tempo reale con StreamBuilder","Usiamo uno `StreamBuilder` collegato al metodo `watchTasks()`. Ogni volta che un documento cambia su Firestore, la UI si aggiorna automaticamente senza dover ricaricare la pagina.","class TasksPage extends StatelessWidget {\n  const TasksPage({super.key});\n\n  @override\n  Widget build(BuildContext context) {\n    final service = TaskService();\n    return Scaffold(\n      appBar: AppBar(title: const Text('Le mie attività')),\n      body: StreamBuilder\u003CQuerySnapshot\u003CMap\u003CString, dynamic>>>(\n        stream: service.watchTasks(),\n        builder: (context, snapshot) {\n          if (snapshot.hasError) {\n            return const Center(child: Text('Errore nel caricamento'));\n          }\n          if (!snapshot.hasData) {\n            return const Center(child: CircularProgressIndicator());\n          }\n          final docs = snapshot.data!.docs;\n          if (docs.isEmpty) {\n            return const Center(child: Text('Nessuna attività'));\n          }\n          return ListView.builder(\n            itemCount: docs.length,\n            itemBuilder: (context, index) {\n              final doc = docs[index];\n              final data = doc.data();\n              return CheckboxListTile(\n                title: Text(data['title'] ?? ''),\n                value: data['done'] ?? false,\n                onChanged: (v) => service.toggleDone(doc.id, v ?? false),\n                secondary: IconButton(\n                  icon: const Icon(Icons.delete_outline),\n                  onPressed: () => service.deleteTask(doc.id),\n                ),\n              );\n            },\n          );\n        },\n      ),\n    );\n  }\n}","La lista mostra i task presenti su Firestore e si aggiorna in tempo reale.",{"id":55,"position":56,"title":57,"body":58,"code_snippet":59,"code_language":38,"expected_result":60,"demo_url":10,"video_url":10},153,5,"Aggiungere nuovi task con un dialog","Aggiungiamo un `FloatingActionButton` che apre un dialog per inserire il titolo di un nuovo task. Al salvataggio chiamiamo `addTask`, e grazie allo stream la lista si aggiorna da sola.","\u002F\u002F Aggiungi questo al Scaffold della TasksPage\nfloatingActionButton: FloatingActionButton(\n  onPressed: () => _showAddDialog(context, service),\n  child: const Icon(Icons.add),\n),\n\n\u002F\u002F Metodo helper\nFuture\u003Cvoid> _showAddDialog(BuildContext context, TaskService service) async {\n  final controller = TextEditingController();\n  await showDialog(\n    context: context,\n    builder: (context) => AlertDialog(\n      title: const Text('Nuova attività'),\n      content: TextField(\n        controller: controller,\n        autofocus: true,\n        decoration: const InputDecoration(hintText: 'Cosa devi fare?'),\n      ),\n      actions: [\n        TextButton(\n          onPressed: () => Navigator.pop(context),\n          child: const Text('Annulla'),\n        ),\n        FilledButton(\n          onPressed: () {\n            final text = controller.text.trim();\n            if (text.isNotEmpty) {\n              service.addTask(text);\n            }\n            Navigator.pop(context);\n          },\n          child: const Text('Salva'),\n        ),\n      ],\n    ),\n  );\n}","Premendo il FAB puoi inserire un nuovo task che appare immediatamente nella lista e viene salvato nel cloud.",{"id":62,"position":63,"title":64,"body":65,"code_snippet":66,"code_language":67,"expected_result":68,"demo_url":10,"video_url":10},154,6,"Configurare le regole di sicurezza","La modalità test scade dopo 30 giorni e lascia il database aperto a tutti. Prima di andare in produzione devi impostare regole di sicurezza adeguate. Se la tua app usa l'autenticazione, limita l'accesso agli utenti loggati.\n\nNel tab **Rules** della console Firestore inserisci ad esempio:","rules_version = '2';\nservice cloud.firestore {\n  match \u002Fdatabases\u002F{database}\u002Fdocuments {\n    match \u002Ftasks\u002F{document} {\n      \u002F\u002F Consenti la lettura\u002Fscrittura solo a utenti autenticati\n      allow read, write: if request.auth != null;\n    }\n  }\n}","javascript","Il database non è più accessibile pubblicamente: solo gli utenti autenticati possono leggere e scrivere i task.",[],1785219610683]