pgserve 1.0.7 โ†’ 1.0.9-rc.4

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/Makefile CHANGED
@@ -1,5 +1,5 @@
1
1
  # ==========================================
2
- # ๐Ÿ“ฆ PGlite Embedded Server - Makefile
2
+ # ๐Ÿ“ฆ pgserve - Embedded PostgreSQL Server
3
3
  # ==========================================
4
4
 
5
5
  .DEFAULT_GOAL := help
@@ -24,14 +24,26 @@ VERSION := $(shell grep '"version"' package.json | head -1 | sed 's/.*"version":
24
24
  .PHONY: help
25
25
  help: ## Show this help
26
26
  @echo ""
27
- @echo "$(PURPLE)$(BOLD)๐Ÿ“ฆ PGlite Embedded Server$(RESET) - v$(VERSION)"
28
- @echo "$(CYAN)Multi-instance PostgreSQL server using PGlite$(RESET)"
27
+ @echo "$(PURPLE)$(BOLD)๐Ÿ“ฆ pgserve$(RESET) - v$(VERSION)"
28
+ @echo "$(CYAN)Embedded PostgreSQL server with multi-tenant support$(RESET)"
29
29
  @echo ""
30
30
  @echo "$(BOLD)Quick Commands:$(RESET)"
31
- @echo " $(PURPLE)publish$(RESET) Publish to npm (auto-checks, builds, publishes)"
31
+ @echo " $(PURPLE)release-rc$(RESET) Create RC release locally"
32
+ @echo " $(PURPLE)release-stable$(RESET) Promote RC to stable"
32
33
  @echo " $(PURPLE)test-local$(RESET) Test server locally"
33
34
  @echo " $(PURPLE)pm2-start$(RESET) Start server with PM2"
34
- @echo " $(PURPLE)pm2-stop$(RESET) Stop PM2 instance"
35
+ @echo ""
36
+ @echo "$(BOLD)CI/CD Workflow:$(RESET)"
37
+ @echo " 1. Create PR with changes"
38
+ @echo " 2. Add 'rc' label โ†’ auto-publishes to npm @next"
39
+ @echo " 3. Add 'stable' label โ†’ promotes to npm @latest"
40
+ @echo ""
41
+ @echo "$(BOLD)Build Executables:$(RESET)"
42
+ @echo " $(PURPLE)build$(RESET) Build for current platform"
43
+ @echo " $(PURPLE)build-all$(RESET) Build for all platforms (Linux, macOS, Windows)"
44
+ @echo " $(PURPLE)build-linux$(RESET) Build for Linux (x64 + arm64)"
45
+ @echo " $(PURPLE)build-macos$(RESET) Build for macOS (x64 + arm64)"
46
+ @echo " $(PURPLE)build-windows$(RESET) Build for Windows (x64)"
35
47
  @echo ""
36
48
  @echo "$(BOLD)Development:$(RESET)"
37
49
  @echo " $(PURPLE)install$(RESET) Install dependencies"
@@ -48,9 +60,21 @@ help: ## Show this help
48
60
  .PHONY: install
49
61
  install: ## Install dependencies
50
62
  @echo "$(CYAN)๐Ÿ“ฆ Installing dependencies...$(RESET)"
51
- @npm install
63
+ @bun install
52
64
  @echo "$(GREEN)โœ… Dependencies installed!$(RESET)"
53
65
 
66
+ .PHONY: test
67
+ test: ## Run tests
68
+ @echo "$(CYAN)๐Ÿงช Running tests...$(RESET)"
69
+ @bun test
70
+ @echo "$(GREEN)โœ… Tests passed!$(RESET)"
71
+
72
+ .PHONY: bench
73
+ bench: ## Run benchmarks
74
+ @echo "$(CYAN)๐Ÿ“Š Running benchmarks...$(RESET)"
75
+ @bun tests/benchmarks/runner.js
76
+ @echo "$(GREEN)โœ… Benchmarks complete!$(RESET)"
77
+
54
78
  # ==========================================
55
79
  # ๐Ÿงช Testing
56
80
  # ==========================================
@@ -78,21 +102,21 @@ pm2-start: ## Start server with PM2
78
102
 
79
103
  pm2-stop: ## Stop PM2 instance
80
104
  @echo "$(CYAN)๐Ÿ›‘ Stopping PM2 instance...$(RESET)"
81
- @pm2 stop "PGlite Local Server" 2>/dev/null || true
82
- @pm2 delete "PGlite Local Server" 2>/dev/null || true
105
+ @pm2 stop "pgserve" 2>/dev/null || true
106
+ @pm2 delete "pgserve" 2>/dev/null || true
83
107
  @pm2 save
84
108
  @echo "$(GREEN)โœ… PM2 instance stopped!$(RESET)"
85
109
 
86
110
  pm2-restart: ## Restart PM2 instance
87
111
  @echo "$(CYAN)๐Ÿ”„ Restarting PM2 instance...$(RESET)"
88
- @pm2 restart "PGlite Local Server" 2>/dev/null || $(MAKE) pm2-start
112
+ @pm2 restart "pgserve" 2>/dev/null || $(MAKE) pm2-start
89
113
  @echo "$(GREEN)โœ… PM2 instance restarted!$(RESET)"
90
114
 
91
115
  pm2-logs: ## Show PM2 logs
92
- @pm2 logs "PGlite Local Server" --lines 50
116
+ @pm2 logs "pgserve" --lines 50
93
117
 
94
118
  pm2-status: ## Show PM2 status
95
- @pm2 status "PGlite Local Server"
119
+ @pm2 status "pgserve"
96
120
 
97
121
  # ==========================================
98
122
  # ๐Ÿ” Pre-publish Checks
@@ -139,7 +163,86 @@ check-files: ## Check required files exist
139
163
  @echo "$(GREEN)โœ… All required files present$(RESET)"
140
164
 
141
165
  # ==========================================
142
- # ๐Ÿ“ฆ Build & Publish
166
+ # ๐Ÿ”จ Build Standalone Executables
167
+ # ==========================================
168
+ DIST_DIR := dist
169
+
170
+ .PHONY: build build-linux build-macos build-windows build-all clean-dist
171
+
172
+ $(DIST_DIR):
173
+ @mkdir -p $(DIST_DIR)
174
+
175
+ build: $(DIST_DIR) ## Build standalone executable for current platform
176
+ @echo "$(CYAN)๐Ÿ”จ Building standalone executable...$(RESET)"
177
+ @bun build --compile bin/pglite-server.js --outfile $(DIST_DIR)/pgserve
178
+ @echo "$(GREEN)โœ… Built: $(DIST_DIR)/pgserve$(RESET)"
179
+
180
+ build-linux: $(DIST_DIR) ## Build for Linux (x64 + arm64)
181
+ @echo "$(CYAN)๐Ÿง Building for Linux...$(RESET)"
182
+ @bun build --compile --target=bun-linux-x64 bin/pglite-server.js --outfile $(DIST_DIR)/pgserve-linux-x64
183
+ @bun build --compile --target=bun-linux-arm64 bin/pglite-server.js --outfile $(DIST_DIR)/pgserve-linux-arm64
184
+ @echo "$(GREEN)โœ… Built: $(DIST_DIR)/pgserve-linux-x64$(RESET)"
185
+ @echo "$(GREEN)โœ… Built: $(DIST_DIR)/pgserve-linux-arm64$(RESET)"
186
+
187
+ build-macos: $(DIST_DIR) ## Build for macOS (x64 + arm64)
188
+ @echo "$(CYAN)๐ŸŽ Building for macOS...$(RESET)"
189
+ @bun build --compile --target=bun-darwin-x64 bin/pglite-server.js --outfile $(DIST_DIR)/pgserve-darwin-x64
190
+ @bun build --compile --target=bun-darwin-arm64 bin/pglite-server.js --outfile $(DIST_DIR)/pgserve-darwin-arm64
191
+ @echo "$(GREEN)โœ… Built: $(DIST_DIR)/pgserve-darwin-x64$(RESET)"
192
+ @echo "$(GREEN)โœ… Built: $(DIST_DIR)/pgserve-darwin-arm64$(RESET)"
193
+
194
+ build-windows: $(DIST_DIR) ## Build for Windows (x64)
195
+ @echo "$(CYAN)๐ŸชŸ Building for Windows...$(RESET)"
196
+ @bun build --compile --target=bun-windows-x64 bin/pglite-server.js --outfile $(DIST_DIR)/pgserve-windows-x64.exe
197
+ @echo "$(GREEN)โœ… Built: $(DIST_DIR)/pgserve-windows-x64.exe$(RESET)"
198
+
199
+ build-all: build-linux build-macos build-windows ## Build for all platforms
200
+ @echo ""
201
+ @echo "$(GREEN)$(BOLD)โ•”โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•—$(RESET)"
202
+ @echo "$(GREEN)$(BOLD)โ•‘ ๐ŸŽ‰ All platform builds complete! โ•‘$(RESET)"
203
+ @echo "$(GREEN)$(BOLD)โ•šโ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•$(RESET)"
204
+ @echo ""
205
+ @ls -lh $(DIST_DIR)/
206
+ @echo ""
207
+
208
+ clean-dist: ## Clean build artifacts
209
+ @echo "$(CYAN)๐Ÿงน Cleaning dist...$(RESET)"
210
+ @rm -rf $(DIST_DIR)
211
+ @echo "$(GREEN)โœ… Dist cleaned!$(RESET)"
212
+
213
+ # ==========================================
214
+ # ๐Ÿš€ CI/CD Release (Automated)
215
+ # ==========================================
216
+ # Releases are triggered by GitHub Actions when PRs are merged with labels:
217
+ # - 'rc' label โ†’ Creates RC release (1.0.8 โ†’ 1.0.9-rc.1)
218
+ # - 'stable' label โ†’ Promotes RC to stable (1.0.9-rc.1 โ†’ 1.0.9)
219
+ #
220
+ # See .github/workflows/release.yml for full automation.
221
+ # ==========================================
222
+ .PHONY: release-rc release-stable release-dry
223
+
224
+ release-rc: ## Create RC release locally (for testing)
225
+ @echo "$(CYAN)๐Ÿ”ข Creating RC release...$(RESET)"
226
+ @node scripts/release.cjs --action bump-rc
227
+ @echo ""
228
+ @echo "$(GREEN)โœ… RC release created!$(RESET)"
229
+ @echo "$(YELLOW)Push with: git push && git push --tags$(RESET)"
230
+
231
+ release-stable: ## Promote RC to stable locally (for testing)
232
+ @echo "$(CYAN)๐ŸŽ‰ Promoting to stable...$(RESET)"
233
+ @node scripts/release.cjs --action promote
234
+ @echo ""
235
+ @echo "$(GREEN)โœ… Stable release created!$(RESET)"
236
+ @echo "$(YELLOW)Push with: git push && git push --tags$(RESET)"
237
+
238
+ release-dry: ## Dry-run release (no changes)
239
+ @echo "$(CYAN)๐Ÿ” Dry-run release...$(RESET)"
240
+ @node scripts/release.cjs --action bump-rc --dry-run
241
+ @echo ""
242
+ @echo "$(GREEN)โœ… Dry-run complete (no changes made)$(RESET)"
243
+
244
+ # ==========================================
245
+ # ๐Ÿ“ฆ Manual Publish (Deprecated)
143
246
  # ==========================================
144
247
  .PHONY: pre-publish publish publish-dry
145
248
  pre-publish: check-git check-npm check-version check-files ## Run all pre-publish checks
@@ -151,57 +254,21 @@ publish-dry: pre-publish ## Dry-run publish (test without actually publishing)
151
254
  @echo "$(GREEN)โœ… Dry-run successful!$(RESET)"
152
255
  @echo "$(YELLOW)To actually publish, run: make publish$(RESET)"
153
256
 
154
- publish: check-git check-npm check-files ## ๐Ÿš€ Publish to npm (auto-bumps version)
257
+ publish: ## โš ๏ธ [DEPRECATED] Use PR labels instead
155
258
  @echo ""
156
- @echo "$(PURPLE)$(BOLD)โ•”โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•—$(RESET)"
157
- @echo "$(PURPLE)$(BOLD)โ•‘ ๐Ÿ“ฆ Publishing $(PACKAGE_NAME) โ•‘$(RESET)"
158
- @echo "$(PURPLE)$(BOLD)โ•šโ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•$(RESET)"
259
+ @echo "$(YELLOW)$(BOLD)โ•”โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•—$(RESET)"
260
+ @echo "$(YELLOW)$(BOLD)โ•‘ โš ๏ธ Manual publish is DEPRECATED โ•‘$(RESET)"
261
+ @echo "$(YELLOW)$(BOLD)โ•‘ โ•‘$(RESET)"
262
+ @echo "$(YELLOW)$(BOLD)โ•‘ Use PR labels for automated releases: โ•‘$(RESET)"
263
+ @echo "$(YELLOW)$(BOLD)โ•‘ โ€ข Add 'rc' label โ†’ RC release (npm @next) โ•‘$(RESET)"
264
+ @echo "$(YELLOW)$(BOLD)โ•‘ โ€ข Add 'stable' label โ†’ Promote to stable (npm @latest) โ•‘$(RESET)"
265
+ @echo "$(YELLOW)$(BOLD)โ•‘ โ•‘$(RESET)"
266
+ @echo "$(YELLOW)$(BOLD)โ•‘ Local testing: โ•‘$(RESET)"
267
+ @echo "$(YELLOW)$(BOLD)โ•‘ make release-rc Create RC locally โ•‘$(RESET)"
268
+ @echo "$(YELLOW)$(BOLD)โ•‘ make release-stable Promote locally โ•‘$(RESET)"
269
+ @echo "$(YELLOW)$(BOLD)โ•‘ make release-dry Dry-run (no changes) โ•‘$(RESET)"
270
+ @echo "$(YELLOW)$(BOLD)โ•šโ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•$(RESET)"
159
271
  @echo ""
160
- @echo "$(CYAN)Current version: v$(VERSION)$(RESET)"
161
- @echo ""
162
- @echo "$(CYAN)๐Ÿ“ˆ Bumping patch version...$(RESET)"
163
- @NEW_VER=$$(node -e "const p=require('./package.json'); const v=p.version.split('.'); v[2]=parseInt(v[2])+1; console.log(v.join('.'))"); \
164
- git tag -d "v$$NEW_VER" 2>/dev/null || true; \
165
- git push origin --delete "v$$NEW_VER" 2>/dev/null || true
166
- @npm version patch -m "chore: bump version to %s"
167
- @NEW_VERSION=$$(grep '"version"' package.json | head -1 | sed 's/.*"version": "\(.*\)".*/\1/'); \
168
- echo "$(GREEN)โœ… Version bumped to $$NEW_VERSION$(RESET)"; \
169
- echo ""; \
170
- echo "$(CYAN)๐Ÿ“ค Pushing to GitHub...$(RESET)"; \
171
- git push && git push --tags; \
172
- echo "$(GREEN)โœ… Pushed to GitHub!$(RESET)"; \
173
- echo ""; \
174
- echo "$(CYAN)Package: $(PACKAGE_NAME)@$$NEW_VERSION$(RESET)"; \
175
- echo ""; \
176
- read -p "$(YELLOW)Confirm publish? [y/N] $(RESET)" -n 1 -r; \
177
- echo; \
178
- if [[ ! $$REPLY =~ ^[Yy]$$ ]]; then \
179
- echo "$(YELLOW)โš ๏ธ Publish cancelled$(RESET)"; \
180
- exit 1; \
181
- fi; \
182
- echo ""; \
183
- echo "$(CYAN)๐Ÿ“ฆ Publishing to npm...$(RESET)"; \
184
- npm publish --access public || { echo "$(RED)โŒ npm publish failed! Run manually: npm publish --access public$(RESET)"; exit 1; }; \
185
- echo "$(GREEN)โœ… Published to npm!$(RESET)"; \
186
- echo ""; \
187
- if command -v gh >/dev/null 2>&1; then \
188
- echo "$(CYAN)๐ŸŽ‰ Creating GitHub release...$(RESET)"; \
189
- gh release create "v$$NEW_VERSION" \
190
- --title "v$$NEW_VERSION" \
191
- --notes "Multi-instance PostgreSQL embedded server - See README.md for details" \
192
- || echo "$(YELLOW)โš ๏ธ GitHub release creation failed (may already exist)$(RESET)"; \
193
- echo ""; \
194
- fi; \
195
- echo "$(GREEN)$(BOLD)โ•”โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•—$(RESET)"; \
196
- echo "$(GREEN)$(BOLD)โ•‘ ๐Ÿพ SUCCESS! Package published! โ•‘$(RESET)"; \
197
- echo "$(GREEN)$(BOLD)โ•šโ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•$(RESET)"; \
198
- echo ""; \
199
- echo "$(CYAN)๐Ÿ“ฆ Install with:$(RESET)"; \
200
- echo " npm install -g $(PACKAGE_NAME)"; \
201
- echo ""; \
202
- echo "$(CYAN)๐Ÿ”— View on npm:$(RESET)"; \
203
- echo " https://www.npmjs.com/package/$(PACKAGE_NAME)"; \
204
- echo ""
205
272
 
206
273
  # ==========================================
207
274
  # ๐Ÿงน Maintenance
@@ -215,7 +282,7 @@ clean: ## Clean generated files
215
282
 
216
283
  clean-all: clean ## Deep clean (including node_modules)
217
284
  @echo "$(CYAN)๐Ÿงน Deep cleaning...$(RESET)"
218
- @rm -rf node_modules package-lock.json pnpm-lock.yaml
285
+ @rm -rf node_modules package-lock.json pnpm-lock.yaml bun.lock
219
286
  @echo "$(GREEN)โœ… Deep clean complete!$(RESET)"
220
287
 
221
288
  # ==========================================
package/README.md CHANGED
@@ -5,6 +5,7 @@
5
5
  <p>
6
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
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/bun-%3E%3D1.0.0-f472b6?style=flat-square" alt="Bun">
8
9
  <img src="https://img.shields.io/badge/PostgreSQL-17.7-blue?style=flat-square" alt="PostgreSQL">
9
10
  <a href="LICENSE"><img src="https://img.shields.io/badge/license-MIT-green?style=flat-square" alt="License"></a>
10
11
  <a href="https://discord.gg/xcW8c7fF3R"><img src="https://img.shields.io/discord/1095114867012292758?style=flat-square&color=00D9FF&label=discord" alt="Discord"></a>
@@ -56,6 +57,10 @@ psql postgresql://localhost:5432/myapp
56
57
  <td><b>Memory Mode</b></td>
57
58
  <td>Fast and ephemeral for development (default)</td>
58
59
  </tr>
60
+ <tr>
61
+ <td><b>RAM Mode</b></td>
62
+ <td>Use <code>--ram</code> for /dev/shm storage (Linux, 2x faster)</td>
63
+ </tr>
59
64
  <tr>
60
65
  <td><b>Persistent Mode</b></td>
61
66
  <td>Use <code>--data ./path</code> for durable storage</td>
@@ -87,6 +92,10 @@ npm install -g pgserve
87
92
 
88
93
  # Project dependency
89
94
  npm install pgserve
95
+
96
+ # With Bun
97
+ bunx pgserve
98
+ bun add pgserve
90
99
  ```
91
100
 
92
101
  > PostgreSQL binaries are automatically downloaded on first run.
@@ -101,6 +110,7 @@ pgserve [options]
101
110
  Options:
102
111
  --port <number> PostgreSQL port (default: 8432)
103
112
  --data <path> Data directory for persistence (default: in-memory)
113
+ --ram Use RAM storage via /dev/shm (Linux only, fastest)
104
114
  --host <host> Host to bind to (default: 127.0.0.1)
105
115
  --log <level> Log level: error, warn, info, debug (default: info)
106
116
  --cluster Force cluster mode (auto-enabled on multi-core)
@@ -119,6 +129,9 @@ Options:
119
129
  # Development (memory mode, auto-clusters on multi-core)
120
130
  pgserve
121
131
 
132
+ # RAM mode (Linux only, 2x faster)
133
+ pgserve --ram
134
+
122
135
  # Persistent storage
123
136
  pgserve --data /var/lib/pgserve
124
137
 
@@ -237,40 +250,46 @@ pgserve --sync-to "postgresql://..." --sync-databases "myapp,tenant_*"
237
250
 
238
251
  ## Performance
239
252
 
253
+ ### Benchmark Results
254
+
240
255
  <table>
241
256
  <tr>
242
257
  <th>Scenario</th>
243
258
  <th>SQLite</th>
244
259
  <th>PGlite</th>
245
- <th>Docker PG</th>
246
- <th>pgserve</th>
260
+ <th>pgserve (Node)</th>
261
+ <th>pgserve (Bun)</th>
262
+ <th>pgserve --ram</th>
247
263
  </tr>
248
264
  <tr>
249
265
  <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>
266
+ <td>85 qps</td>
267
+ <td>211 qps</td>
268
+ <td>833 qps</td>
269
+ <td>1,754 qps</td>
270
+ <td><b>4,000 qps</b> ๐Ÿ†</td>
254
271
  </tr>
255
272
  <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>
273
+ <td><b>Mixed Workload</b></td>
274
+ <td>339 qps</td>
275
+ <td>505 qps</td>
276
+ <td>1,017 qps</td>
277
+ <td>999 qps</td>
278
+ <td><b>1,986 qps</b> ๐Ÿ†</td>
261
279
  </tr>
262
280
  <tr>
263
281
  <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>
282
+ <td>86 qps</td>
283
+ <td>168 qps</td>
284
+ <td>488 qps</td>
285
+ <td>1,176 qps</td>
286
+ <td><b>4,348 qps</b> ๐Ÿ†</td>
268
287
  </tr>
269
288
  </table>
270
289
 
271
- > pgserve beats Docker PostgreSQL in 2/3 scenarios. For development, CI/CD, and ephemeral deployments โ€” better-than-Docker performance without Docker.
290
+ > **Bun gives 2x throughput** for concurrent writes vs Node.js. **RAM mode adds another 2-4x** on Linux.
272
291
  >
273
- > Run benchmarks: `npm run bench`
292
+ > Run benchmarks: `bun run bench`
274
293
 
275
294
  <br>
276
295
 
@@ -320,11 +339,31 @@ pgserve --sync-to "postgresql://..." --sync-databases "myapp,tenant_*"
320
339
 
321
340
  ## Requirements
322
341
 
323
- - **Node.js** >= 18.0.0
342
+ - **Runtime**: Node.js >= 18.0.0 or Bun >= 1.0.0
324
343
  - **Platform**: Linux x64, macOS ARM64/x64, Windows x64
325
344
 
326
345
  <br>
327
346
 
347
+ ## Development
348
+
349
+ This project uses Bun for development:
350
+
351
+ ```bash
352
+ # Install dependencies
353
+ bun install
354
+
355
+ # Run tests
356
+ bun test
357
+
358
+ # Run benchmarks
359
+ bun tests/benchmarks/runner.js
360
+
361
+ # Lint
362
+ bun run lint
363
+ ```
364
+
365
+ <br>
366
+
328
367
  ## Contributing
329
368
 
330
369
  Contributions welcome! Fork the repo, create a feature branch, add tests, and submit a PR.
@@ -1,4 +1,4 @@
1
- #!/usr/bin/env node
1
+ #!/usr/bin/env bun
2
2
 
3
3
  /**
4
4
  * pgserve - Embedded PostgreSQL Server
@@ -44,6 +44,7 @@ USAGE:
44
44
  OPTIONS:
45
45
  --port <number> PostgreSQL port (default: 8432)
46
46
  --data <path> Data directory for persistence (default: in-memory)
47
+ --ram Use RAM storage via /dev/shm (Linux only, faster)
47
48
  --host <host> Host to bind to (default: 127.0.0.1)
48
49
  --log <level> Log level: error, warn, info, debug (default: info)
49
50
  --cluster Force cluster mode (auto-enabled on multi-core systems)
@@ -55,7 +56,8 @@ OPTIONS:
55
56
  --help Show this help message
56
57
 
57
58
  MODES:
58
- In-memory (default): Fast, ephemeral - data lost on restart
59
+ In-memory (default): Ephemeral temp directory - data lost on restart
60
+ RAM mode (--ram): True RAM via /dev/shm (Linux only, fastest)
59
61
  Persistent: Use --data to persist databases to disk
60
62
 
61
63
  EXAMPLES:
@@ -98,6 +100,7 @@ function parseArgs() {
98
100
  port: 8432,
99
101
  host: '127.0.0.1',
100
102
  dataDir: null, // null = memory mode
103
+ useRam: false, // Use /dev/shm for true RAM storage (Linux only)
101
104
  logLevel: 'info',
102
105
  autoProvision: true,
103
106
  cluster: cpuCount > 1, // Auto-enable on multi-core (use --no-cluster to disable)
@@ -120,6 +123,10 @@ function parseArgs() {
120
123
  options.dataDir = args[++i];
121
124
  break;
122
125
 
126
+ case '--ram':
127
+ options.useRam = true;
128
+ break;
129
+
123
130
  case '--host':
124
131
  case '-h':
125
132
  options.host = args[++i];
@@ -178,6 +185,9 @@ function parseArgs() {
178
185
  async function main() {
179
186
  const options = parseArgs();
180
187
  const memoryMode = !options.dataDir;
188
+ const storageType = options.dataDir
189
+ ? options.dataDir
190
+ : (options.useRam ? '/dev/shm (RAM)' : '(temp directory)');
181
191
 
182
192
  // Only print header if not a cluster worker (workers get PGSERVE_WORKER env)
183
193
  if (!process.env.PGSERVE_WORKER) {
@@ -196,6 +206,7 @@ pgserve - Embedded PostgreSQL Server
196
206
  port: options.port,
197
207
  host: options.host,
198
208
  baseDir: options.dataDir,
209
+ useRam: options.useRam,
199
210
  logLevel: options.logLevel,
200
211
  autoProvision: options.autoProvision,
201
212
  workers: options.workers
@@ -204,13 +215,14 @@ pgserve - Embedded PostgreSQL Server
204
215
  // Only primary process shows full startup message
205
216
  if (server.workers) {
206
217
  const stats = server.getStats();
218
+
207
219
  console.log(`
208
220
  Cluster started successfully!
209
221
 
210
222
  Endpoint: postgresql://${options.host}:${options.port}/<database>
211
223
  Mode: ${memoryMode ? 'In-memory (ephemeral)' : 'Persistent'} (Cluster)
212
224
  Workers: ${stats.workers} processes
213
- Data: ${memoryMode ? '(temp directory)' : options.dataDir}
225
+ Data: ${storageType}
214
226
  Auto-create: ${options.autoProvision ? 'Enabled' : 'Disabled'}
215
227
 
216
228
  Examples:
@@ -226,6 +238,7 @@ Press Ctrl+C to stop
226
238
  port: options.port,
227
239
  host: options.host,
228
240
  baseDir: options.dataDir,
241
+ useRam: options.useRam,
229
242
  logLevel: options.logLevel,
230
243
  autoProvision: options.autoProvision,
231
244
  syncTo: options.syncTo,
@@ -244,7 +257,7 @@ Server started successfully!
244
257
 
245
258
  Endpoint: postgresql://${options.host}:${options.port}/<database>
246
259
  Mode: ${memoryMode ? 'In-memory (ephemeral)' : 'Persistent'}
247
- Data: ${memoryMode ? '(temp directory)' : options.dataDir}
260
+ Data: ${storageType}
248
261
  PostgreSQL: Port ${router.pgPort} (internal)
249
262
  Auto-create: ${options.autoProvision ? 'Enabled' : 'Disabled'}
250
263
  Sync: ${syncStatus}${options.syncDatabases ? ` (${options.syncDatabases})` : ''}