Custom Domains
Serve your app on your own domain — add it, create two DNS records, and TLS is issued and renewed automatically. Subdomains and apex domains supported.
Every app gets a stable https://<app-id>.pandastack.ai URL. Custom domains let
you serve the same app on your own domain — app.acme.com, or the apex
acme.com — with TLS issued and renewed automatically. No certificates to
manage, nothing to renew, nothing extra to pay.
How it works
- Add the domain to your app (dashboard, API, or SDK).
- Create two DNS records at your DNS provider — the exact records are
shown when you add the domain:
- a TXT record that proves you control the domain, and
- a CNAME pointing the domain at
ingress.pandastack.ai(apex domains use ALIAS/ANAME instead — see below).
- Wait for DNS to propagate — verification and certificate issuance then
complete automatically, typically within a few minutes. The domain shows
pending → verified → active; atactiveit serves traffic.
Your custom domain behaves exactly like the default URL: blue-green deploys, scale-to-zero and wake-on-request, previews of build logs — everything is identical. The domain survives every deploy.
Adding a domain
Open your app → Custom domains → enter the domain → Add domain. The panel shows the DNS records to create and live status; it refreshes automatically until the domain is active.
curl -X POST https://api.pandastack.ai/v1/apps/$APP_ID/domains \
-H "Authorization: Bearer $PANDASTACK_API_KEY" \
-H "Content-Type: application/json" \
-d '{"domain": "app.acme.com"}'The response's records array lists the DNS records to create. Poll
GET /v1/apps/{id}/domains/{domain} until status is "active".
import { PandaStack } from "@pandastack/sdk";
const ps = new PandaStack();
const d = await ps.apps.addDomain(appId, "app.acme.com");
for (const r of d.records) {
console.log(`${r.type} ${r.name} → ${r.value}`);
}
// later:
const status = (await ps.apps.getDomain(appId, "app.acme.com")).status;from pandastack import PandaStack
ps = PandaStack()
d = ps.apps.add_domain(app_id, "app.acme.com")
for r in d["records"]:
print(f"{r['type']} {r['name']} → {r['value']}")
# later:
status = ps.apps.get_domain(app_id, "app.acme.com")["status"]Apex domains
A bare apex (acme.com) cannot hold a CNAME record — that's a DNS rule, not
ours. Use whichever your DNS provider offers:
- ALIAS / ANAME record →
ingress.pandastack.ai(Route 53, DNSimple, NS1, …) - CNAME flattening (Cloudflare does this automatically for apex CNAMEs)
The TXT verification record works the same either way.
Statuses
| Status | Meaning | What to do |
|---|---|---|
pending | Waiting for your TXT record | Create the records; DNS can take minutes to propagate |
verified | Ownership proven, certificate issuing | Nothing — usually completes in minutes |
active | Serving traffic with TLS | Done |
error | Something actionable is wrong | Read the message — it names the exact problem (record missing, points elsewhere, …) |
The dns_note field always describes what the platform currently observes
("TXT not found yet", "DNS points at X, expected Y"), so you never have to
guess which record is wrong.
Already proxying through Cloudflare? If your domain is on Cloudflare with the orange cloud on, issuance still works — but during initial setup prefer DNS-only (grey cloud) for the record if activation seems stuck, and re-enable proxying after the domain turns active.
Removing a domain
Deleting a domain stops traffic on it immediately and deprovisions its certificate. Deleting the app removes all of its domains automatically.
Limits & notes
- A domain can be attached to one app at a time, across all workspaces — first verified owner holds it.
- Wildcard domains (
*.acme.com) are not supported; add each hostname. - The verification TXT record is safe to delete after the domain turns
active— a working production domain is never torn down because a verification record was cleaned up later.
Environment Variables & Secrets
Give your app config and secrets — injected at build and runtime, encrypted at rest, masked in the API, scoped to production or previews, and never leaked to logs or PR comments.
Snapshot & Restore
How a sandbox boots in 49 ms — the path from snapshot file on disk to sshd accepting connections.