Use location in your app
Get a coarse location hint from the declared platform's headers and geocode addresses through network, never for access decisions.
Status Status is where the work is: Planned (in a milestone, not started), Building (tickets in progress), Preview (usable, may change), then the stability it ships at.
Stability The promise an interface ships with.
- Stable Follows semantic versioning; breaking changes need a new major, 12 months of overlap and a codemod.
- Beta Usable in production; may change before it becomes stable.
- Experimental May change or go away; needs an explicit opt-in in main.yaml.
You will read a location hint for a default, geocode an address and see what MainSDK refuses. It takes about 15 minutes. The hint is for defaults only: a place guessed from a network address is wrong for people on a VPN or roaming, so it never decides who gets in.
You need
- A MainSDK app with a
main.yaml(see Thirty-minute path). - For geocoding, a Mapbox or Google Maps Platform key kept in your secrets manager.
1. Declare your platform
geo.of reads the headers of one platform, the one your app declares. Set deploy.target to vercel, cloudflare or fly. On Docker or Node behind CloudFront, set geo.edge instead.
deploy:
target: vercel
geo:
driver: platform-headersHeaders from any other platform are ignored, so a visitor cannot give your app a place by sending them. Fly sends no country header, so set x-mainsdk-country from your own GeoIP step.
2. Use the hint for a default
import { geo } from "mainsdk/geo";
export async function GET(request: Request) {
const { country, timezone } = geo.of(request);
return Response.json({ currency: country === "IN" ? "INR" : "USD", timezone: timezone ?? "UTC" });
}The hint holds a country, region, city and time zone, each checked, and never an IP address. When the platform sends nothing the fields are missing, so always have a fallback.
3. Geocode an address
Switch the driver and add the key as a secret reference.
geo:
driver: mapbox
key: secret:MAPBOX_TOKEN"use server";
import { geo } from "mainsdk/geo";
export async function placeFor(address: string) {
return geo.geocode(address); // a Place, or null
}The address goes through network to a host that serves the tenant's region, and the place is cached for the tenant. Your code does not change when you swap mapbox for google-maps. When the provider is down you get null: show the typed address and carry on. A tenant in a region the driver does not serve fails with MAIN-GEO-0004 before anything is sent.
4. Keep the hint out of access
Do not pass the hint to policy, access or auth.require. They throw MAIN-GEO-0001, and mainsdk check reports MAIN-GEO-0002 for geo.of used in access code. For country rules on protected files use protect policy.
5. Test it with no network
import { createTestApp } from "@mainsdk/testing";
import { geo } from "mainsdk/geo";
createTestApp({ yaml: "schema: 1\ngeo:\n driver: local\n" });
const place = await geo.geocode("1 Main St, Springfield"); // from the kit's table, no networkCheck it worked
Run npx mainsdk check. It passes when geo.driver is one of platform-headers, mapbox or google-maps, a provider driver has key: secret:NAME, a platform is declared where geo.of is used, and no access code reads the hint.
Was this page helpful?