Web SQL Database is a deprecated web standard for storing structured data in the browser using a SQL-based relational database. Under the hood, browsers that supported it used SQLite, so familiar SQL statements—CREATE TABLE, INSERT, SELECT, UPDATE, and DELETE—work much like server-side databases.
Although Web SQL is no longer recommended for new projects, understanding how it works is valuable for maintaining legacy applications and learning how client-side storage evolved. This page is the overview and entry point for the Web SQL series; follow-up tutorials cover each CRUD operation in depth.
What You’ll Learn
01
openDatabase
Open or create a DB.
02
Transactions
Wrap every query.
03
executeSql
Run SQL safely.
04
ResultSet
Read SELECT rows.
05
IndexedDB
Modern alternative.
Fundamentals
What Is Web SQL?
Web SQL is a browser API that lets web applications store data in a relational database on the client. You interact with it using SQL—the same language used by MySQL, PostgreSQL, and SQLite—which makes it approachable if you already know databases.
The two core methods are:
openDatabase(name, version, displayName, size) — opens an existing database or creates a new one.
db.transaction(callback) — runs one or more tx.executeSql() calls as an atomic unit.
Data persists across page reloads (until the user clears site data), making Web SQL useful for offline-first prototypes, cached records, and small local datasets—when the browser still exposes the API.
History
Why Web SQL Was Deprecated
The W3C deprecated Web SQL in 2010 and stopped pursuing it as an official standard. The main reasons were:
Single implementation — Web SQL depended on one vendor’s SQLite build, not a spec every browser could implement independently.
Inconsistent support — Firefox never shipped it; Chrome later removed it; only some Safari versions kept it.
Better alternative — IndexedDB provides a standardized, cross-browser key-value and object store without tying the web platform to SQL.
For new code in 2026, treat Web SQL as read-only knowledge—learn it to debug old apps, but build new storage on IndexedDB or server APIs.
Vocabulary
Basic Concepts
Before writing queries, know these relational-database terms:
Database — a named container for tables (opened with openDatabase).
Table — rows and columns of related data (created with CREATE TABLE).
SQL — Structured Query Language for defining schema and reading/writing rows.
Transaction — a group of statements that succeed or fail together, preserving consistency.
ResultSet — the object returned by SELECT queries; iterate with results.rows.item(i).
Setup
Creating a Database
Call openDatabase to open or create a database. The fourth argument is an estimated size in bytes (here, 2 MB). Then run CREATE TABLE inside a transaction:
js
const db = openDatabase('myDatabase', '1.0', 'My App DB', 2 * 1024 * 1024);
db.transaction(function (tx) {
tx.executeSql(
'CREATE TABLE IF NOT EXISTS contacts (id INTEGER PRIMARY KEY, name TEXT, email TEXT)'
);
});
CREATE TABLE IF NOT EXISTS is idempotent—safe to run on every page load without errors if the table already exists.
Queries
Executing SQL Queries
Use tx.executeSql(sql, params, successCallback, errorCallback) inside a transaction. Always bind dynamic values with ? placeholders instead of string concatenation:
js
db.transaction(function (tx) {
tx.executeSql(
'INSERT INTO contacts (id, name, email) VALUES (?, ?, ?)',
[1, 'Jane Doe', 'jane@example.com'],
function (tx, result) {
console.log('Inserted row, insertId:', result.insertId);
},
function (tx, error) {
console.error('Insert failed:', error.message);
return true; /* roll back transaction */
}
);
});
Every Web SQL operation must run inside db.transaction(). You can pass three callbacks to transaction itself—work, error, and success:
js
db.transaction(
function (tx) {
tx.executeSql('UPDATE contacts SET name = ? WHERE id = ?', ['Jane Smith', 1]);
},
function (error) {
console.error('Transaction failed:', error.message);
},
function () {
console.log('Transaction committed successfully');
}
);
Inside executeSql, return true from the error callback to roll back the transaction. Without it, the transaction may continue and leave data in an inconsistent state.
Reading Data
Working with Results
When you run a SELECT query, the success callback receives a ResultSet. Use results.rows.length and results.rows.item(index) to read each row:
js
db.transaction(function (tx) {
tx.executeSql(
'SELECT * FROM contacts ORDER BY name',
[],
function (tx, results) {
const len = results.rows.length;
for (let i = 0; i < len; i++) {
const row = results.rows.item(i);
console.log(row.id, row.name, row.email);
}
}
);
});
For write operations, check result.rowsAffected (updates/deletes) or result.insertId (inserts) to confirm what changed.
These examples demonstrate the Web SQL lifecycle from opening a database to reading rows. Use Try It Yourself to run live demos. If your browser does not expose openDatabase, the demo shows a clear status message.
📚 Getting Started
Open a database and set up your first table.
Example 1 — Feature Detect & Open Database
Always check for API support before calling openDatabase.
js
if (!window.openDatabase) {
console.warn('Web SQL is not supported in this browser.');
} else {
const db = openDatabase('myApp', '1.0', 'My Application', 1024 * 1024);
console.log('Database opened:', db);
}
The guard prevents runtime errors in browsers that removed Web SQL. When supported, openDatabase returns a Database object immediately—schema setup happens in the next transaction.
Example 2 — Create a Table
Define a contacts table with an integer primary key and text columns.
js
const db = openDatabase('myApp', '1.0', 'My Application', 2 * 1024 * 1024);
db.transaction(function (tx) {
tx.executeSql(
'CREATE TABLE IF NOT EXISTS contacts (' +
'id INTEGER PRIMARY KEY, name TEXT, email TEXT' +
')'
);
}, function (err) {
console.error('Setup failed:', err.message);
}, function () {
console.log('Table ready');
});
Schema changes are SQL statements like any other—they still run inside transaction. The success callback fires when the table exists and the transaction commits.
📈 CRUD Basics
Insert rows and read them back with standard SQL.
Example 3 — Insert a Row
Add a contact with bound parameters—never concatenate user input into SQL strings.
Status: Added id 1717584000123
List:
• New Contact (id 1717584000123)
How It Works
On load, the script creates the table. Each button click starts a new transaction—inserts and selects are separate atomic operations. This is the pattern most legacy Web SQL apps follow.
Applications
🚀 Common Use Cases
Offline drafts — save form data locally when the network is unavailable.
Cached catalogs — store product or article rows for faster repeat visits.
Legacy mobile web apps — maintain older Safari-based apps that still call openDatabase.
Learning SQL — experiment with relational queries without a server.
Migration planning — understand existing Web SQL schemas before moving to IndexedDB.
🧠 How Web SQL Works
1
openDatabase
Browser opens or creates a SQLite file for your origin.
Connect
2
transaction
Your callback receives a SQLTransaction object.
Wrap
3
executeSql
SQLite runs your statement with optional bound parameters.
Query
=
🗃️
Persisted data
Rows survive reloads until the user clears site storage.
Pro Tips
💡 Best Practices
✅ Do
Feature-detect with window.openDatabase
Bind all dynamic values with ? placeholders
Handle error callbacks and return true to roll back
Keep stored data small—Web SQL is for lightweight client cache
Use IndexedDB for new projects
Read the CRUD tutorials for deeper coverage
❌ Don’t
Build new features on Web SQL in 2026
Concatenate user input into SQL strings
Call executeSql outside a transaction
Store large blobs or entire media files
Assume Web SQL works in Chrome or Firefox
Skip error handling on write operations
Important
📝 Notes
Web SQL is deprecated—prefer IndexedDB for new apps.
All executeSql calls must run inside db.transaction().
Version upgrades use changeVersion() (advanced; rarely needed in tutorials).
Estimated size is a hint; browsers may enforce quotas per origin.
Clearing browser data wipes the entire Web SQL database for that site.
Web SQL was never implemented in Firefox. Chrome shipped it early but removed it in Chrome 97. Safari on iOS/macOS historically supported it on some versions. Always feature-detect with window.openDatabase before running demos or legacy code.
✓ Baseline · Since HTML
Web SQL API
Web SQL was never implemented in Firefox. Chrome shipped it early but removed it in Chrome 97. Safari on iOS/macOS historically supported it on some versions. Always feature-detect with window.openDatabase before running demos or legacy code.
25%Modern browser support
Google ChromeAll versions · Desktop & Mobile
Full support
Mozilla FirefoxAll versions · Desktop & Mobile
Full support
Apple SafariAll versions · macOS & iOS
Full support
Microsoft EdgeAll versions · Chromium & Legacy
Full support
Internet ExplorerIE 6+ · Legacy environments
Full support
OperaAll modern versions
Full support
Web SQL APIDeprecated
Bottom line: For cross-browser storage today, use IndexedDB.
Wrap Up
Conclusion
Web SQL brought familiar SQL to the browser: openDatabase to connect, transaction to wrap work, and executeSql to run statements with safe parameter bindings. You can create tables, insert rows, and read results entirely on the client.
Because the API is deprecated, treat this knowledge as essential for legacy maintenance, not greenfield development. When you are ready to go deeper, continue with the DELETE, INSERT, SELECT, and UPDATE tutorials—or start fresh with IndexedDB for modern apps.
Use these points when reading or maintaining client-side SQL code.
5
Core concepts
🗃️01
openDatabase
Connect first.
Setup
🔄02
transaction
Wrap SQL.
Required
💻03
executeSql
Run queries.
CRUD
🔒04
? bindings
Stay safe.
Security
⚠️05
Deprecated
Use IndexedDB.
Modern
❓ Frequently Asked Questions
Web SQL Database is a deprecated browser API that stores structured data in a local SQLite database. You open it with openDatabase() and run standard SQL statements (CREATE TABLE, INSERT, SELECT, UPDATE, DELETE) inside db.transaction() using tx.executeSql().
Web SQL is deprecated and removed from most modern browsers, including current Chrome. Firefox never implemented it. Treat this tutorial as educational for legacy code; use IndexedDB for new projects.
The W3C stopped standardizing Web SQL because it relied on a single vendor's SQLite implementation, making cross-browser behavior hard to guarantee. IndexedDB became the recommended client-side database API.
Call openDatabase(name, version, displayName, estimatedSize). Example: openDatabase('myApp', '1.0', 'My App DB', 2 * 1024 * 1024). The method returns a Database object or throws if Web SQL is unavailable.
The Web SQL API requires every executeSql call to run within db.transaction(). Transactions group statements atomically—if one fails, the whole transaction can roll back, keeping data consistent.
Use IndexedDB for new browser storage. It is supported across modern browsers, handles larger datasets, and works with structured JavaScript objects. localStorage is fine for simple key-value strings only.
Did you know?
Web SQL uses the same SQL dialect as SQLite, including features like INSERT OR REPLACE and CREATE TABLE IF NOT EXISTS. If you know SQLite from mobile or embedded development, most of that knowledge transfers directly to Web SQL.