← Back to Blogs

Data Synchronization

Implementing Offline-First Architecture with Local Databases in React Native

InnovationM Admin 24 Jul 2025 4 min read
Implementing Offline-First Architecture with Local Databases in React Native

In today’s mobile-first world, ensuring your app works seamlessly without an internet connection is no longer a luxury — it’s a necessity. This is where the Offline-First architecture comes in. In this guide, we’ll implement an offline-first architecture in a React Native application using local databases, data synchronization, and network status handling.

Table of Contents

  1. What is Offline-First Architecture?
  2. Why Offline-First in React Native?
  3. Tools and Libraries
  4. Setting up the Project
  5. Using SQLite with react-native-sqlite-storage
  6. Detecting Network Status
  7. Syncing Data with Remote API
  8. Handling Conflicts
  9. Example Use Case: Notes App
  10. Best Practices
  11. Conclusion

What is Offline-First Architecture?

Offline-First means your application prioritizes local data and uses the network only when available. The user should be able to read/write data offline, and it should sync with the backend once the network is available.

Why Offline-First in React Native?

  • Better UX in unstable networks.
  • Faster access to data.
  • Essential for travel, rural areas, or low-end devices.

Tools and Libraries

We’ll use:

  • react-native-sqlite-storage: Local database storage 
  • @react-native-community/netinfo: Network status 
  • axios: API requests 
  • redux or zustand: For state management (optional) 
  • background-fetch or custom logic for sync (optional for auto-sync) 

Install dependencies:

npm install react-native-sqlite-storage @react-native-community/netinfo axios

For iOS and Android, link SQLite properly:

cd ios && pod install

 Setting up the Project

Create a new React Native project:

npx react-native init OfflineFirstApp

cd OfflineFirstApp

Using SQLite with react-native-sqlite-storage

✅ Initialize SQLite

// db.js

import SQLite from 'react-native-sqlite-storage';

SQLite.enablePromise(true);

export const getDBConnection = async () => {

return await SQLite.openDatabase({ name: 'offline.db', location: 'default' });

};

export const createTables = async (db) => {

const query = `CREATE TABLE IF NOT EXISTS notes (

id INTEGER PRIMARY KEY AUTOINCREMENT,

title TEXT,

content TEXT,

synced INTEGER DEFAULT 0

)`;

await db.executeSql(query);

};

export const insertNote = async (db, note) => {

const insertQuery = 'INSERT INTO notes (title, content, synced) VALUES (?, ?, ?)';

await db.executeSql(insertQuery, [note.title, note.content, 0]);

};

export const getUnsyncedNotes = async (db) => {

const [results] = await db.executeSql('SELECT * FROM notes WHERE synced = 0');

return results;

};

const notes = [];

for (let i = 0; i < results.rows.length; i++) {

notes.push(results.rows.item(i));

}

return notes;

};

export const markAsSynced = async (db, noteId) => {

await db.executeSql(

`UPDATE notes SET synced = 1 WHERE id = ?`,

[noteId]

);

};

Detecting Network Status

// useNetwork.js
import { useEffect, useState } from 'react';

import NetInfo from '@react-native-community/netinfo';

const useNetwork = () => {

  const [isConnected, setIsConnected] = useState(true);

  useEffect(() => {

    const unsubscribe = NetInfo.addEventListener(state => {

      setIsConnected(state.isConnected);

    });

    return () => unsubscribe();

  }, []);

  return isConnected;

};

export default useNetwork;

Syncing Data with Remote API

Example sync function

// sync.js

import axios from 'axios';

import { getDBConnection, getUnsyncedNotes, markAsSynced } from './db';

export const syncNotes = async () => {

  const db = await getDBConnection();

  const unsyncedNotes = await getUnsyncedNotes(db);

  for (const note of unsyncedNotes) {

    try {

      await axios.post('https://your-api.com/notes', {

        title: note.title,

        content: note.content,

      });

      await markAsSynced(db, note.id);

    } catch (error) {

      console.log('Sync failed for note:', note.id);

    }

  }

};

You can trigger syncNotes() when the network becomes available.

Handling Conflicts

Use timestamps and conflict resolution strategies:

  • Last-write-wins 
  • Merge if both updated 
  • Prompt user for manual resolution 

Update the DB schema:

ALTER TABLE notes ADD COLUMN updated_at TEXT;

Compare timestamps before syncing.

Example Use Case: Notes App

Create Note Screen

// CreateNote.js

import React, { useState } from 'react';

import { View, TextInput, Button } from 'react-native';

import { getDBConnection, insertNote } from './db';

import useNetwork from './useNetwork';

import { syncNotes } from './sync';

const CreateNote = () => {

  const [title, setTitle] = useState('');

  const [content, setContent] = useState('');

  const isConnected = useNetwork();

  const saveNote = async () => {

    const db = await getDBConnection();

    await insertNote(db, { title, content });
    if (isConnected) {

      await syncNotes();

    }

    setTitle('');

    setContent('');

  };
  return (

    <View>

      <TextInput placeholder="Title" value={title} onChangeText={setTitle} />

      <TextInput placeholder="Content" value={content} onChangeText={setContent} />

      <Button title="Save Note" onPress={saveNote} />

    </View>

  );

};
export default CreateNote;

Best Practices

  • Use timestamps for syncing.
  • Consider retry strategies with exponential backoff.
  • Use queueing mechanisms to ensure order of operations.
  • Optimize for battery by syncing on certain conditions (WiFi, charging).
  • Encrypt sensitive local data if needed.

Optional Enhancements

  • Use WatermelonDB or Realm for complex apps.
  • Background sync using react-native-background-fetch.
  • Use redux-persist to persist the UI state.
  • Add UI indicators for “syncing” state.

Conclusion

Implementing an offline-first architecture in React Native greatly improves UX, especially in real-world conditions where connectivity is unreliable. With local databases, smart sync logic, and proper network detection, you can ensure a robust user experience.

About the Author
InnovationM Admin

Contributor at InnovationM.

LinkedIn

We don't
predict
the future.
We build what
comes next.

Share your goals, challenges, or ideas, we'll help you turn them into scalable digital solutions.