Storing App Data with SQLite in a Kivy Application

In this tutorial, you will learn how to build a data-driven application using Python and Kivy, with data stored locally using SQLite. This is a practical step toward creating apps that retain user data across sessions; perfect for to-do lists, notes, expense trackers, or any form-based mobile or desktop application.

We will walk through a basic example of integrating SQLite into a Kivy app. The database will store and retrieve user-generated data dynamically within the app.

Step 1: Installing Required Libraries

Kivy comes with everything you need for the GUI. Python also includes SQLite support by default through the sqlite3 module, so no additional installation is required.

Step 2: Setting Up the Database

Before creating the user interface, we will define a simple SQLite database to store task data. Each task will have an ID and a text description.

    
      import sqlite3

      def initialize_database():
          conn = sqlite3.connect("tasks.db")
          cursor = conn.cursor()
          cursor.execute('''
              CREATE TABLE IF NOT EXISTS tasks (
                  id INTEGER PRIMARY KEY AUTOINCREMENT,
                  content TEXT NOT NULL
              )
          ''')
          conn.commit()
          conn.close()
    
  

This function creates a database file named tasks.db with a single table called tasks.

Step 3: Creating the Application Layout

Now we will build the Kivy interface using BoxLayout, TextInput, Button, and Label widgets. The app will include:

All code will be in a single Python file.


    from kivy.app import App
    from kivy.uix.boxlayout import BoxLayout
    from kivy.uix.button import Button
    from kivy.uix.label import Label
    from kivy.uix.textinput import TextInput
    from kivy.uix.scrollview import ScrollView
    from kivy.uix.gridlayout import GridLayout
    import sqlite3

    class TaskApp(App):
      def build(self):
        initialize_database()

        self.root_layout = BoxLayout(orientation='vertical', padding=20, spacing=10)

        input_layout = BoxLayout(size_hint_y=None, height=40, spacing=10)
        self.task_input = TextInput(hint_text='Enter a task')
        add_button = Button(text='Add')
        add_button.bind(on_press=self.add_task)

        input_layout.add_widget(self.task_input)
        input_layout.add_widget(add_button)

        self.task_container = GridLayout(cols=1, spacing=10, size_hint_y=None)
        self.task_container.bind(minimum_height=self.task_container.setter('height'))

        scroll = ScrollView()
        scroll.add_widget(self.task_container)

        self.root_layout.add_widget(input_layout)
        self.root_layout.add_widget(scroll)

        self.load_tasks()

        return self.root_layout

      def add_task(self, instance):
        task_text = self.task_input.text.strip()
        if task_text:
          conn = sqlite3.connect("tasks.db")
          cursor = conn.cursor()
          cursor.execute("INSERT INTO tasks (content) VALUES (?)", (task_text,))
          conn.commit()
          conn.close()
          self.task_input.text = ''
          self.load_tasks()

      def delete_task(self, task_id):
        conn = sqlite3.connect("tasks.db")
        cursor = conn.cursor()
        cursor.execute("DELETE FROM tasks WHERE id = ?", (task_id,))
        conn.commit()
        conn.close()
        self.load_tasks()

      def load_tasks(self):
        self.task_container.clear_widgets()
        conn = sqlite3.connect("tasks.db")
        cursor = conn.cursor()
        cursor.execute("SELECT id, content FROM tasks")
        tasks = cursor.fetchall()
        conn.close()

      for task_id, content in tasks:
        task_box = BoxLayout(size_hint_y=None, height=40, spacing=10)
        label = Label(text=content, halign='left', valign='middle')
        label.bind(size=label.setter('text_size'))

        delete_button = Button(text='Delete', size_hint_x=None, width=80)
        delete_button.bind(on_press=lambda instance, id=task_id: self.delete_task(id))

        task_box.add_widget(label)
        task_box.add_widget(delete_button)
        self.task_container.add_widget(task_box)
    
  

Step 4: Running the Application

Save the code above in a file named task_app.py and run it with:

python task_app.py

The application window will allow users to enter tasks, view stored tasks, and delete them. All task data is stored in tasks.db and will persist across sessions.

Conclusion

You now have a fully functional Kivy application that stores user data using SQLite. This is a foundational pattern for building data-driven apps where offline persistence is required. The same codebase can be packaged for mobile platforms using tools like Buildozer for Android or PyInstaller for desktop.

This project demonstrates how to connect a local database to a modern Python interface using Kivy. From here, you can expand the app by adding search functionality, editing tasks, or syncing with an online database.