Skip to content

Production checklist

Run through this before you launch an app built on VAIF Studio.

  • Publishable key in clients, secret key on servers only. A secret key (vk_srv_…) bypasses row rules, so it must never be in a browser or an app bundle. See API key types.
  • Separate keys for each environment, and rotate any key that was ever committed or shared.
  • Row rules on every table with user data, tested with two different users. A table with no rules is open to every signed-in user, for reading and writing. See Row rules.
  • Public rules only on visitor-facing tables. A request with no signed-in user is denied everywhere else. Check that each public rule allows reading only, unless the table really takes anonymous writes, such as a contact form.
  • Every page that signs users in is on the redirect URL list (social sign-in and magic links), with exact origins, including each preview address you test with.
  • Catch SDK errors and show users a friendly message instead of the raw error.
  • Handle 429 by waiting Retry-After seconds. The SDK retries reads on 429 and 5xx; writes are not replayed, so retry a write only when you know it is safe to repeat.
import { createVaifClient, VaifError, VaifRateLimitError } from "@vaifstudio/client";
const vaif = createVaifClient({
baseUrl: "https://api.vaif.studio",
projectId: process.env.VAIF_PROJECT_ID,
apiKey: process.env.VAIF_PUBLISHABLE_KEY,
});
async function loadPosts() {
try {
const { data } = await vaif.from("posts").limit(20).list();
return data;
} catch (error) {
if (error instanceof VaifRateLimitError) {
console.warn(`Rate limited; try again in ${error.retryAfter ?? 1}s`);
} else if (error instanceof VaifError) {
console.error("Could not load posts:", error.code, error.requestId);
}
return [];
}
}
console.log((await loadPosts()).length);
  • Environment variables set for each environment: the API URL, project ID and key.
  • Secrets kept in secrets management (vaif secrets set), not in code or in .env files committed to git.
  • Know your backups. A dedicated database is backed up automatically, with point-in-time recovery; the shared database has neither.
  • Schema changes as migration files, applied with vaif db push and reviewed like code. See Migrations.
  • Indexes on the columns you filter and sort by.
  • Pagination everywhere: a list returns a limited number of rows per request, so page through with limit and offset.
  • Realtime instead of polling for live data. See Realtime.