Behind the build: AmazonADS

This blog is part of our Behind the Build series, where we explore the architecture, guardrails, and engineering culture behind zally. In this edition, we're focusing on how we took complete control of our databases without sacrificing the speed and convenience of managed infrastructure.

1. From 20+ DynamoDB Tables to One Lean RDS cluster 

Our original architecture diagram had more than twenty DynamoDB tables (a core data storage component of Amazon DynamoDB), each created to support “just one more” feature.

Over time, this setup became costly, and the management of these tables grew increasingly.
This also created a steep mental load for newly onboarded engineers.

Therefore, we stepped back and rethought our strategy. We consolidated everything into a single Amazon Aurora PostgreSQL cluster within Amazon RDS. This unified, managed relational backbone now stores all our data while maintaining the elasticity and durability we need. 

2. RDS the zally Way: One Cluster, Many Safe Spaces

The secret? Database-level isolation. Every developer branch, pull request, and production stacks get its own fully isolated database, all within the same cluster. 

Here’s how we keep every environment isolated and automated:

  1. Namespaced Databases – Whether it’s prod, staging, or a feature branch like pr-123, each environment gets its isolated database schema.

  2. Automatic Lifecycles – Closing a pull request automatically tears down the corresponding database via our GitHub Actions workflow, resulting in no manual clean-up required.

  3. Zero-Touch Provisioning – SST handles the cluster spin-up, while a lightweight Lambda function creates or deletes databases on demand — seamlessly and instantly.

3. Drizzle: The Toolbelt on Top

We layer our RDS setup with Drizzle to give engineers visibility, safety and confidence from day one:

Drizzle Studio - Visibility by Default: We expose the cluster to Drizzle Studio, a browser-based IDE that lets engineers browse tables, run ad-hoc queries, and even fiddle with indexes in a permission-controlled environment.

DrizzleORM - Queries That Read Like Code: Inside the codebase, Drizzle ORM replaces raw SQL, typed safe models map 1-to-1 tables, catching schema mistakes at compile time.

Relation Manager - Complex Links, Zero Join Tables: Drizzle Relation Manager lets us declare one-to-many and many-to-many links in plain Typescript. Under the hood, it generates optimised SQL with JOINs, but we stay unaware and we never create pointless join tables just to glue entities together.

4. Continuous Delivery: Migrations That Ship Themselves

Every pull request kicks off drizzle-migrate in CI: 

  1. Generate: Developers run ‘’run drizzle-kit generate” to create SQL files from model changes.

  2. Validate: The pipeline applies migrations to a disposable PR database.

  3. Promote: On merge, the same SQL runs against staging and production in order, guaranteeing deterministic versioning.

5. The Payoff: Slimmer Infra, Faster Teams, Safer Data

The result? Every engineer has full ownership of their data flow, from model definition to production queries, with complete autonomy and zero conflicts.

Our journey from DynamoDB sprawl to an RDS-plus-Drizzle powerhouse proves that you don’t have to choose between convenience and control. With the right tools, strict automation, and a culture that treats database ownership as a first-class feature, precision becomes the default, not a luxury.

Next
Next

Behind the Build: ZenML