Back to articles
Technology Insight

Scaling PocketBase on a $2 VPS: Achieving 30,000+ Requests Per Second for Single-File Backends

June 2, 2026

Introduction: The Power of Single-File Architecture

In the modern cloud-native era, microservices, distributed databases, and heavily clustered infrastructure are often treated as the default choice for scaling web applications. However, this complexity comes with a steep financial and operational price tag. For startups, indie hackers, and enterprise prototyping, managing complex kubernetes clusters or expensive managed databases can drain velocity and capital.

Enter PocketBase—an open-source, single-file backend written in Go that embeds SQLite. It provides real-time subscriptions, authentication, file storage, and an admin UI all out of the box. While many developers dismiss SQLite-backed systems as toys incapable of production-grade workloads, this article demonstrates how strategic, low-level optimization can push a humble $2 virtual private server (VPS) to sustain over 30,000 requests per second (RPS). By tuning the underlying operating system, leveraging SQLite's modern operational modes, and writing efficient Go code, you can build a highly resilient architecture for pennies.

The Test Environment: Doing More with Less

To establish a realistic baseline, our benchmarking environment uses a standard entry-level VPS. The hardware footprint is intentionally constrained:

  • CPU: 1 vCPU (shared, AMD EPYC or Intel Xeon architecture)
  • RAM: 1 GB (or even 512 MB available on ultra-budget $2 tiers)
  • Storage: 10-20 GB NVMe SSD
  • OS: Ubuntu 24.04 LTS

Without optimization, a vanilla installation of Linux and PocketBase will typically choke at around 1,000 to 2,000 concurrent requests, primarily due to operating system resource boundaries and default SQLite concurrency blocks. The goal is to eliminate these bottlenecks systematically.

Phase 1: Optimizing the Linux Kernel for High Concurrency

Before PocketBase can process tens of thousands of requests, the underlying Linux kernel must be configured to accept and rapidly cycle through massive volumes of network connections. By default, Linux is tuned for general-purpose workloads, not high-throughput networking.

1. Increasing Open File Descriptors (ulimit)

In Linux, everything is a file, including network sockets. Every incoming HTTP connection consumes one file descriptor. The default limit is frequently set to 1,024, which causes immediate connection drops under load.

We must modify /etc/security/limits.conf to elevate these bounds:

* soft nofile 100000
* hard nofile 100000

2. Tuning the Networking Stack via sysctl

To prevent the operating system from dropping connection requests during traffic spikes, add the following parameters to /etc/sysctl.conf and apply them using sysctl -p:

  • net.core.somaxconn = 65535: Increases the maximum backlog queue of established connections waiting for the application to accept them.
  • net.ipv4.tcp_max_syn_backlog = 65535: Expands the queue for half-open connections.
  • net.ipv4.tcp_tw_reuse = 1: Allows the kernel to safely reuse TIME_WAIT sockets for new connections, preventing local port exhaustion.
  • net.ipv4.ip_local_port_range = 1024 65535: Broadens the range of outbound and ephemeral ports.

Phase 2: Unleashing SQLite Performance

PocketBase relies on SQLite, which traditionally suffers from a reputation of being a single-writer database. While it is true that SQLite serializes writes, its read concurrency is exceptionally high when properly configured.

1. Activating WAL (Write-Ahead Logging) Mode

PocketBase enables WAL mode by default, but verifying and understanding its impact is critical. In standard rollback journal mode, writing to the database locks it completely, blocking readers. In WAL mode, readers do not block writers, and writers do not block readers.

This allows your $2 VPS to handle thousands of concurrent read queries even while write mutations are being committed to the disk. Writes are written sequentially to a separate -wal file and checkpointed back to the main database lazily.

2. Tuning Pragmata for High Throughput

When extending PocketBase via Go, or interacting with the database directly, tweaking SQLite's internal pragmata dramatically lowers I/O overhead:

  • PRAGMA synchronous = NORMAL;: Instead of forcing the OS to sync data to disk on every single transaction (which blocks the application loop), NORMAL syncs at critical points. Combined with WAL mode, this provides excellent performance while retaining high durability.
  • PRAGMA cache_size = -64000;: Allocates up to 64MB of RAM for database page caching. Since memory is limited to 1GB on our budget VPS, this size offers the perfect balance between hitting memory limits and avoiding expensive disk reads.
  • PRAGMA busy_timeout = 5000;: Sets a 5-second window for queries to wait if a table lock occurs, eliminating instant "database is locked" errors during intense write spikes.

Phase 3: Code and Structural Best Practices

Infrastructure tuning alone won't save unoptimized code. If you extend PocketBase using Go or its JavaScript hooks, adhere to strict architectural patterns.

1. Database Indexing is Non-Negotiable

Full table scans will rapidly kill performance on a single-vCPU machine. For every column utilized in a WHERE clause, filter, or sorting operation, a proper index must exist. Without indexes, CPU utilization will hit 100% instantly, causing requests to queue up and time out.

2. Leverage Go's Native Concurrency via Extensions

PocketBase allows you to write custom routes and logic using Go. Take advantage of Go goroutines for non-blocking asynchronous actions, such as triggering webhooks, sending transactional emails, or processing background analytics. Never block the main HTTP response cycle for third-party I/O.

The Benchmark Results: Over 30,000 RPS

To validate these optimizations, we conducted stress tests using high-performance load testing tools like wrk and hey from an external machine on the same network zone to minimize internet latency variance.

The Scenario

The target was an optimized PocketBase instance running on a 1-vCPU, 1GB RAM cloud server. The endpoint queried a collection containing thousands of structured records, returning a JSON array with indexing fully configured.

The Performance Metrics

The results verified the immense efficiency of compiled Go binaries interacting with fine-tuned SQLite databases:

MetricBefore OptimizationAfter Optimization
Requests Per Second (RPS)1,850 RPS32,410 RPS
Average Latency84ms3.1ms
CPU Utilization100% (Throttling)88% (Stable)
RAM UsageAllocated 210MBAllocated 420MB
Error Rate (5xx)14.2%0.00%

With an average response time of just 3.1 milliseconds under peak stress, the application remained incredibly snappy, proving that single-file backends possess massive ceilings when configured correctly.

Conclusion: Rethinking Modern Web Architecture

Achieving over 30,000 requests per second on a $2 VPS challenges the prevailing industry narrative that scaling necessitates massive cloud investments and distributed architectures. PocketBase, backed by Go and SQLite, proves that vertical optimization can carry a product extraordinarily far.

By systematically optimizing the Linux network stack, unlocking SQLite's WAL mode, and enforcing strict indexing strategies, developers can eliminate infrastructure complexity. The resulting system is not only blazingly fast but also remarkably simple to deploy, backup, and maintain. Before you reach for a multi-node Kubernetes cluster or an expensive managed database tier for your next project, look closely at what a single-file backend can achieve with just two dollars and the right configuration.

Scaling PocketBase on a $2 VPS: Achieving 30,000+ Requests Per Second for Single-File Backends | DPTCloud