> ## Documentation Index
> Fetch the complete documentation index at: https://docs.stackshift.cloud/llms.txt
> Use this file to discover all available pages before exploring further.

# Import and export a database

> Move complete PostgreSQL or MySQL databases as portable SQL with resumable uploads, private candidates, structural validation, explicit promotion, and 24-hour rollback.

<Tip>
  **Live.** This area is documented as current, user-reliable behavior.
</Tip>

## Goal

Export or import a complete database without staging full dumps in the API or changing production before a validated, explicitly confirmed cutover.

## Prerequisites

* A running PostgreSQL or MySQL database on the qualified hosted V2 `containerd` runtime
* A transfer-capable digest-qualified hosted agent and stable-endpoint lineage
* Project mutation permission for a project database, or ownership of a standalone database

## Workflow

<Steps>
  <Step>
    Open the database and select Import / Export.
  </Step>

  <Step>
    For export, choose SQL or compressed SQL and wait for verified completion before requesting a download.
  </Step>

  <Step>
    For import, select a `.sql` or `.sql.gz` file or provide a normal/presigned HTTPS URL and optional stored-byte SHA-256.
  </Step>

  <Step>
    Wait for fetch/upload, candidate provisioning, restore, and structural validation to complete.
  </Step>

  <Step>
    Inspect the validation report and use the candidate-only read-only workbench to confirm intended business data.
  </Step>

  <Step>
    Type the current database name exactly and explicitly promote the candidate.
  </Step>

  <Step>
    Smoke-test through the unchanged stable endpoint and keep the rollback deadline visible for 24 hours.
  </Step>
</Steps>

## Eligibility and exclusions

Import / Export is available on every active plan when the database and deployment are qualified. Eligibility is runtime-based, not plan-tier based.

* Supported: complete hosted V2 PostgreSQL and MySQL logical databases.
* Not supported: Redis, connected-node databases, selective tables, server-global users/roles/grants, custom URL authentication headers, or automatic promotion.
* One nonterminal import and one nonterminal export may exist for the same stable database. A second active transfer in the same direction returns conflict.

## Formats, compression, checksums, and limits

The accepted input is plain SQL or exactly one gzip-compressed SQL stream. Gzip is detected from magic bytes rather than the filename. ZIP, PostgreSQL custom format, bzip2, zstd, concatenated gzip members, trailing payloads, corrupt/truncated streams, and expansion-limit violations are rejected.

`expected_sha256`, when supplied, is the lowercase SHA-256 of the stored bytes before decompression. For `.sql.gz`, hash the gzip file itself.

```text Adaptive limits theme={null}
stored import limit = min(20 GiB, max(1 GiB, 2 × target disk))
expanded SQL limit = min(64 GiB, max(4 GiB, 4 × target disk))

plain export stored limit = expanded SQL limit
gzip export stored limit = 20 GiB
gzip export expanded dump must also remain within the expanded SQL limit
```

## Export behavior

* PostgreSQL exports schema and data without ownership or privilege statements.
* MySQL exports use a consistent transaction and include routines, events, triggers, and binary-safe values; incompatible nontransactional behavior is rejected.
* Server-global roles, users, grants, and unrelated databases are excluded.
* Dump-client, compressor, object upload, multipart completion, byte totals, and checksums are verified independently before completion.
* Generated filenames are sanitized and include database name, engine, UTC timestamp, and `.sql` or `.sql.gz`.

## Resumable browser upload

The browser hashes the file in 64 MiB slices and uploads parts directly to the private transfer bucket. The complete file never passes through the API process. Session and part progress are persisted in IndexedDB so a reload can resume after the same file is reselected.

* Every non-final part is exactly 64 MiB; the last part may be smaller.
* The manifest contains 1–320 ordered parts with exact sizes and lowercase SHA-256 checksums.
* Signed part URLs last 15 minutes and are bound to the exact object, part number, size, and checksum.
* Recreating an identical session reconciles provider-reported parts and returns URLs only for missing parts.
* Starting import verifies every part, completes multipart upload, and verifies the final provider checksum before restore is queued.

## Hardened HTTPS import

A normal or presigned HTTPS URL may include a query string, but cannot include userinfo, a fragment, or custom headers. The full URL is encrypted only until fetch completes; API responses, audits, metrics, and normal logs retain a query-free scheme/host/path form.

* At most five redirects; every destination is revalidated and authorization/cookie/proxy-authorization headers are stripped.
* TLS 1.2 or later with hostname verification, 10-second connect/TLS, 30-second response-header, 30-second no-progress, and six-hour overall limits.
* All DNS answers and the connected peer are checked; connections are pinned to an approved address to prevent DNS rebinding.
* Loopback, private, link-local, multicast, unspecified, metadata, carrier-grade NAT, benchmark, control-plane, and configured deployment networks are blocked.
* Stored-byte limits are enforced while streaming even when `Content-Length` is missing or misleading.

## Restore isolation

StackShift provisions a hidden private candidate on the same node, engine version, storage tier, and stable lineage as the active generation. Candidate credentials and physical identifiers are never returned, and the candidate never inherits public exposure.

SQL is treated as untrusted input and runs with a temporary database-scoped restore owner in a pinned ephemeral sandbox: non-root, read-only root filesystem, no host mounts, dropped capabilities, bounded CPU/memory/PIDs/time, and network access only to the candidate.

* PostgreSQL restore receives no superuser capability; ownership is reassigned before the temporary role is removed.
* MySQL restore receives candidate-database privileges only and never `FILE` or global privileges.
* PostgreSQL shell, unsafe `\copy`, and include commands and MySQL `system`, `source`, `tee`, and pager commands are rejected outside strings/comments.
* Fetch, hash, decompression, SQL guard, SQL client, compression, upload, and multipart status are preserved separately.

