Last modified: Sep 22, 2026

Connecting Python to SQLite

Python SQLite Connection: A Complete Guide

Working with databases is essential for modern applications. Python provides built-in support for SQLite through the sqlite3 module. This guide explains how to connect Python to SQLite effectively.

SQLite is a lightweight, file-based database. It requires no separate server setup. Python's sqlite3 module makes database operations simple and intuitive.

Why Choose SQLite with Python?

SQLite offers several advantages:

  • Zero configuration: No server installation required
  • Lightweight: Minimal memory footprint
  • File-based: Database stored as a single file
  • Built-in: Part of Python standard library

Basic Connection Setup

Connecting Python to SQLite is straightforward. Use the sqlite3.connect() function to establish a connection:


import sqlite3

# Connect to SQLite database (creates if not exists)
conn = sqlite3.connect('example.db')

print("Connection established successfully")
print(type(conn))

Connection established successfully
<class 'sqlite3.Connection'>

This creates a file named example.db in your current directory. The connection object provides methods for executing SQL commands.

Creating Your First Table

After connecting, create tables using SQL statements. Use the cursor() method to execute queries:


import sqlite3

# Establish connection
conn = sqlite3.connect('users.db')

# Create cursor object
cursor = conn.cursor()

# SQL statement to create table
create_table_query = """
CREATE TABLE IF NOT EXISTS users (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    name TEXT NOT NULL,
    email TEXT UNIQUE NOT NULL,
    age INTEGER
);
"""

# Execute the query
cursor.execute(create_table_query)

# Commit changes to database
conn.commit()

print("Table created successfully")

Table created successfully

The IF NOT EXISTS clause prevents errors when re-running. Always call conn.commit() to save changes permanently.

Inserting Data into Tables

Insert records using the cursor.execute() method with parameterized queries for security:


import sqlite3

conn = sqlite3.connect('users.db')
cursor = conn.cursor()

# Parameterized insert query
insert_query = """
INSERT INTO users (name, email, age)
VALUES (?, ?, ?)
"""

# Data to insert
user_data = [
    ('Alice Johnson', 'alice@example.com', 28),
    ('Bob Smith', 'bob@example.com', 32),
    ('Carol Davis', 'carol@example.com', 25)
]

# Insert multiple records
cursor.executemany(insert_query, user_data)

# Save changes
conn.commit()

print(f"Inserted {cursor.rowcount} records successfully")

Inserted 3 records successfully

Using executemany() efficiently inserts multiple records. Parameterized queries prevent SQL injection attacks.

Querying Data from SQLite

Retrieve data using SELECT statements with the cursor.execute() method:


import sqlite3

conn = sqlite3.connect('users.db')
cursor = conn.cursor()

# Select all users
cursor.execute("SELECT * FROM users")

# Fetch all results
all_users = cursor.fetchall()

print("All Users:")
for user in all_users:
    print(f"ID: {user[0]}, Name: {user[1]}, Email: {user[2]}, Age: {user[3]}")

All Users:
ID: 1, Name: Alice Johnson, Email: alice@example.com, Age: 28
ID: 2, Name: Bob Smith, Email: bob@example.com, Age: 32
ID: 3, Name: Carol Davis, Email: carol@example.com, Age: 25

The fetchall() method returns all matching rows. Alternatives include fetchone() for single records.

Updating Existing Records

Modify data using UPDATE statements with proper conditions:


import sqlite3

conn = sqlite3.connect('users.db')
cursor = conn.cursor()

# Update user age
update_query = """
UPDATE users
SET age = ?
WHERE name = ?
"""

cursor.execute(update_query, (29, 'Alice Johnson'))
conn.commit()

# Verify update
cursor.execute("SELECT name, age FROM users WHERE name = 'Alice Johnson'")
result = cursor.fetchone()

print(f"Updated record: {result}")

Updated record: ('Alice Johnson', 29)

Always specify WHERE conditions carefully. Without them, all records get affected unintentionally.

Deleting Records Safely

Remove data using DELETE statements with caution:


import sqlite3

conn = sqlite3.connect('users.db')
cursor = conn.cursor()

# Delete specific user
delete_query = "DELETE FROM users WHERE age < ?"

cursor.execute(delete_query, (26,))
conn.commit()

# Check remaining records
cursor.execute("SELECT COUNT(*) FROM users")
remaining = cursor.fetchone()[0]

print(f"Remaining users: {remaining}")

Remaining users: 2

The cursor.rowcount property shows affected rows. Always test DELETE operations in development first.

Proper Resource Management

Close connections properly to avoid resource leaks. Use context managers for automatic cleanup:


import sqlite3

# Using context manager for automatic cleanup
with sqlite3.connect('users.db') as conn:
    cursor = conn.cursor()
    
    # Perform database operations
    cursor.execute("SELECT name, email FROM users")
    users = cursor.fetchall()
    
    for user in users:
        print(f"{user[0]}: {user[1]}")
    
    # Connection automatically commits and closes

