How do I check in SQLite whether a table exists?
System Design practice on Codemia
Work through 120+ system design problems with detailed solutions, from rate limiters to multi-region storage.
Introduction
Query the sqlite_master (or sqlite_schema) system table and filter by type = 'table'. If the query returns a row, the table exists. In many cases, though, you should not check at all. If your goal is to create the table safely, CREATE TABLE IF NOT EXISTS is simpler and avoids the check-then-act race condition entirely.
Query the Schema Table
This is the standard existence check in SQLite:
If you prefer a boolean-style result (1 for exists, 0 for does not exist):
Starting with SQLite 3.33.0 (released August 2020), the table was aliased to sqlite_schema. Both names work in modern SQLite, but sqlite_master remains more portable if your code needs to support older versions.
Using Parameterized Queries in Application Code
When the table name comes from a variable, always use parameterized queries to prevent SQL injection. Here are examples in multiple languages.
Python:
JavaScript (better-sqlite3, Node.js):
Java (JDBC):
PRAGMA table_info as a Secondary Check
You will also see this approach:
If the table exists, SQLite returns one row per column with the column name, type, default value, and nullable flag. If the result set is empty, the table does not exist (or has no columns, which is not possible in practice).
This is useful when you also need column metadata, but it is less direct than querying the schema table when existence is the only question. It also cannot be parameterized like a regular SQL query, which makes it harder to use safely with dynamic table names.
CREATE TABLE IF NOT EXISTS
Many existence checks are written only because the code wants to create the table if it is missing. SQLite handles this in a single statement:
This is better than the two-step approach (check, then create) for several reasons:
- It is atomic. No race condition between checking and creating.
- It is one round-trip to the database instead of two.
- The code is shorter and harder to get wrong.
If the table already exists, the statement is a no-op. It does not verify that the existing table has the same schema. If you need schema validation, that is a separate concern (see PRAGMA table_info above).
Distinguishing Tables from Views and Indexes
The sqlite_master table contains all schema objects, not just tables. The type column can be table, view, index, or trigger. Without the type = 'table' filter, you might match a view or index with the same name and incorrectly conclude the table exists.
Temporary Tables
Temporary tables are stored in a separate schema catalog. If you create a table with CREATE TEMP TABLE, it will not appear in sqlite_master. Check sqlite_temp_master (or sqlite_temp_schema) instead:
If your code needs to check both regular and temporary tables, query both catalogs:
Attached Databases
When you attach a database with ATTACH DATABASE, its schema lives in a separate catalog named after the attachment alias:
The prefix before sqlite_master must match the alias you used in the ATTACH statement.
Comparison of Methods
| Method | Returns | Parameterizable | Finds Temp Tables | Best For |
SELECT FROM sqlite_master | Row if exists | Yes | No | General existence check |
SELECT EXISTS(...) | 1 or 0 | Yes | No | Boolean result in code |
PRAGMA table_info(name) | Column metadata | No | Yes | Existence + schema inspection |
CREATE TABLE IF NOT EXISTS | Nothing (DDL) | No | N/A | Safe table creation |
SELECT FROM sqlite_temp_master | Row if exists | Yes | Yes (only temp) | Temp table checks |
Common Pitfalls
Checking before creating when IF NOT EXISTS would suffice. The two-step approach adds complexity and can race in multi-threaded scenarios where two threads both check, both see "not found," and both try to create.
Forgetting type = 'table' in the filter. Without this filter, a view named users would match a query looking for a table named users. The result would be a false positive.
Using PRAGMA table_info as a general existence test. It works, but it cannot be parameterized, making it vulnerable to SQL injection if the table name comes from user input. It also returns a full result set when you only need a boolean.
Checking sqlite_master for temp tables. Temporary tables are stored in sqlite_temp_master. Checking the wrong catalog makes a table look missing when it is actually present.
Assuming schema compatibility after an existence check. CREATE TABLE IF NOT EXISTS confirms the table exists but does not verify its columns match your expected schema. A table with the right name but wrong columns will pass the check silently. Use PRAGMA table_info for schema validation.
Summary
- Query
sqlite_master(orsqlite_schema) withtype = 'table'to check whether a table exists. - Use
SELECT EXISTS(...)when you need a clean boolean result in application code. - Always use parameterized queries when the table name comes from a variable.
- Prefer
CREATE TABLE IF NOT EXISTSwhen your real goal is safe table creation. - Use
sqlite_temp_masterfor temporary tables, and prefix with the alias for attached databases. - Filter by
typeto avoid false positives from views, indexes, or triggers with the same name.
Related reading
- How do I check to see if a value is an integer in MySQL?
- How do I clone a Django model instance object and save it to the database?
- How do I Cluster Hibernate ORM Identifiers when using GenerationType.Table
- How do I configure HikariCP in my Spring Boot app in my application.properties files?
- How do I connect to a MySQL Database in Python?
- How do I connect to a MySQL Database in Python?
- How do I connect to a MySQL Database in Python?
- How do I connect to mongodb with node.js and authenticate?

System Design Fundamentals
Build a strong foundation in designing scalable, reliable distributed systems.
View the courseTrack what you have practised
A free account saves your progress, solutions and study plan across every problem on Codemia.
System Design practice on Codemia
Work through 120+ system design problems with detailed solutions, from rate limiters to multi-region storage.