pgserve 0.1.4 → 1.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude/settings.local.json +11 -0
- package/README.md +281 -256
- package/bin/pglite-server.js +212 -395
- package/package.json +13 -10
- package/src/cluster.js +322 -0
- package/src/index.js +8 -171
- package/src/postgres.js +479 -0
- package/src/protocol.js +49 -10
- package/src/router.js +117 -114
- package/src/sync.js +344 -0
- package/tests/benchmarks/runner.js +300 -155
- package/tests/sync-perf-test.js +150 -0
- package/src/detector.js +0 -105
- package/src/pool.js +0 -320
- package/src/ports.js +0 -114
- package/src/registry.js +0 -134
- package/src/server.js +0 -265
package/README.md
CHANGED
|
@@ -1,323 +1,348 @@
|
|
|
1
|
-
|
|
1
|
+
<div align="center">
|
|
2
|
+
<h1>pgserve</h1>
|
|
3
|
+
<p><strong>Embedded PostgreSQL Server with TRUE Concurrent Connections</strong></p>
|
|
2
4
|
|
|
3
|
-
|
|
5
|
+
<p>
|
|
6
|
+
<a href="https://www.npmjs.com/package/pgserve"><img src="https://img.shields.io/npm/v/pgserve?style=flat-square&color=00D9FF" alt="npm version"></a>
|
|
7
|
+
<img src="https://img.shields.io/badge/node-%3E%3D18.0.0-brightgreen?style=flat-square" alt="Node.js">
|
|
8
|
+
<img src="https://img.shields.io/badge/PostgreSQL-17.7-blue?style=flat-square" alt="PostgreSQL">
|
|
9
|
+
<a href="LICENSE"><img src="https://img.shields.io/badge/license-MIT-green?style=flat-square" alt="License"></a>
|
|
10
|
+
<a href="https://discord.gg/xcW8c7fF3R"><img src="https://img.shields.io/discord/1095114867012292758?style=flat-square&color=00D9FF&label=discord" alt="Discord"></a>
|
|
11
|
+
</p>
|
|
4
12
|
|
|
5
|
-
|
|
13
|
+
<p><em>Zero config, auto-provision databases, unlimited concurrent connections. Just works.</em></p>
|
|
6
14
|
|
|
7
|
-
|
|
15
|
+
<p>
|
|
16
|
+
<a href="#-quick-start">Quick Start</a> •
|
|
17
|
+
<a href="#-features">Features</a> •
|
|
18
|
+
<a href="#-cli-reference">CLI</a> •
|
|
19
|
+
<a href="#-api">API</a> •
|
|
20
|
+
<a href="#-performance">Performance</a>
|
|
21
|
+
</p>
|
|
22
|
+
</div>
|
|
8
23
|
|
|
9
|
-
|
|
10
|
-
- 🚀 **Auto-Provisioning** - Databases created on demand from connection string
|
|
11
|
-
- 🔌 **Single Endpoint** - `postgresql://localhost:8432/dbname` routes to correct PGlite instance
|
|
12
|
-
- ⚡ **High Performance** - MVCC, row-level locking, concurrent writes
|
|
13
|
-
- 🎛️ **Zero Configuration** - Auto-tuned for your hardware (CPU, RAM)
|
|
14
|
-
- 📦 **PostgreSQL Compatible** - Works with any PostgreSQL client (psql, Prisma, pg, etc.)
|
|
15
|
-
- 🛡️ **Data Isolation** - Each database = separate PGlite instance
|
|
16
|
-
- 💾 **Persistent** - Data survives restarts
|
|
24
|
+
<br>
|
|
17
25
|
|
|
18
|
-
##
|
|
19
|
-
|
|
20
|
-
### Perfect For
|
|
21
|
-
|
|
22
|
-
- 🤖 **AI Agents** - Each agent gets isolated database (sessions, memory, state)
|
|
23
|
-
- 👥 **Multi-User Apps** - One database per user, single endpoint
|
|
24
|
-
- 🏢 **SaaS Applications** - Tenant isolation without infrastructure complexity
|
|
25
|
-
- 🧪 **Development** - Local PostgreSQL without Docker
|
|
26
|
-
- 📱 **Desktop Apps** - Electron, Tauri with embedded multi-tenant DB
|
|
27
|
-
|
|
28
|
-
### Real-World Examples
|
|
29
|
-
|
|
30
|
-
- **AI Agent Swarms**: 100+ agents, each with isolated database
|
|
31
|
-
- **Multi-Tenant SaaS**: Single endpoint, automatic tenant provisioning
|
|
32
|
-
- **Desktop Apps**: Embedded PostgreSQL with multi-user support
|
|
33
|
-
|
|
34
|
-
## 🚀 Quick Start
|
|
35
|
-
|
|
36
|
-
### Installation
|
|
26
|
+
## Quick Start
|
|
37
27
|
|
|
38
28
|
```bash
|
|
39
|
-
|
|
40
|
-
# or
|
|
41
|
-
pnpm add pgserve
|
|
42
|
-
```
|
|
43
|
-
|
|
44
|
-
### Multi-Tenant Mode (Recommended)
|
|
45
|
-
|
|
46
|
-
```javascript
|
|
47
|
-
import { startMultiTenantServer } from 'pgserve';
|
|
48
|
-
|
|
49
|
-
// Start multi-tenant router on single port
|
|
50
|
-
const router = await startMultiTenantServer({
|
|
51
|
-
port: 8432, // Single port for all databases
|
|
52
|
-
baseDir: './data', // Base directory (creates ./data/dbname/ per DB)
|
|
53
|
-
autoProvision: true, // Auto-create databases (default: true)
|
|
54
|
-
maxInstances: 100, // Max concurrent databases
|
|
55
|
-
logLevel: 'info'
|
|
56
|
-
});
|
|
57
|
-
|
|
58
|
-
// Clients connect like normal PostgreSQL:
|
|
59
|
-
// postgresql://localhost:8432/user123 → ./data/user123/
|
|
60
|
-
// postgresql://localhost:8432/app456 → ./data/app456/
|
|
61
|
-
```
|
|
62
|
-
|
|
63
|
-
### Usage with PostgreSQL Clients
|
|
64
|
-
|
|
65
|
-
```javascript
|
|
66
|
-
import pg from 'pg';
|
|
67
|
-
|
|
68
|
-
// Connect to database "user123" (auto-created)
|
|
69
|
-
const client1 = new pg.Client({
|
|
70
|
-
connectionString: 'postgresql://localhost:8432/user123'
|
|
71
|
-
});
|
|
72
|
-
|
|
73
|
-
await client1.connect();
|
|
74
|
-
await client1.query('CREATE TABLE users (id SERIAL, name TEXT)');
|
|
75
|
-
await client1.query("INSERT INTO users (name) VALUES ('Alice')");
|
|
76
|
-
|
|
77
|
-
// Connect to database "app456" (different isolated instance)
|
|
78
|
-
const client2 = new pg.Client({
|
|
79
|
-
connectionString: 'postgresql://localhost:8432/app456'
|
|
80
|
-
});
|
|
81
|
-
|
|
82
|
-
await client2.connect();
|
|
83
|
-
await client2.query('CREATE TABLE posts (id SERIAL, title TEXT)');
|
|
84
|
-
|
|
85
|
-
// Each database is completely isolated!
|
|
29
|
+
npx pgserve
|
|
86
30
|
```
|
|
87
31
|
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
```javascript
|
|
91
|
-
// prisma/schema.prisma
|
|
92
|
-
datasource db {
|
|
93
|
-
provider = "postgresql"
|
|
94
|
-
url = env("DATABASE_URL")
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
// .env
|
|
98
|
-
DATABASE_URL="postgresql://localhost:8432/myapp"
|
|
99
|
-
```
|
|
32
|
+
Connect from any PostgreSQL client — databases auto-create on first connection:
|
|
100
33
|
|
|
101
34
|
```bash
|
|
102
|
-
|
|
103
|
-
npx prisma migrate dev
|
|
35
|
+
psql postgresql://localhost:5432/myapp
|
|
104
36
|
```
|
|
105
37
|
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
38
|
+
<br>
|
|
39
|
+
|
|
40
|
+
## Features
|
|
41
|
+
|
|
42
|
+
<table>
|
|
43
|
+
<tr>
|
|
44
|
+
<td><b>Unlimited Concurrency</b></td>
|
|
45
|
+
<td>Native PostgreSQL process forking — no connection locks</td>
|
|
46
|
+
</tr>
|
|
47
|
+
<tr>
|
|
48
|
+
<td><b>Zero Config</b></td>
|
|
49
|
+
<td>Just run <code>pgserve</code>, connect to any database name</td>
|
|
50
|
+
</tr>
|
|
51
|
+
<tr>
|
|
52
|
+
<td><b>Auto-Provision</b></td>
|
|
53
|
+
<td>Databases created automatically on first connection</td>
|
|
54
|
+
</tr>
|
|
55
|
+
<tr>
|
|
56
|
+
<td><b>Memory Mode</b></td>
|
|
57
|
+
<td>Fast and ephemeral for development (default)</td>
|
|
58
|
+
</tr>
|
|
59
|
+
<tr>
|
|
60
|
+
<td><b>Persistent Mode</b></td>
|
|
61
|
+
<td>Use <code>--data ./path</code> for durable storage</td>
|
|
62
|
+
</tr>
|
|
63
|
+
<tr>
|
|
64
|
+
<td><b>Async Replication</b></td>
|
|
65
|
+
<td>Sync to real PostgreSQL with zero performance impact</td>
|
|
66
|
+
</tr>
|
|
67
|
+
<tr>
|
|
68
|
+
<td><b>Cross-Platform</b></td>
|
|
69
|
+
<td>Linux x64, macOS ARM64/x64, Windows x64</td>
|
|
70
|
+
</tr>
|
|
71
|
+
<tr>
|
|
72
|
+
<td><b>Any Client Works</b></td>
|
|
73
|
+
<td>psql, node-postgres, Prisma, Drizzle, TypeORM</td>
|
|
74
|
+
</tr>
|
|
75
|
+
</table>
|
|
76
|
+
|
|
77
|
+
<br>
|
|
78
|
+
|
|
79
|
+
## Installation
|
|
109
80
|
|
|
110
|
-
|
|
81
|
+
```bash
|
|
82
|
+
# Zero install (recommended)
|
|
83
|
+
npx pgserve
|
|
111
84
|
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
port: 8432, // Port to listen on (default: 8432)
|
|
115
|
-
host: '127.0.0.1', // Host to bind (default: 127.0.0.1)
|
|
116
|
-
baseDir: './data', // Base data directory (default: './data')
|
|
117
|
-
autoProvision: true, // Auto-create databases (default: true)
|
|
118
|
-
maxInstances: 100, // Max concurrent databases (default: 100)
|
|
119
|
-
logLevel: 'info', // Log level: error, warn, info, debug (default: 'info')
|
|
120
|
-
inspect: false // Enable wire protocol debugging (default: false)
|
|
121
|
-
});
|
|
85
|
+
# Global install
|
|
86
|
+
npm install -g pgserve
|
|
122
87
|
|
|
123
|
-
|
|
88
|
+
# Project dependency
|
|
89
|
+
npm install pgserve
|
|
124
90
|
```
|
|
125
91
|
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
```javascript
|
|
129
|
-
// Get router stats
|
|
130
|
-
const stats = router.getStats();
|
|
131
|
-
// {
|
|
132
|
-
// port: 8432,
|
|
133
|
-
// activeConnections: 2,
|
|
134
|
-
// pool: {
|
|
135
|
-
// totalInstances: 3,
|
|
136
|
-
// maxInstances: 100,
|
|
137
|
-
// instances: [...]
|
|
138
|
-
// }
|
|
139
|
-
// }
|
|
140
|
-
|
|
141
|
-
// List all databases
|
|
142
|
-
const databases = router.listDatabases();
|
|
143
|
-
// [
|
|
144
|
-
// { dbName: 'user123', locked: false, queueLength: 0, ... },
|
|
145
|
-
// { dbName: 'app456', locked: true, queueLength: 1, ... }
|
|
146
|
-
// ]
|
|
147
|
-
|
|
148
|
-
// Stop router (closes all instances)
|
|
149
|
-
await router.stop();
|
|
150
|
-
```
|
|
92
|
+
> PostgreSQL binaries are automatically downloaded on first run.
|
|
151
93
|
|
|
152
|
-
|
|
94
|
+
<br>
|
|
153
95
|
|
|
154
|
-
|
|
96
|
+
## CLI Reference
|
|
155
97
|
|
|
156
98
|
```
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
│ ├─ app456 → PGlite('./data/app456') │
|
|
172
|
-
│ └─ tenant789 → PGlite('./data/tenant789') │
|
|
173
|
-
└────────────────────────────────────────┘
|
|
99
|
+
pgserve [options]
|
|
100
|
+
|
|
101
|
+
Options:
|
|
102
|
+
--port <number> PostgreSQL port (default: 5432)
|
|
103
|
+
--data <path> Data directory for persistence (default: in-memory)
|
|
104
|
+
--host <host> Host to bind to (default: 127.0.0.1)
|
|
105
|
+
--log <level> Log level: error, warn, info, debug (default: info)
|
|
106
|
+
--cluster Force cluster mode (auto-enabled on multi-core)
|
|
107
|
+
--no-cluster Force single-process mode
|
|
108
|
+
--workers <n> Number of worker processes (default: CPU cores)
|
|
109
|
+
--no-provision Disable auto-provisioning of databases
|
|
110
|
+
--sync-to <url> Sync to real PostgreSQL (async replication)
|
|
111
|
+
--sync-databases <p> Database patterns to sync (comma-separated)
|
|
112
|
+
--help Show help message
|
|
174
113
|
```
|
|
175
114
|
|
|
176
|
-
|
|
115
|
+
<details>
|
|
116
|
+
<summary><b>Examples</b></summary>
|
|
177
117
|
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
4. **Auto-provision** creates `./data/myapp/` if doesn't exist
|
|
182
|
-
5. **Route connection** to PGlite instance
|
|
183
|
-
6. **Client communicates** with isolated database
|
|
118
|
+
```bash
|
|
119
|
+
# Development (memory mode, auto-clusters on multi-core)
|
|
120
|
+
pgserve
|
|
184
121
|
|
|
185
|
-
|
|
122
|
+
# Persistent storage
|
|
123
|
+
pgserve --data /var/lib/pgserve
|
|
186
124
|
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
- **Concurrent connections**: Queued (PGlite is single-connection per instance)
|
|
190
|
-
- **Connection closes**: Instance unlocked, ready for next connection
|
|
125
|
+
# Custom port
|
|
126
|
+
pgserve --port 5433
|
|
191
127
|
|
|
192
|
-
|
|
128
|
+
# Sync to production PostgreSQL
|
|
129
|
+
pgserve --sync-to "postgresql://user:pass@db.example.com:5432/prod"
|
|
130
|
+
```
|
|
193
131
|
|
|
194
|
-
|
|
132
|
+
</details>
|
|
195
133
|
|
|
196
|
-
|
|
197
|
-
|----------|-----------|------------|-------------|
|
|
198
|
-
| **Multi-tenant** | 1 | Auto | ✅ Excellent (100+ DBs) |
|
|
199
|
-
| Multi-port | 1 per DB | Manual | ⚠️ Limited (port exhaustion) |
|
|
134
|
+
<br>
|
|
200
135
|
|
|
201
|
-
|
|
136
|
+
## API
|
|
202
137
|
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
- **Concurrent databases**: Tested with 100+ isolated instances
|
|
206
|
-
- **Memory**: ~10-30MB per PGlite instance (depends on data)
|
|
138
|
+
```javascript
|
|
139
|
+
import { startMultiTenantServer } from 'pgserve';
|
|
207
140
|
|
|
208
|
-
|
|
141
|
+
const server = await startMultiTenantServer({
|
|
142
|
+
port: 5432,
|
|
143
|
+
host: '127.0.0.1',
|
|
144
|
+
baseDir: null, // null = memory mode
|
|
145
|
+
logLevel: 'info',
|
|
146
|
+
autoProvision: true,
|
|
147
|
+
syncTo: null, // Optional: PostgreSQL URL for replication
|
|
148
|
+
syncDatabases: null // Optional: patterns like "myapp,tenant_*"
|
|
149
|
+
});
|
|
209
150
|
|
|
210
|
-
|
|
151
|
+
// Get stats
|
|
152
|
+
console.log(server.getStats());
|
|
211
153
|
|
|
212
|
-
|
|
213
|
-
|
|
154
|
+
// Graceful shutdown
|
|
155
|
+
await server.stop();
|
|
214
156
|
```
|
|
215
157
|
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
```bash
|
|
219
|
-
# Start multi-tenant router
|
|
220
|
-
pgserve start --port 8432 --dir ./data
|
|
221
|
-
|
|
222
|
-
# Check router status
|
|
223
|
-
pgserve router-stats
|
|
224
|
-
|
|
225
|
-
# List all databases
|
|
226
|
-
pgserve list-databases
|
|
158
|
+
<br>
|
|
227
159
|
|
|
228
|
-
|
|
229
|
-
pgserve stop-router
|
|
230
|
-
```
|
|
160
|
+
## Framework Integration
|
|
231
161
|
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
### Custom Instance Pool
|
|
162
|
+
<details>
|
|
163
|
+
<summary><b>node-postgres</b></summary>
|
|
235
164
|
|
|
236
165
|
```javascript
|
|
237
|
-
import
|
|
166
|
+
import pg from 'pg';
|
|
238
167
|
|
|
239
|
-
const
|
|
240
|
-
|
|
241
|
-
maxInstances: 50,
|
|
242
|
-
autoProvision: true
|
|
168
|
+
const client = new pg.Client({
|
|
169
|
+
connectionString: 'postgresql://localhost:5432/myapp'
|
|
243
170
|
});
|
|
244
171
|
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
172
|
+
await client.connect();
|
|
173
|
+
await client.query('CREATE TABLE users (id SERIAL, name TEXT)');
|
|
174
|
+
await client.query("INSERT INTO users (name) VALUES ('Alice')");
|
|
175
|
+
const result = await client.query('SELECT * FROM users');
|
|
176
|
+
console.log(result.rows);
|
|
177
|
+
await client.end();
|
|
250
178
|
```
|
|
251
179
|
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
PGlite is **single-connection** per instance. When multiple clients connect to the same database:
|
|
255
|
-
|
|
256
|
-
```javascript
|
|
257
|
-
// Client 1 connects to "mydb" → locks instance
|
|
258
|
-
const client1 = new pg.Client({ database: 'mydb', ... });
|
|
259
|
-
await client1.connect(); // ✅ Connected
|
|
260
|
-
|
|
261
|
-
// Client 2 tries to connect to "mydb" → queued
|
|
262
|
-
const client2 = new pg.Client({ database: 'mydb', ... });
|
|
263
|
-
await client2.connect(); // ⏳ Waits for client1 to disconnect
|
|
180
|
+
</details>
|
|
264
181
|
|
|
265
|
-
|
|
266
|
-
|
|
182
|
+
<details>
|
|
183
|
+
<summary><b>Prisma</b></summary>
|
|
267
184
|
|
|
268
|
-
|
|
269
|
-
//
|
|
185
|
+
```prisma
|
|
186
|
+
// prisma/schema.prisma
|
|
187
|
+
datasource db {
|
|
188
|
+
provider = "postgresql"
|
|
189
|
+
url = env("DATABASE_URL")
|
|
190
|
+
}
|
|
270
191
|
```
|
|
271
192
|
|
|
272
|
-
|
|
193
|
+
```bash
|
|
194
|
+
# .env
|
|
195
|
+
DATABASE_URL="postgresql://localhost:5432/myapp"
|
|
273
196
|
|
|
274
|
-
|
|
275
|
-
|
|
197
|
+
# Run migrations
|
|
198
|
+
npx prisma migrate dev
|
|
276
199
|
```
|
|
277
200
|
|
|
278
|
-
|
|
201
|
+
</details>
|
|
279
202
|
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
- **Production**: Use proper PostgreSQL for external access
|
|
203
|
+
<details>
|
|
204
|
+
<summary><b>Drizzle</b></summary>
|
|
283
205
|
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
./data/
|
|
288
|
-
├─ user123/ (PGlite data for "user123" database)
|
|
289
|
-
│ ├─ base/
|
|
290
|
-
│ ├─ pg_wal/
|
|
291
|
-
│ └─ PG_VERSION
|
|
292
|
-
├─ app456/ (PGlite data for "app456" database)
|
|
293
|
-
└─ tenant789/ (PGlite data for "tenant789" database)
|
|
294
|
-
```
|
|
206
|
+
```typescript
|
|
207
|
+
import { drizzle } from 'drizzle-orm/node-postgres';
|
|
208
|
+
import { Pool } from 'pg';
|
|
295
209
|
|
|
296
|
-
|
|
210
|
+
const pool = new Pool({
|
|
211
|
+
connectionString: 'postgresql://localhost:5432/myapp'
|
|
212
|
+
});
|
|
297
213
|
|
|
298
|
-
|
|
214
|
+
const db = drizzle(pool);
|
|
215
|
+
const users = await db.select().from(usersTable);
|
|
216
|
+
```
|
|
299
217
|
|
|
300
|
-
|
|
301
|
-
2. Create a feature branch
|
|
302
|
-
3. Add tests for new features
|
|
303
|
-
4. Submit a pull request
|
|
218
|
+
</details>
|
|
304
219
|
|
|
305
|
-
|
|
220
|
+
<br>
|
|
306
221
|
|
|
307
|
-
|
|
222
|
+
## Async Replication
|
|
308
223
|
|
|
309
|
-
|
|
224
|
+
Sync ephemeral pgserve data to a real PostgreSQL database. Uses native logical replication for **zero performance impact** on the hot path.
|
|
310
225
|
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
-
|
|
226
|
+
```bash
|
|
227
|
+
# Sync all databases
|
|
228
|
+
pgserve --sync-to "postgresql://user:pass@db.example.com:5432/mydb"
|
|
314
229
|
|
|
315
|
-
|
|
230
|
+
# Sync specific databases (supports wildcards)
|
|
231
|
+
pgserve --sync-to "postgresql://..." --sync-databases "myapp,tenant_*"
|
|
232
|
+
```
|
|
316
233
|
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
234
|
+
> Replication is handled by PostgreSQL's WAL writer process, completely off the Node.js event loop. Sync failures don't affect main server operation.
|
|
235
|
+
|
|
236
|
+
<br>
|
|
237
|
+
|
|
238
|
+
## Performance
|
|
239
|
+
|
|
240
|
+
<table>
|
|
241
|
+
<tr>
|
|
242
|
+
<th>Scenario</th>
|
|
243
|
+
<th>SQLite</th>
|
|
244
|
+
<th>PGlite</th>
|
|
245
|
+
<th>Docker PG</th>
|
|
246
|
+
<th>pgserve</th>
|
|
247
|
+
</tr>
|
|
248
|
+
<tr>
|
|
249
|
+
<td><b>Concurrent Writes</b> (10 agents)</td>
|
|
250
|
+
<td>100 qps</td>
|
|
251
|
+
<td>219 qps</td>
|
|
252
|
+
<td>758 qps</td>
|
|
253
|
+
<td><b>855 qps 🏆</b></td>
|
|
254
|
+
</tr>
|
|
255
|
+
<tr>
|
|
256
|
+
<td><b>Mixed Workload</b> (messages)</td>
|
|
257
|
+
<td>335 qps</td>
|
|
258
|
+
<td>506 qps</td>
|
|
259
|
+
<td>940 qps</td>
|
|
260
|
+
<td><b>1034 qps 🏆</b></td>
|
|
261
|
+
</tr>
|
|
262
|
+
<tr>
|
|
263
|
+
<td><b>Write Lock</b> (50 writers)</td>
|
|
264
|
+
<td>98 qps</td>
|
|
265
|
+
<td>201 qps</td>
|
|
266
|
+
<td><b>478 qps 🏆</b></td>
|
|
267
|
+
<td>391 qps</td>
|
|
268
|
+
</tr>
|
|
269
|
+
</table>
|
|
270
|
+
|
|
271
|
+
> pgserve beats Docker PostgreSQL in 2/3 scenarios. For development, CI/CD, and ephemeral deployments — better-than-Docker performance without Docker.
|
|
272
|
+
>
|
|
273
|
+
> Run benchmarks: `npm run bench`
|
|
274
|
+
|
|
275
|
+
<br>
|
|
276
|
+
|
|
277
|
+
## Use Cases
|
|
278
|
+
|
|
279
|
+
<table>
|
|
280
|
+
<tr>
|
|
281
|
+
<td width="50%">
|
|
282
|
+
<h4>Development & Testing</h4>
|
|
283
|
+
<ul>
|
|
284
|
+
<li><b>Local Development</b> — PostgreSQL without Docker</li>
|
|
285
|
+
<li><b>Integration Testing</b> — Real PostgreSQL, not mocks</li>
|
|
286
|
+
<li><b>CI/CD Pipelines</b> — Fresh databases per test run</li>
|
|
287
|
+
<li><b>E2E Testing</b> — Isolated database for Playwright/Cypress</li>
|
|
288
|
+
</ul>
|
|
289
|
+
</td>
|
|
290
|
+
<td width="50%">
|
|
291
|
+
<h4>AI & Agents</h4>
|
|
292
|
+
<ul>
|
|
293
|
+
<li><b>AI Agent Memory</b> — Isolated, concurrent-safe database</li>
|
|
294
|
+
<li><b>LLM Tool Use</b> — Give AI models a real PostgreSQL</li>
|
|
295
|
+
<li><b>RAG Applications</b> — Store embeddings with pgvector</li>
|
|
296
|
+
</ul>
|
|
297
|
+
</td>
|
|
298
|
+
</tr>
|
|
299
|
+
<tr>
|
|
300
|
+
<td width="50%">
|
|
301
|
+
<h4>Multi-Tenant & SaaS</h4>
|
|
302
|
+
<ul>
|
|
303
|
+
<li><b>Tenant Isolation</b> — Auto-provision per tenant</li>
|
|
304
|
+
<li><b>Demo Environments</b> — Instant sandboxed PostgreSQL</li>
|
|
305
|
+
<li><b>Microservices Dev</b> — Each service gets its own DB</li>
|
|
306
|
+
</ul>
|
|
307
|
+
</td>
|
|
308
|
+
<td width="50%">
|
|
309
|
+
<h4>Edge & Embedded</h4>
|
|
310
|
+
<ul>
|
|
311
|
+
<li><b>IoT Devices</b> — Full PostgreSQL on Raspberry Pi</li>
|
|
312
|
+
<li><b>Desktop Apps</b> — Electron with embedded PostgreSQL</li>
|
|
313
|
+
<li><b>Offline-First</b> — Local DB that syncs when online</li>
|
|
314
|
+
</ul>
|
|
315
|
+
</td>
|
|
316
|
+
</tr>
|
|
317
|
+
</table>
|
|
318
|
+
|
|
319
|
+
<br>
|
|
320
|
+
|
|
321
|
+
## Requirements
|
|
322
|
+
|
|
323
|
+
- **Node.js** >= 18.0.0
|
|
324
|
+
- **Platform**: Linux x64, macOS ARM64/x64, Windows x64
|
|
325
|
+
|
|
326
|
+
<br>
|
|
327
|
+
|
|
328
|
+
## Contributing
|
|
329
|
+
|
|
330
|
+
Contributions welcome! Fork the repo, create a feature branch, add tests, and submit a PR.
|
|
331
|
+
|
|
332
|
+
<br>
|
|
320
333
|
|
|
321
334
|
---
|
|
322
335
|
|
|
323
|
-
|
|
336
|
+
<div align="center">
|
|
337
|
+
<p>
|
|
338
|
+
<b>MIT License</b> — Copyright (c) 2025 Namastex Labs
|
|
339
|
+
</p>
|
|
340
|
+
<p>
|
|
341
|
+
<a href="https://github.com/namastexlabs/pgserve">GitHub</a> •
|
|
342
|
+
<a href="https://www.npmjs.com/package/pgserve">npm</a> •
|
|
343
|
+
<a href="https://github.com/namastexlabs/pgserve/issues">Issues</a>
|
|
344
|
+
</p>
|
|
345
|
+
<p>
|
|
346
|
+
Made with love by <a href="https://namastex.ai">Namastex Labs</a>
|
|
347
|
+
</p>
|
|
348
|
+
</div>
|