Engineering
Everything we have filed under this category.
2 items

Multi-tenant SaaS without the pain
Every successful SaaS platform reaches the same moment: dozens, then hundreds of tenants on the same infrastructure, and one question deciding the product's future — was multi-tenancy designed in from the start, or patched on later? The gap between those two is the gap between quiet growth and nights of cross-customer data-leak incidents. In this article we summarize the isolation, authentication, and billing patterns we apply at Grid when building multi-tenant platforms that scale without the pain.Choose your isolation model deliberately — not by accidentThe isolation decision is the platform's most important architectural choice, with three main patterns:Database per tenant — strongest isolation and easiest compliance, but operational cost multiplies with every customer. Right for large clients and strictly regulated sectors.Shared schema with a tenant ID — the most operationally efficient and fastest to grow, but it puts the entire isolation burden on code discipline.Hybrid — shared schema for the general tier, dedicated databases for those who pay for isolation. The pattern most mature platforms end up with.There is no "correct" model — there is the model that fits today's customers while leaving the door open for tomorrow's.The tenant ID flows through every layer — and defense has multiple linesIn the shared model, the worst possible incident is a query that forgot the tenant filter and showed one customer's data to another. Protection isn't left to human attention; it's built in layers: a mandatory tenant context on every request, a data-access layer that adds the filter automatically and can't be bypassed, and row-level security (RLS) in the database as a last line of defense that works even when the code is wrong.Then automated tests that deliberately attempt cross-tenant access — failing the build in CI before the hole ever reaches production.Authentication: identity is one thing, membership is anotherThe pattern that lasts: one identity per user, multiple tenant memberships, and roles per membership. That handles the real-world cases smoothly — a consultant working with three companies, an employee moving between teams — without duplicate accounts. And with your first enterprise customer comes the SSO request (SAML or OIDC); build the integration point early, because it's a deal requirement, not a luxury feature.Billing starts with meteringYou can't bill what you don't measure. From day one, record usage per tenant — active users, storage, API calls, or whatever unit reflects value in your product — in an event stream independent of the billing logic itself. Then you can lay any pricing model on top of the data: plans, pay-as-you-go, or a mix, and change it later without a rebuild.And connect plan limits to actual enforcement: a plan promising ten users must be enforced by the system automatically, with a polite upgrade prompt rather than a cryptic error.The noisy neighbor: resource fairnessOn shared infrastructure, one heavy tenant — a million-row import, a runaway integration — can slow the platform for everyone. Prevention: rate limits per tenant rather than per system, processing queues that separate heavy work from the interactive path, and per-tenant monitoring that shows who is consuming what before the others start complaining.Migrations across a fleet of databasesIf you chose database-per-tenant, every schema migration becomes a fleet operation: automation that rolls the migration out gradually, verifies success per database, and halts the rollout at the first failure. Without it, tenants drift across schema versions — a mess that's very hard to come back from.A pain-free multi-tenancy checklistIs your isolation model a documented, deliberate decision — not an inherited default?Does the tenant ID flow mandatorily through every layer, with RLS as the last line of defense?Is identity separate from membership, with an SSO integration point ready for enterprise customers?Do you meter usage per tenant from day one, with limits enforced automatically?Do you have per-tenant rate limits and segmented monitoring that exposes the noisy neighbor?The bottom lineMulti-tenancy isn't a feature you add later; it's a lens you design every layer through: isolation, identity, metering, and operational fairness. Platforms that build it in grow from ten customers to a thousand quietly; platforms that patch it on pay in incidents and customer trust. Early investment here is the cheapest insurance for your product's future.At Grid we design multi-tenant SaaS platforms from scratch and fix multi-tenancy pain in existing ones. If you're building your platform or preparing for your first enterprise customer, get in touch.

Choosing a model-agnostic architecture
Every few months a new AI model arrives that beats its predecessor on capability, price, or both. A product that hardcoded one provider's API calls throughout its codebase faces two painful options: a sweeping rewrite, or staying on an aging model and paying for it in performance and cost. A model-agnostic architecture dissolves that dilemma at the root: you build your product once and swap models underneath it freely. In this article we explain how we design that layer at Grid and what we've learned from running it in real products.Why neutrality is a strategic decision, not a technical luxuryThree reasons make hard-coupling to a single provider a risk. First, the race is fierce — today's best model can be third place within months. Second, prices move constantly, and the cost gap between two models capable of the same task can reach 10x. Third, compliance and data-residency requirements may demand tomorrow a model that runs inside your geography or your own infrastructure.Couple your product to the task it solves, not to the model that happens to run it today.One abstraction layer separates the product from the providerRule one: product code never calls a provider directly. Every call goes through a single internal interface that translates requests to each provider's format, normalizes response shapes and tool calls, and handles errors, retries, and fallback when a provider goes down.The interface is defined in your product's terms — "summarize", "classify", "extract" — and beneath it lives a configuration file that maps each task to a model. Changing the model becomes a one-line config edit, not a rewrite project.Route each task to the model it deservesNot every call needs the strongest, most expensive model. Smart routing classifies the work:Complex tasks — deep analysis, code generation, multi-step reasoning: the strongest model.Volume tasks — classification, field extraction, short drafting: a small fast model at a fraction of the cost.Sensitive tasks — data that must not leave your infrastructure: a self-hosted model or one inside the required region.In many products, 80% of calls are volume tasks that a cheaper model serves at comparable quality — routing alone can cut the bill severalfold.Prompts are managed assets — not scattered stringsFree swapping assumes the instructions themselves are portable. We store prompts outside the code, versioned with a change history, and allow per-model variants where needed — because optimal phrasing differs between models. The result: trying a new model never touches product code at all.Evaluation is the safety valveFreedom to swap means nothing without a way to know the swap is safe. For each task we build an evaluation suite from real cases with clear success criteria, and any candidate model runs through it before touching production. The numbers settle the debate: equal or better quality, at lower cost, at acceptable latency — or no swap.After the swap, monitoring continues in production on real samples, because a model's behavior on your actual data can differ from its eval-suite results.A warning: don't over-engineerModel-agnostic doesn't mean building a huge platform on day one. If your product calls one model in two places, a single wrapper function and an organized prompt file are enough. Build the full layer when tasks and models genuinely multiply — neutrality is an architectural habit that starts small, not a big upfront project.A model-agnostic checklistDoes every model call go through one internal abstraction layer?Does a config file — not code — decide which model serves which task?Are your prompts stored with versions and per-model variants?Do you have an evaluation suite per task that settles swap decisions with numbers?Do you track cost and latency per task and per model in production?The bottom lineThe model market will keep moving for years, and the winner isn't whoever bets on the right horse — it's whoever builds a carriage whose horses swap easily. A clean abstraction layer, task-based routing, managed prompts, and evaluations that settle decisions: with these pieces, every new model becomes an opportunity you capture in days, not a threat that demands a rebuild.At Grid we design AI architectures for products that want to profit from the race instead of being burned by it. If your product is locked to a single provider and you want to decouple safely, get in touch.