print("Database operations completed safely")

Alice Johnson: alice@example.com
Bob Smith: bob@example.com
Database operations completed safely

Context managers ensure connections close even during exceptions. This prevents database locking issues.

Error Handling Best Practices

Handle database errors gracefully using try-except blocks:


import sqlite3
from sqlite3 import Error

def create_connection(db_file):
    """Create database connection to SQLite database"""
    conn = None
    try:
        conn = sqlite3.connect(db_file)
        print(f"Connected to {db_file} successfully")
        return conn
    except Error as e:
        print(f"Connection error: {e}")
        return None

def safe_insert(conn, user):
    """Safely insert user data with error handling"""
    try:
        cursor = conn.cursor()
        cursor.execute(
            "INSERT INTO users (name, email, age) VALUES (?, ?, ?)",
            user
        )
        conn.commit()
        print("Record inserted successfully")
    except Error as e:
        print(f"Insertion error: {e}")
        conn.rollback()

# Usage example
connection = create_connection('users.db')
if connection:
    new_user = ('David Wilson', 'david@example.com', 30)
    safe_insert(connection, new_user)
    connection.close()

Connected to users.db successfully
Record inserted successfully

Use rollback() to undo failed transactions. Always validate data before insertion.

Advanced Connection Options

Configure connections with additional parameters for better performance:


import sqlite3

# Advanced connection with timeout and isolation level
conn = sqlite3.connect(
    'advanced.db',
    timeout=10.0,          # Wait 10 seconds for lock
    isolation_level=None,  # Auto-commit mode
    check_same_thread=False  # Allow multi-thread access
)

cursor = conn.cursor()

# Create table with advanced settings
cursor.execute("""
CREATE TABLE IF NOT EXISTS products (
    id INTEGER PRIMARY KEY,
    name TEXT NOT NULL,
    price REAL CHECK(price > 0),
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
)
""")

# Insert sample product
cursor.execute(
    "INSERT INTO products (name, price) VALUES (?, ?)",
    ('Laptop', 999.99)
)

cursor.execute("SELECT * FROM products")
product = cursor.fetchone()
print(f"Product: {product}")

conn.close()

Product: (1, 'Laptop', 999.99, '2023-06-15 10:30:45')

The timeout parameter handles database locks. Set isolation_level=None for auto-commit mode.

Retrieving Database Metadata

Access database information using built-in methods:


import sqlite3

conn = sqlite3.connect('users.db')
cursor = conn.cursor()

# Get table names
cursor.execute("SELECT name FROM sqlite_master WHERE type='table'")
tables = cursor.fetchall()
print(f"Tables: {[table[0] for table in tables]}")

# Get column information
cursor.execute("PRAGMA table_info(users)")
columns = cursor.fetchall()
print("\nUsers table columns:")
for col in columns:
    print(f"  {col[1]} ({col[2]})")

# Get SQLite version
print(f"\nSQLite version: {sqlite3.sqlite_version}")

conn.close()

Tables: ['users']

Users table columns:
  id (INTEGER)
  name (TEXT)
  email (TEXT)
  age (INTEGER)

SQLite version: 3.39.5

The sqlite_master table contains schema information. Use PRAGMA commands for detailed metadata.

Performance Optimization Tips

Improve database performance with these techniques:


import sqlite3
import time

# Optimized batch insertion
def optimized_insert(conn, data):
    cursor = conn.cursor()
    
    # Use executemany for bulk inserts
    start_time = time.time()
    
    cursor.executemany(
        "INSERT INTO users (name, email, age) VALUES (?, ?, ?)",
        data
    )
    
    conn.commit()
    end_time = time.time()
    
    print(f"Inserted {len(data)} records in {end_time - start_time:.4f} seconds")

# Generate sample data
sample_data = [
    (f'User{i}', f'user{i}@example.com', 20 + i)
    for i in range(1000)
]

conn = sqlite3.connect('perf_test.db')
optimized_insert(conn, sample_data)
conn.close()

Inserted 1000 records in 0.0123 seconds

Batch operations significantly improve performance. Avoid individual inserts in loops.

Conclusion

Connecting Python to SQLite provides a powerful yet simple database solution. Key takeaways include:

  • Use sqlite3.connect() for establishing connections
  • Always commit changes with conn.commit()
  • Implement proper error handling with try-except blocks
  • Close connections using context managers or conn.close()
  • Use parameterized queries to prevent SQL injection

SQLite integrates seamlessly with Python applications. Its zero-configuration approach makes it ideal for prototyping and small to medium projects. Mastering these fundamentals enables efficient database operations in any Python project.

Explore advanced topics like PRAGMA commands, parameter styles, and SQL logging to deepen your expertise.