Connecting from Application Code
Every example so far in this track has been run through the sqlite3 command-line
shell. In a real app, though, RecipeBox's SQL runs from inside actual application code — a
Python script, a PHP backend, a Node service, or an Android app. This lesson shows short, correct
snippets for connecting and querying from several of the most common environments, all using
parameterized queries as covered in the previous lesson.
Python — the Built-In sqlite3 Module
Python ships SQLite support in its standard library — no install required. Connecting opens (or creates) the database file directly.
# connect.py
import sqlite3
conn = sqlite3.connect('recipebox.db')
cursor = conn.cursor()
# Parameterized query: the ? is bound safely, never string-concatenated
cursor.execute(
"SELECT id, title FROM recipes WHERE user_id = ?",
(user_id,)
)
for row in cursor.fetchall():
print(row)
conn.close()
sqlite3 module uses ? placeholders (or named placeholders like :user_id) — never Python's own string formatting (f"...", %, .format()) to build a query with user input.PHP — PDO
This site is built on PHP, and PHP's PDO (PHP Data Objects) extension talks to
SQLite the same way it talks to MySQL or PostgreSQL — one consistent API across drivers,
just with a different connection string.
// connect.php
$pdo = new PDO('sqlite:recipebox.db');
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
// Parameterized query using a named placeholder
$stmt = $pdo->prepare('SELECT id, title FROM recipes WHERE user_id = :user_id');
$stmt->execute(['user_id' => $userId]);
foreach ($stmt->fetchAll(PDO::FETCH_ASSOC) as $recipe) {
echo $recipe['title'] . "\n";
}
$pdo->prepare() plus execute() with bound values is exactly the
parameterized-query pattern from the previous lesson — PDO handles the escaping, so
$userId is never pasted directly into the SQL string.
Node.js — better-sqlite3
better-sqlite3 is a popular Node package for talking to SQLite — synchronous
and fast, which fits SQLite's local, embedded nature well (there's no network round-trip to wait
on asynchronously).
// connect.js
const Database = require('better-sqlite3');
const db = new Database('recipebox.db');
// Parameterized query using a ? placeholder
const recipes = db.prepare('SELECT id, title FROM recipes WHERE user_id = ?').all(userId);
for (const recipe of recipes) {
console.log(recipe.title);
}
Android / Java — SQLiteOpenHelper and Room
SQLite is built directly into Android — every Android device already has the engine on board. There are two common ways to use it from app code:
SQLiteOpenHelper— Android's lower-level, direct API. You write raw SQL yourself and manage the connection lifecycle by hand.- Room — the modern, recommended persistence library built on top of SQLite. You define entities and DAOs with annotations, and Room generates the SQL (including parameterized queries) for you at compile time.
// A Room DAO method — Room generates the parameterized SQL underneath
@Query("SELECT * FROM recipes WHERE user_id = :userId")
List<Recipe> getRecipesForUser(int userId);
The Pattern That Stays the Same Everywhere
Notice that every snippet above follows the same shape, regardless of language: open a
connection to the .db file, write SQL with placeholders instead of concatenated
values, and pass the real values separately so the driver binds them safely. That consistency is
one of SQLite's biggest practical strengths — the SQL you've learned throughout this track
transfers directly, no matter which language ends up calling it.