The Python API

DuckDB · Essentials · 10 min

Most people use DuckDB from Python scripts and notebooks, so this is the everyday interface.

pip install duckdb gives you everything; there are no other dependencies. Two entry points:

  • duckdb.sql(query) runs on a shared default in-memory database. Handy in notebooks.
  • con = duckdb.connect("file.duckdb") (or connect() for in-memory) gives you an explicit connection. Use this in real programs and close it with con.close() or a with block.

sql() returns a lazy relation: nothing runs until you print it or fetch. fetchall() returns a list of tuples, fetchone() a single tuple, and .show() prints a table. Relations can be chained or queried again, which makes building a query step by step natural.

con.execute(query, params) runs a statement immediately and supports prepared parameters with ? or $name placeholders. Always pass values this way rather than formatting them into the SQL string; it avoids injection and quoting bugs. executemany runs one statement for many parameter rows, but for bulk loading it is far faster to insert from a DataFrame or a file.

A connection is not meant to be shared by several threads at once; give each thread its own con.cursor().

Example

import duckdb

with duckdb.connect() as con:            # in-memory database
    con.execute("CREATE TABLE users (id INT, name TEXT, age INT)")
    con.executemany("INSERT INTO users VALUES (?, ?, ?)",
                    [(1, "Ann", 34), (2, "Bob", 19), (3, "Cy", 52)])

    rows = con.execute("SELECT name FROM users WHERE age > ? ORDER BY name",
                       [30]).fetchall()
    print(rows)                          # [('Ann',), ('Cy',)]

    rel = con.sql("SELECT avg(age) AS avg_age FROM users")
    print(rel.fetchone())                # (35.0,)

Remember

  • duckdb.sql uses a default in-memory database; duckdb.connect gives an explicit one
  • Relations are lazy until fetched or shown
  • Pass values with ? or $name parameters, never string formatting
  • Use one cursor per thread

Watch out for

  • Building SQL with f-strings from user input, which breaks on quotes and invites injection.

Check yourself

  1. What does `duckdb.sql('SELECT 1')` return before you call fetchall()?

Sign in to answer, see the explanations, and get this lesson back as a quick review later.

Official docs: duckdb.org/docs/current/clients/python/overview