Skip to main content

Postgres on Angular with PGlite

· 2 min read
Moazzem Hossen
building edge, yet another Postgres backend

PGlite and Angular Signals seem an intriguing alternative to state management solutions like NgRx. The combo is particularly appealing if Postgres is already in (backend) stack.

  • Unified Queries: Same Postgres syntax frontend & backend
  • Fast Reads: Zero network for local queries
  • Signal-Driven UI: Reactivity without reducers
  • Sync Ready: Pair with remote Postgres when needed

Getting PGlite to work with Angular took some time, so I thought of documenting a minimal demo.

  1. Create a demo app
npm install -g @angular/cli@latest
NG_PROJECT_NAME=${NG_PROJECT_NAME:-"ng-pglite-demo"}
ng new --inline-style --inline-template --routing --ssr=false --style=scss $NG_PROJECT_NAME
cd $NG_PROJECT_NAME
npm install @electric-sql/pglite
  1. Update angular.json (with jq like below) or set the values manually
cp angular.json angular.json.bak

jq --arg project_name "$NG_PROJECT_NAME" \
'(.projects[$project_name].architect.build.options.allowedCommonJsDependencies += ["@electric-sql/pglite"])
| (.projects[$project_name].architect.build.configurations.production.externalDependencies += ["util"])
| (.projects[$project_name].architect.build.configurations.development.externalDependencies += ["util"])
| (.projects[$project_name].architect.serve.options.prebundle) = false
| (.projects[$project_name].architect.build.options.assets += [{"glob": "**/*", "input": "node_modules/@electric-sql/pglite/dist", "output": "/"}])' \
angular.json > tmp.json && mv tmp.json angular.json
  1. Try PGlite in a service / component eg src/app/app.component.ts with below content
import { ChangeDetectionStrategy, ChangeDetectorRef, Component, inject, OnInit } from '@angular/core';
import { PGlite } from '@electric-sql/pglite';
import { CommonModule } from '@angular/common';

@Component({
selector: 'app-root',
imports: [CommonModule],
template: `
<div>Rows
@if (rows.length === 0) {
<span>Loading...</span>
} @else {
<span>Loaded {{ rows.length }} rows</span>
<pre><code>{{ rows | json }}</code></pre>
}
</div>
`,
styles: [],
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class AppComponent implements OnInit {
private cdr = inject(ChangeDetectorRef);

db = new PGlite();
rows: any[] = [];

async ngOnInit() {
try {
await this.testDB();
} catch (err) {
console.error("Error initializing database:", err);
}
}

async testDB() {
await this.db.exec("CREATE TABLE users (id INT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY, name TEXT)");
await this.db.exec("INSERT INTO users (name) VALUES ('Alice'), ('Bob'), ('Charlie')");
const result = await this.db.query("SELECT * FROM users");
console.log("Query Result:", result);
this.rows = result.rows;
this.cdr.detectChanges();
}
}
  1. Verify
ng serve

Visit http://localhost:4200 and notice the rows of users table are rendered.