Building a Microservice Architecture with Rust & PostgreSQL

July 6, 2026 BlueSparrow Labs
RustPostgreSQLMicroservicesDatabase

Modern mobile apps often need robust backend infrastructures. For our cross-platform Flutter apps, we adopted a microservice architecture powered by Rust and PostgreSQL. Here's a detailed look at our design, the reasons behind our choices, and the benefits we've reaped in scalability, maintainability, and performance.

Overview of Our Architecture

The diagram below illustrates our backend layout:

Illustration: Simplified microservice architecture. Flutter apps (left) call an API Gateway (Rust) that dispatches to individual services: AuthService, UserService, DataService, each connected to a PostgreSQL database.

  1. API Gateway (Rust): A thin Rust/Actix-Web service that exposes endpoints to the Flutter client. It handles routing requests to downstream services and enforces authentication (via JWT) using Redis for session validation.
  2. AuthService (Rust): Responsible for login, signup, and token issuance. It has its own Postgres schema (auth.*) and uses Argon2 for password hashing.
  3. UserService (Rust): Manages user profiles, settings, and preferences. It connects to the same Postgres cluster (schema users.*).
  4. DataService (Rust): Handles main app data (e.g. posts, messages, analytics events). Also backed by Postgres (data.* schema), and we store some JSONB for flexible metadata.
  5. Redis Cache: Used by AuthService to track active sessions and by DataService for caching frequent queries.
  6. PostgreSQL (self-hosted in EU): A single PostgreSQL cluster in Frankfurt, with multiple logical schemas. We enforce SSL/TLS on all connections (Green line). Backups are running with point-in-time recovery to a French datacenter (yellow path) every hour.
  7. External APIs: We also interact with a payment gateway (HTTPS) and cloud message service (FCM) for notifications, but those are out-of-scope here.

This diagram was drawn using Mermaid (for clarity) and represents our production topology. Each Rust service is containerized (Docker) and deployed via Kubernetes on our VPS cluster. Kubernetes gives us auto-scaling: we can specify CPU-based scaling for each microservice. This is key for resilience under load.

Why Rust + PostgreSQL?

  • Rust for Services: As noted in Post 1, Rust offers high performance and safety. This suits an architecture with many moving parts. Each microservice is written in Rust with the [Actix Web] or [Axum] framework. For example, Actix is our choice for AuthService because of its synchronous actor model and top-tier raw throughput. Axum (with Tokio) powers DataService, where async database calls are common. Both are production-tested and integrate well with async runtimes.
  • PostgreSQL as the DB: PostgreSQL is our single relational store for structured data. We chose it for reliability and features (ACID, rich JSON support). Each service uses a different schema within the same DB to keep data logically separate but easily queryable. For instance, UserService tables are all under users, DataService tables under data. This lets us do cross-schema joins with permission checks if needed. We use the [SQLx] crate in Rust for interacting with Postgres, benefiting from compile-time query validation and async execution.

By using Rust for all services, we avoid interop friction. We also considered a polyglot mix (e.g. Rust + Node) but sticking to Rust simplified devops (one Docker base, one CI pipeline). As our team's primary backend language, this uniformity speeds up debugging and sharing tools (like Prometheus exporters written in Rust).

Data Flow Example

Let's walk through a typical API request: the Flutter app wants the current user's profile data.

  1. The app sends a GET to /api/profile to the API Gateway, including an auth JWT.
  2. API Gateway verifies the JWT by checking it against Redis (and HMAC secret). If valid, it routes the request to UserService at /user/me.
  3. UserService queries its Postgres schema: SELECT id, name, avatar_url, settings FROM users.profiles WHERE user_id = $1.
  4. It serializes the result to JSON and returns it to the Gateway, which passes it back to the client.
  5. Meanwhile, AuthService remains idle for this request. DataService unaffected. If caching were needed (e.g. for frequently accessed user profiles), we could add Redis caching in front of step 3.

Another flow: when a new message is sent, the app POSTs to /api/message. API Gateway authenticates, forwards to DataService, which inserts the message row in data.messages and maybe publishes a notification via FCM (using a Rust FCM client).

Each service's database interactions are isolated, so schema changes don't affect others. We ensure referential integrity manually through code or PostgreSQL foreign keys across schemas when needed.

Managing the Database

We use role-based access in Postgres: the AuthService's DB user only has rights on the auth schema, UserService's user only on users.*, etc. Our Kubernetes secrets hold these credentials. This enforces the principle of least privilege.

For migrations, we use [sqlx-cli] to version-control each service's schema. This allows rolling updates: deploying a new version of UserService with an updated SQL migration to add a column, for example, without touching AuthService.

The Postgres cluster has streaming replication to a standby node for high availability. Write to master, read from replicas when possible (via pgx load balancing, though we mainly run on the primary for simplicity). We also use PostGIS in the data schema for geo-queries, which just required adding the extension.

Benefits and Metrics

This microservice+Postgres design gives us:

  • Scalability: We can scale each component individually. Under heavy login load, only AuthService pods scale up, saving resources on others. Kubernetes HPA (Horizontal Pod Autoscaler) based on CPU or custom Prometheus alerts handles this.
  • Maintainability: If we need to refactor the messaging logic, we can push a new version of DataService alone. No need to rebuild the whole backend monolith. Our CI pipeline builds each Rust service image separately.
  • Performance: In internal benchmarks, each microservice is capable of tens of thousands of ops/sec. For example, DataService returns typical data queries in ~50ms under moderate load (measured via Artillery). Without microservices, a monolith might have slower cold-cache response due to resource contention.
  • Privacy & Security: Since services are separated, we minimize data scope. AuthService doesn't even know about user posts, and DataService doesn't handle passwords, reducing attack surfaces.

Our monitoring stack (Prometheus + Grafana) shows overall system health. For instance, 99th percentile response times for our key endpoints are consistently under 200ms, and CPU usage rarely spikes above 30% on our 4-CPU VPS cluster. Postgres CPU hovers below 20% due to efficient indexing and query tuning.

Conclusion

Designing a backend from scratch was challenging, but going microservice with Rust and Postgres has paid off. We achieve fast, reliable service delivery that scales as we grow. This architecture is also aligned with our focus on privacy: each service only handles data it needs, and the central Postgres server is locked down in an EU data center.

For teams considering a similar stack, remember: start simple. Perhaps begin with a monolith prototype, then split services as needed. Ensure your data model is solid before microservices. Use Postgres as a single source of truth when possible. And choose languages (like Rust) that you feel comfortable operating at scale.

With careful design (and diagrams like above!), you can manage complexity effectively. Over time, as features expand, this setup will allow adding new services (e.g. a Machine Learning inference service) without rearchitecting the core. In essence, we've built a flexible, privacy-first backend on which our Flutter apps can confidently run.

Built by BlueSparrow Labs

We build utility applications that respect your data and help you live mindfully. Explore our matching live apps:

Billnix icon

Billnix

Track recurring bills, reminders, sync and restore without bank linking.

Google Play
LensNote icon

LensNote

Private journal & mood tracker. Offline-first, secure, insightful.

Google Play
GITA Pray icon

GITA Pray

Turn phone distraction into spiritual growth with daily Bhagavad Gita verses.

Google Play
AGAMA icon

AGAMA

Turn phone distraction into dharma with Jain Sacred Texts & Wisdom Sources.

Google Play