Back to Engineering Blog
Architecture8 min read

Why We Chose Single-Table Design for Our Database

Composite keys, one partition per user, and the access patterns that made a single DynamoDB table simpler than four of them.

Glacro · Published August 8, 2026

Everything Glacro stores lives in one table. Users, projects, deployments, credit transactions, invoices, audit entries — one table, one set of keys.

The key design

text
PK = USER#<userId>
SK = PROFILE
     PROJECT#<projectId>
     DEPLOY#<deployId>
     TX#<timestamp>
     INVOICE#<invoiceId>

Every record belonging to one account shares a partition key. Loading a dashboard is a single query on USER#<id> that returns the profile, the projects and the recent deployments together, rather than three round trips to three tables that then have to be stitched back together in application code.

What it costs

Queries that cut across users — every project on the platform, every deployment today — do not fit the partition and need a secondary index. Those are almost entirely administrative, which makes the trade a comfortable one: the common path is fast and cheap, the rare path is a little awkward.

Key Takeaway
The uniqueness constraints are separate items, not attributes: a published URL is held by SLUG#<slug>, a phone number by PHONE#<number>. Deleting a project has to release its slug explicitly, or the name stays reserved against everyone forever.

Access goes through helpers

Routes never touch the storage driver directly. A small set of helpers — getItem, putItem, updateItem, queryByPK, queryByGSI — is the only way in. That is what makes the key convention above enforceable rather than aspirational.

Related Articles

Product Updates

What Glacro Actually Runs, and What It Doesn't

August 26, 2026 · 6 min read
Tutorials

Deploying a Next.js 14 Static Export

August 20, 2026 · 7 min read