## Structural validation and candidate inspection

A candidate becomes `ready_to_promote` only after its current validation passes and immutable evidence is sealed. This proves structural integrity, not that you selected the intended dump or that your application logic will behave correctly.

* Stored and expanded checksums and complete SQL-client success.
* Database health and PostgreSQL `pg_amcheck` or MySQL extended table checks.
* Schema/table/object counts, per-table row-count summary, total rows, and canonical schema manifest.
* An immutable evidence hash binding artifact, candidate, engine, clients, checksums, and manifest.
* Candidate workbench: schema browsing plus one read-only statement, no semicolon, at most 500 rows, 2 MiB of result data, and 10 seconds.

## Promotion and rollback

Promotion is destructive to the logical contents served by the stable endpoint. It is available only after validation passes and requires the current database name as case-sensitive typed confirmation. The name and all evidence are checked again while the stable-endpoint lock is held.

StackShift makes the old generation read-only, switches the stable proxy lineage, reapplies and verifies proxy/firewall policy, and smoke-tests through the stable endpoint. If completion evidence is incomplete after routing may have changed, it attempts an automatic journaled rollback.

* The active database stays unchanged when upload, fetch, provisioning, restore, or validation fails.
* The replaced generation remains read-only for exactly 24 hours after successful promotion.
* Manual rollback is allowed only while that promoted generation remains current and before `rollback_deadline`.
* A newer promotion supersedes an older rollback action even though cleanup still honors the original retention deadline.

## Downloads, cancellation, expiry, and durable state

* Download appears only for a verified completed export. Each token is opaque, single-use, valid for 10 minutes, and rejects HTTP Range requests.
* Cancellation is cooperative and allowed only before promotion begins.
* Inactive failed, cancelled, expired, or rolled-back transfers can be purged early, but purge never shortens retained-generation rollback.
* The durable transfer states are `uploading`, `fetching`, `queued`, `exporting`, `restoring`, `validating`, `ready_to_promote`, `promoting`, `active`, `rolling_back`, `rolled_back`, `failed`, `cancelled`, `expired`, and `purged`.
* The UI polls about every two seconds while active, every ten seconds while rollback is available, refreshes on focus, and stops in terminal states.

## API route families and idempotency

The project and standalone transfer resources expose identical suffixes. All state-changing requests require an `Idempotency-Key` of 1–255 characters. Repeating the identical canonical request returns the original durable result; reusing the key with a different request returns conflict.

```text Transfer resources theme={null}
/api/v1/projects/{projectID}/databases/{databaseID}/transfers
/api/v1/databases/{databaseID}/transfers

GET    /
POST   /exports
POST   /upload-sessions
POST   /imports
GET    /{transferID}
POST   /{transferID}/download-url
POST   /{transferID}/cancel
POST   /{transferID}/promote
POST   /{transferID}/rollback
DELETE /{transferID}
GET    /{transferID}/candidate/schema
POST   /{transferID}/candidate/query
```

```json Create a gzip export theme={null}
{
  "format": "sql",
  "compression": "gzip"
}
```

```json Import from HTTPS theme={null}
{
  "source": {
    "kind": "url",
    "url": "https://objects.example.com/database.sql.gz?signature=...",
    "expected_sha256": "<64 lowercase hexadecimal characters>"
  }
}
```

## Expected result

<Check>
  The transfer completes durably; imports leave production untouched until explicit promotion, and successful promotion preserves the stable connection identity with a time-bounded rollback.
</Check>

## Common failures

<Warning>
  * Import / Export is hidden or returns not found: confirm the database is running qualified hosted V2 PostgreSQL/MySQL and that you used the correct project or standalone context.
  * Multipart upload is incomplete: reconcile the identical upload session and upload only the missing provider-reported parts before starting import.
  * Checksum mismatch: hash the stored file bytes; for gzip, hash the `.gz` file rather than expanded SQL.
  * URL blocked: every redirect, DNS answer, and connected peer must remain verified HTTPS and outside blocked/private/deployment networks.
  * Export pipeline failed: inspect the durable attempt evidence for the first failed dump-client, compressor, byte-limit, upload, multipart, or checksum stage.
  * Download returns not found: the 10-minute token expired, was already consumed by the first request/scanner, or the isolated download route is unavailable; request a fresh token after confirming service health.
  * Promote is unavailable: validation must currently pass, the candidate must be `ready_to_promote`, and the exact current database name is required.
  * Rollback is unavailable: the promoted generation must still be current and the exact 24-hour deadline must not have passed.
</Warning>

## Related guides

<CardGroup cols={2}>
  <Card title="Managed database overview" href="/databases/managed-database-overview">
    Understand project and standalone databases, stable endpoint identity, supported engines, recovery, and transfer eligibility.
  </Card>

  <Card title="Credentials, pooling, and usage expectations" href="/databases/credentials-pooling-and-usage">
    Use stable connection details, TLS, public-access policy, and pooler endpoints without relying on physical runtime addresses.
  </Card>

  <Card title="Back up and restore a database" href="/databases/back-up-and-restore-a-database">
    Use durable recovery storage correctly and understand why backups are independent from portable SQL transfers.
  </Card>

  <Card title="Database troubleshooting" href="/databases/database-troubleshooting">
    Diagnose provisioning, stable connectivity, backup, upload, export, validation, promotion, download, rollback, and cleanup failures.
  </Card>

  <Card title="Recovery states, logs, and troubleshooting" href="/operations/recovery-logs-and-troubleshooting">
    Read the operation state on a resource — its status, current step, attempt count, retryable flag, and last error — together with logs, instead of treating a single “error” badge as the whole story.
  </Card>
</CardGroup>
