---
title: "Keep personal data in the person's own country"
description: "Mark fields as vaulted so a vault in the person's country holds the values and your database keeps only tokens, with reads allowed only for a stated purpose."
section: "guides"
status: "Planned for 1.2"
spec: "residency-vaults"
canonical: "https://mainsdk.dev/docs/guides/store-personal-data-in-country"
updated: "2026-10-28"
---

# Keep personal data in the person's own country

> Mark fields as vaulted so a vault in the person's country holds the values and your database keeps only tokens, with reads allowed only for a stated purpose.

Status: Planned for 1.2 · Canonical: https://mainsdk.dev/docs/guides/store-personal-data-in-country · Updated: 2026-10-28

You will send the personal fields of people in countries beyond MainSDK's three regions to a vault in their own country, and read them back only for an allowed purpose. It takes about 30 minutes plus a vault account.

## You need

- A MainSDK app with `db` and `keys` configured.
- An account with a vault provider: InCountry, Skyflow, VGS, Basis Theory or Piiano.

## 1. Mark the fields

```yaml title="main.yaml"
markets: [in, ae]
db:
  fields:
    user.name: { label: personal, vault: true }
    user.phone: { label: personal, vault: true }
vault:
  driver: incountry
  countries: [in, ae]
  locations: { in: loc-in, ae: loc-ae }
  route: { by: user.country }
```

A field labelled `pan` is refused: card numbers are never stored, so hand card data to `pay`. `mainsdk check` fails when a market is outside `vault.countries` (`MAIN-DATA-0181`) and when a query filters on the raw value of a vaulted field (`MAIN-DATA-0180`).

## 2. Write and read through `Vaults`

`Vaults` from `mainsdk/vault` takes the fields, a driver client, the locations and a purpose policy. `write` sends the vaulted values to the vault in the row's country and returns the row with tokens such as `tok_ae_<ref>`. A row with no vaulted field never touches the vault. `read` fills in real values only where the policy allows the viewer and purpose, and audits every detokenise; otherwise the field comes back as `{ token, redacted: true }`.

## 3. Erase through the vault

Register `vaultEraseHook` with `privacy.register("vault", ...)`. It deletes the person's tokens and throws until the vault confirms, so the signed erasure record lists the vault only once the data is gone.

## 4. Keep personal data out of model prompts

`redactorFromConfig` from `mainsdk/vault-redact` builds a redactor for `ai.redact`: the built-in one masks email addresses, card numbers and phone numbers, and `agentcloak` calls AgentCloak. Values are restored in the reply only when policy allows.

## Check it worked

Run `npx mainsdk check`. In a test, write a row for a UAE user against `fakeInCountry` from `@mainsdk/testing` and confirm the database row holds only the token.
