If you’re building a browser-based SQLite application and suddenly hit this error, you’ve stumbled into one of the most common pitfalls when using SQL.js. The error typically appears when upgrading SQL.js versions or integrating it with ORMs like TypeORM.
The Error
The error will be recorded as:
TypeError: Cannot read properties of undefined (reading 'Database')
What’s Actually Happening
This error occurs when your code tries to access SQL.Database
before SQL.js has finished loading. Prior to version 1.0.0, SQL.js loaded synchronously, but modern versions require asynchronous initialization to handle WebAssembly loading. Your code is trying to create a database instance from an undefined SQL object.
The error commonly appears in two scenarios:
Direct SQL.js usage:
import SQL from 'sql.js';
const db = new SQL.Database(); // TypeError: Cannot read properties of undefined
TypeORM with SQL.js driver:
const dataSource = new DataSource({
type: 'sqljs',
entities: [User],
synchronize: true
});
await dataSource.initialize(); // Error occurs inside TypeORM
Understanding the Root Cause
The Breaking Change in SQL.js v1.0.0+
SQL.js underwent a major architectural change when it moved to WebAssembly. The library now needs to asynchronously load a .wasm
file before the SQL object becomes available. This caught many developers off guard because older tutorials and code examples show synchronous usage.
What changed:
- Before v1.0.0:
import SQL from 'sql.js'
gave you immediate access toSQL.Database
- After v1.0.0: You must call
initSqlJs()
and await the result beforeSQL.Database
exists
TypeORM Integration Issues
When using TypeORM with the SQL.js driver, the error often appears deep in TypeORM’s internal code:
TypeError: Cannot read properties of undefined (reading 'Database')
at SqljsDriver.js:214:52
TypeORM expects SQL.js to be available globally or properly initialized, but if that hasn’t happened, it tries to access undefined.Database
.
Environment-Specific Problems
The error frequently appears in:
- Ionic/Cordova apps when running in browser mode (works fine on device)
- Electron applications due to module loading conflicts
- Webpack builds missing proper WASM file handling
- Angular apps with incorrect module imports
How to Fix “Cannot read properties of undefined (reading ‘Database’)”
Fix 1: Properly Initialize SQL.js (Direct Usage)
For direct SQL.js usage, always use the async initialization pattern:
import initSqlJs from 'sql.js';
// Initialize SQL.js first
const SQL = await initSqlJs({
// Required: specify where to find the WASM file
locateFile: file => `https://sql.js.org/dist/${file}`
});
// Now you can safely create databases
const db = new SQL.Database();
// Run queries
db.run("CREATE TABLE test (id INT, name TEXT)");
const stmt = db.prepare("SELECT * FROM test");
stmt.getAsObject();
Common mistake: Forgetting to specify locateFile
causes the WASM file to fail loading silently.
Fix 2: TypeORM + SQL.js Integration
TypeORM requires SQL.js to be initialized before creating the data source:
import { DataSource } from 'typeorm';
import initSqlJs from 'sql.js';
// Step 1: Initialize SQL.js
const SQL = await initSqlJs({
locateFile: file => `/assets/${file}` // Adjust path as needed
});
// Step 2: Make SQL available globally (TypeORM looks for it here)
window.SQL = SQL;
// Step 3: Now create your TypeORM data source
const dataSource = new DataSource({
type: 'sqljs',
autoSave: true,
location: 'browser',
logging: true,
synchronize: true,
entities: [/* your entities */]
});
// Step 4: Initialize the data source
await dataSource.initialize();
Fix 3: Webpack Configuration
If you’re bundling with Webpack, you need special configuration to handle the WASM file:
// webpack.config.js
const CopyPlugin = require('copy-webpack-plugin');
module.exports = {
module: {
rules: [
{
test: /\.wasm$/,
type: 'webassembly/async'
}
],
// Prevent Webpack from parsing the pre-built SQL.js file
noParse: /node_modules\/sql\.js\/dist\/sql-wasm\.js$/
},
plugins: [
// Copy WASM file to output directory
new CopyPlugin({
patterns: [
{
from: 'node_modules/sql.js/dist/sql-wasm.wasm',
to: 'sql-wasm.wasm'
}
]
})
],
experiments: {
asyncWebAssembly: true
}
};
Fix 4: Angular/Ionic Applications
For Angular applications, create a service to manage SQL.js initialization:
import { Injectable } from '@angular/core';
import initSqlJs from 'sql.js';
@Injectable({
providedIn: 'root'
})
export class DatabaseService {
private SQL: any;
private db: any;
async initializeDatabase() {
if (!this.SQL) {
this.SQL = await initSqlJs({
locateFile: file => `assets/sql-js/${file}`
});
}
this.db = new this.SQL.Database();
return this.db;
}
async query(sql: string) {
if (!this.db) {
await this.initializeDatabase();
}
return this.db.exec(sql);
}
}
Fix 5: Electron Applications
In Electron, you might need to handle both main and renderer process scenarios:
// In renderer process or preload script
import initSqlJs from 'sql.js';
async function setupDatabase() {
const SQL = await initSqlJs({
// Use file:// protocol for local WASM file
locateFile: file => {
if (file.endsWith('.wasm')) {
return `file://${__dirname}/sql-wasm.wasm`;
}
return file;
}
});
return new SQL.Database();
}
Quick Debugging Steps
- Check your import statement - Are you using
import initSqlJs
(correct) orimport SQL
(incorrect for v1.0.0+)? - Verify WASM file loading - Check Network tab to ensure sql-wasm.wasm loads successfully
- Console log the SQL object - Add
console.log(SQL)
before accessingSQL.Database
to see what’s actually there - Check TypeORM version compatibility - Some older TypeORM versions don’t support newer SQL.js versions
Prevention Best Practices
Always use async/await with SQL.js:
// Create a reusable database module
let SQLModule = null;
export async function getDatabase() {
if (!SQLModule) {
SQLModule = await initSqlJs({
locateFile: file => `/path/to/${file}`
});
}
return new SQLModule.Database();
}
// Use it anywhere
const db = await getDatabase();
For TypeORM users, initialize SQL.js in your app’s entry point:
// main.ts or index.ts
import initSqlJs from 'sql.js';
async function bootstrap() {
// Initialize SQL.js before anything else
window.SQL = await initSqlJs({
locateFile: file => `/assets/${file}`
});
// Now initialize your app
// TypeORM connections will work properly
}
bootstrap();
Monitor Database Errors in Production
While these fixes will resolve most SQL.js initialization issues during development, you need visibility into what’s happening in production. Users might encounter edge cases like:
- WASM files failing to load due to network issues
- Browser-specific WebAssembly incompatibilities
- Race conditions in complex applications
Error monitoring services like TrackJS automatically capture these “Cannot read properties of undefined” errors along with the full stack trace, browser details, and user actions leading up to the error. This gives you the context needed to identify patterns - like if the error only happens on certain browsers or after specific user workflows.
Without production monitoring, you’re flying blind and relying on user reports to know when your database initialization fails.
Summary
The “Cannot read properties of undefined (reading ‘Database’)” error is a telltale sign that SQL.js hasn’t finished initializing before you try to use it. This became a common issue after SQL.js v1.0.0 switched to asynchronous loading for WebAssembly support.
The fix is straightforward: always await initSqlJs()
before accessing SQL.Database
. For TypeORM users, ensure SQL.js is initialized and available globally before creating your data source. With proper initialization and the right build configuration, you can run SQLite smoothly in any browser-based JavaScript application.