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 to SQL.Database
  • After v1.0.0: You must call initSqlJs() and await the result before SQL.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

  1. Check your import statement - Are you using import initSqlJs (correct) or import SQL (incorrect for v1.0.0+)?
  2. Verify WASM file loading - Check Network tab to ensure sql-wasm.wasm loads successfully
  3. Console log the SQL object - Add console.log(SQL) before accessing SQL.Database to see what’s actually there
  4. 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.

TrackJS is the easy way to monitor your JavaScript applications and fix production errors. TrackJS is provides detailed error monitoring and alerting to developers around the world at companies like 3M, Tidal, IKEA, Venmo, Allbirds, and Frontend Masters. TrackJS catches millions of errors from users everyday. Let's start catching yours.

Protect your JavaScript