Feed

Links, thoughts, and things I'm exploring.

WASM Databases

WASM (WebAssembly) databases expand browser client-side storage options beyond the traditional options such as IndexedDB. IndexedDB provides a key-value API rather than a relational model. There have been attempts previously at client side storage with SQL syntax in browsers, such as WebSQL, which was removed from Chrome in 2022.

With WebAssembly, database engines can run directly inside the browser runtime. SQLite compiled to WASM (Sqlite3 WASM) and PGlite are the two examples of this.

Last year, Notion added a WASM implementation of SQLite to their website for caching data, which improved page load times by 20%.

PGlite brings PostgreSQL to the browser using WebAssembly. From the PGlite documentation:

PGlite is a WASM Postgres build packaged into a TypeScript/JavaScript client library, that enables you to run Postgres in the browser, Node.js and Bun, with no need to install any other dependencies. It’s under 3mb Gzipped, and has support for many Postgres extensions, including pgvector.

Supabase has a PGlite based demo at database.build, which uses IndexedDB for local persistence.

Compared to IndexedDB, these WASM databases expose a relational model with SQL queries and transactions. In the case of PGlite, this includes PostgreSQL compatible features such as extensions and listen/notify. Extensions such as pgvector enable advanced use cases like vector similarity search directly in the browser.

For persistence, these databases rely on browser-backed storage such as IndexedDB or the File System Access API (OPFS). There are some limitations around concurrency, for example PGlite runs in a single connection mode only.

Try PGlite in your browser

You can try out PGlite in your browser console:

  1. Load the browser bundle
const { PGlite } = await import(
  "https://cdn.jsdelivr.net/npm/@electric-sql/pglite/dist/index.js"
);
  1. Initialize in-memory (no persistence). Data will be wiped on page refresh
const db = new PGlite();
  1. Create a table
await db.query(`
 CREATE TABLE tasks (
   id SERIAL PRIMARY KEY,
   title TEXT NOT NULL,
   completed BOOLEAN DEFAULT FALSE
 );
`);
  1. Add some data
await db.query(
  `
  INSERT INTO tasks (title) VALUES 
    ($1), 
    ($2);
`,
  [
    "Explore PGlite Extensions",
    "Try vector similarity search with pgvector and PGlite",
  ],
);
  1. Query and display
const res = await db.query("SELECT * FROM tasks;");
console.table(res.rows);
References / Additional Resources
GitHub Actions Has a Package Manager, and It Might Be the Worst

Related HN discussion

An interesting blog post by Andrew discussing the issues around GitHub Actions’ package management. I’ve had some doubts about the versioning model in GitHub Actions for a while, and this post affirms many of those concerns. The high numbers in the linked research are not surprising at all.

Mutable versions. When you pin to actions/checkout@v4, that tag can move. The maintainer can push a new commit and retag. Your workflow changes silently.

This in my opinion is the main issue, which gives a false sense of security. The v4 you ran last month might not be the same v4 you run today, and there’s no indication that anything has changed.

Invisible transitive dependencies. SHA pinning doesn’t solve this. Composite actions resolve their own dependencies, but you can’t see or control what they pull in. When you pin an action to a SHA, you only lock the outer file. If it internally pulls some-helper@v1 with a mutable tag, your workflow is still vulnerable

So there’s little point to SHA pinning if the action itself pulls in mutable dependencies. You might as well just pin to the tag.

Interestingly, immutable releases were made generally available only this October. As for immutable actions, the issues on the roadmap for public preview and GA have been closed as not planned only few days ago.

Why should CI/CD workflows be treated any less seriously than application dependencies?

Edit: There is a community built tool gh-actions-lockfile (CLI + GitHub Action) that allows you to generate and verify a lockfile for your GitHub Actions. It seems to be inspired by the Andrew’s post. Useful solution, but I still feel it is a workaround for a problem that should be solved by GitHub natively.