Why Forge Apps Don't Store Your Data Outside Atlassian
Forge apps run inside Atlassian's own cloud — code executes on Atlassian-operated runtime, storage lives in Atlassian-provisioned Forge SQL and Forge KVS in your tenant's region, and outbound network access is blocked by default. Unlike Connect apps (which pull Jira data into the vendor's servers), Forge keeps everything inside Atlassian's boundary. For regulated industries, that flips the compliance calculus.
This is the technical companion to the pillar on Forge vs Connect security. Below is the architecture behind the claim “Forge apps don't store your data outside Atlassian” — and the specific cases where it bends.
What does “runs inside Atlassian” actually mean technically?
Three concrete things: the app's compiled code executes on Atlassian-operated serverless infrastructure, its persistent storage is provisioned by Atlassian in the tenant's region, and its network egress is gated by the Forge runtime itself. None of these three layers exist on the vendor's own cloud account. The vendor pushes source code through the Forge CLI; from that point forward, Atlassian is the operator. Under Connect, your Jira data lives temporarily on the vendor's servers every time the app processes a request. Under Forge, it doesn't — the vendor's code touches it, but only inside infrastructure Atlassian controls.
Where does a Forge app's code execute?
Backend functions execute in an Atlassian-operated serverless runtime, per the Forge runtime reference. Each resolver, trigger, and async event consumer runs in an isolated sandbox with tight time limits (25 seconds for standard resolvers, 900 seconds for async events). The function cannot open arbitrary network sockets, read from the filesystem beyond its own bundle, or persist state between invocations except via Forge Storage APIs. Custom UI apps serve their frontend from an Atlassian-controlled origin in a cross-origin iframe; the bridge wraps every resolver call in a short-lived JWT scoped to the installation and the current user, so the vendor never sees raw credentials.
Where does a Forge app's data persist?
Forge gives apps three persistent storage primitives, all operated by Atlassian: Forge SQL (MySQL-compatible, per-installation, up to 1 GiB in production), Forge KVS (per-installation key-value store), and app storage for entities (a higher-level API over the same primitives). See the Forge storage documentation. Every store is provisioned in the tenant's region and scoped to the installation context.
When a Forge app is installed on ten Jira tenants, Atlassian provisions ten separate SQL databases and ten separate KVS namespaces — one per tenant. The vendor's code running for Tenant A has no way to query Tenant B's data, because the storage handle returned by the Forge SDK is bound to the calling installation at the runtime layer. Backups, encryption at rest, and key management are handled by Atlassian under the same controls that back Jira itself. A Forge vendor cannot leak data by misconfiguring an S3 bucket, because they do not own the bucket.
Can a Forge app make outbound API calls?
Yes — but only under an explicit, admin-approved declaration. The Forge manifest includes a permissions.external.fetch block (see the permissions reference) where the vendor lists the exact domains the app wants to reach. At install time, the admin sees this list and must approve it. The runtime enforces the allowlist: any fetch() call to a domain not on the manifest fails at the platform layer before the request leaves the runtime.
A Forge app that declares no external.fetch cannot reach the public internet. It can still call Jira and Confluence REST APIs through the Forge product-API wrapper (those stay inside Atlassian's boundary), but it cannot fetch() anything else. For buyers, the external.fetch block is a definitive egress inventory — if the list is empty, there is no egress; if it names api.openai.com, that is the only place data can flow.
How is this different from a Connect app?
A Connect app reverses the hosting relationship. The vendor runs the full app — HTTP server, database, scheduler, logs — on their own infrastructure. Atlassian sends signed webhook events to the vendor's server; the vendor's server calls Jira REST APIs back into the tenant. Every Jira page that embeds a Connect app panel loads an iframe from the vendor's domain, not from Atlassian. Cached issues sit in the vendor's database, in whatever region the vendor chose, where the vendor's engineers can query them, back them up, pipe them into their observability stack, and ship metrics to their analytics vendor. Each of those is additional ground your security team has to cover.
| Dimension | Forge app (default) | Connect app |
|---|---|---|
| Code execution | Atlassian-operated serverless runtime | Vendor's own servers (AWS / GCP / colo) |
| Primary data storage | Forge SQL / Forge KVS in tenant's region | Vendor-operated database (region chosen by vendor) |
| Outbound network egress | Blocked unless declared in manifest | Unrestricted — vendor code can call any URL |
| Admin consent at install | Explicit egress allowlist shown and approved | Grouped permission grant, no per-domain review |
| Tenant isolation | Per-installation storage, runtime-enforced | Vendor implementation-dependent |
What does this mean for GDPR, HIPAA, and SOC 2?
Under GDPR, a Connect vendor is a full sub-processor whose hosting region, sub-processor chain, and data-handling practices must be documented in your DPA and reviewed annually. A Forge vendor that declares no external.fetch is a much narrower sub-processor — their code processes the data, but the data never reaches vendor-controlled infrastructure. HIPAA follows the same logic: Atlassian offers a BAA for Jira Cloud, and a Forge app inherits the runtime, storage, and egress controls that back it. A Connect app handling PHI requires a separate vendor BAA covering its own hosting environment. SOC 2 Type II works similarly — the Forge app inherits Atlassian's audited infrastructure controls; the vendor still has to document SDLC and operational controls, but the platform layer is not theirs to build. See the data residency buyer's guide for the region-by-region breakdown and the Atlassian compliance page for the current certification list.
When does a Forge app still touch external services?
The “zero egress” claim describes the default Forge posture, not a universal guarantee for every app. Any app can declare external.fetch to reach specific outbound domains, and some categories legitimately need to: LLM-backed assistants calling OpenAI or Anthropic, notification integrations posting to Slack or Microsoft Teams, billing integrations calling Stripe. Each is a declared egress path the admin approved at install. Two specific cases to watch for: email notifications usually flow through an external provider like SendGrid or Amazon SES, which must be declared; and LLM calls to an external inference provider transit prompts and responses outside Atlassian (Atlassian's own Forge LLM API keeps inference inside). The Cloud Fortified program — detailed in our Cloud Fortified guide — sets additional operational bars but does not mandate zero egress.
For the record, Foundation declares no external.fetch in its manifest. Every row of Jira data Foundation reads or caches stays in Forge SQL and Forge KVS provisioned in your tenant's region. See the Foundation security page for the full posture — manifest scopes, storage layout, residency inheritance, and audit artifacts we can provide for enterprise reviews.
Sources
- Forge security model — Atlassian Developer docs
- Forge manifest permissions reference (scopes and external.fetch)
- Forge storage documentation
- Forge runtime reference
- Atlassian Trust Center — compliance and certifications
- Atlassian Cloud Fortified apps program
- Atlassian data residency — supported regions
Frequently asked questions
Can a Forge app send my Jira data to an external server?
Only if the app declares an external.fetch permission in its manifest naming the specific outbound domains, and only if the Jira admin approves those domains at install time. A Forge app that declares no external.fetch cannot reach the public internet at all — the runtime blocks the attempt at the platform layer. This is not a vendor promise, it is a runtime guarantee enforced on infrastructure the vendor does not control.
Where is Forge app data physically stored?
Inside Atlassian's cloud, in the same region as the Jira tenant that installed the app. If your Jira site is pinned to the EU, the app's Forge SQL database, Forge KVS key-value store, scheduled-job state, and event-queue state all live in an EU region provisioned by Atlassian. The vendor has no knob to override this. A Forge app cannot choose to store its data in the vendor's own AWS account or colocation facility, because no such account or facility is in the data path.
What's the difference between Forge SQL and a vendor-hosted database?
Forge SQL is a per-installation MySQL-compatible database that Atlassian provisions, operates, backs up, and encrypts for each Forge app install. A vendor-hosted database (the Connect-app pattern) is operated by the vendor on their own cloud account, with their own backups, their own encryption keys, and their own sub-processors. Under Forge, the vendor writes SQL queries; Atlassian runs the database. Under Connect, the vendor runs everything.
Does this mean my Jira data is completely inaccessible to the vendor?
The vendor's code reads and writes your data during normal operation — that's how the app works. What the vendor cannot do, under the default Forge posture, is move the data onto infrastructure the vendor controls. The vendor's engineers cannot SSH into the storage tier, dump a database, or pull a snapshot to their own laptops. Support access to customer data follows Atlassian's access-control rules, not the vendor's.
If a Forge app uses an LLM, does data leave Atlassian then?
It depends on which LLM. If the app uses Atlassian's own Forge LLM API (currently in early access), the inference happens inside Atlassian's boundary and no data leaves. If the app declares an external.fetch permission targeting OpenAI, Anthropic, or another model provider, that provider becomes a sub-processor and data in the prompt is subject to that provider's retention policy. The manifest tells you exactly which case applies — there is no ambiguity.
Is a Forge app's storage tenant-isolated?
Yes. Forge SQL and Forge KVS are per-installation — each Jira tenant that installs the app gets its own isolated database and KV namespace. The vendor's code cannot query across tenants even if it wanted to, because the Forge runtime scopes every storage call to the installation context of the request. Cross-tenant data leaks in a well-built Forge app require a platform-level bug, not a vendor-level one.