---
term: 'Point-in-Time Recovery (PITR) & Backups in BaaS'
seoTitle: 'Point-in-Time Recovery (PITR) & Backups in BaaS'
headline: 'What is Point-in-Time Recovery (PITR)?'
slug: point-in-time-recovery-backups
category: database
shortDefinition: 'Point-in-time recovery is a restore method that replays a change log over a base backup to rebuild a database as of any chosen second.'
relatedTerms:
  - multi-tenant-database-architecture
  - data-encryption-at-rest-transit
  - database-schema
  - acid-transactions
contrastsWith:
  - data-encryption-at-rest-transit
faq:
  - question: 'What is point-in-time recovery in simple terms?'
    answer: 'A restore that can land on any moment, not just on scheduled backup times. The engine starts from a base backup and replays its change log — every committed write, in order — stopping at the second you name. Instead of losing everything since last night''s snapshot, you lose only what happened after 14:31:59, the second before the incident.'
  - question: 'What is the difference between a snapshot and PITR?'
    answer: 'Granularity. A snapshot is a photograph: restoring lands exactly on the moment it was taken, and everything after it is gone. PITR is a film: base backup plus continuous log capture lets you stop playback anywhere inside the retention window. Snapshots are simpler and cheaper to keep; PITR turns recovery from "which night?" into "which second?".'
  - question: 'What are RPO and RTO?'
    answer: 'The two numbers every backup conversation is secretly about. RPO — recovery point objective — is how much recent data you can afford to lose, set by backup or log-shipping frequency. RTO — recovery time objective — is how long restore may take, set by data size and restore mechanics. Daily snapshots give an RPO of hours; continuous log capture shrinks it toward seconds.'
  - question: 'Does replication replace backups?'
    answer: 'No — replication is availability, not recovery. A replica faithfully copies whatever the primary does, including the DROP TABLE you ran by mistake; within seconds every copy agrees on the damage. Backups and PITR exist precisely to reach a state *before* the error, which no amount of replication preserves. You need both, for different failure classes.'
  - question: 'How often should backups run?'
    answer: 'Work backwards from your RPO. If losing a day of writes is survivable, nightly snapshots suffice; if an hour hurts, add more frequent increments; if minutes matter, you need continuous log capture — at which point snapshot frequency governs restore speed rather than data loss. Whatever the schedule, retention length decides how far back mistakes remain fixable.'
  - question: 'Why do restore drills matter?'
    answer: 'Because an untested backup is a hypothesis, not a plan. Drills surface the failures that only appear under practice: silently broken exports, restores that take nine hours against a one-hour RTO, missing credentials, undocumented steps. A quarterly drill — restore to a scratch environment, verify data, time the process — converts the hypothesis into a rehearsed procedure.'
  - question: 'What should I check after a database restore?'
    answer: 'Verify the timeline first: the newest records should sit just before the recovery target, and nothing should exist after it. Then verify integrity — row counts against expectations, critical invariants, references that must resolve. Finally verify the application: log in, run core flows, confirm background jobs resume cleanly. Restores that "completed" can still be wrong in all three ways.'
  - question: 'Who handles backups in a BaaS — the platform or me?'
    answer: 'The mechanics are the platform''s: snapshots, log capture, storage, restore tooling. The objectives remain yours: choosing RPO and RTO for your product, knowing the retention window, running restore drills, and keeping an independent export if policy demands one. A managed backend removes the plumbing, not the responsibility for deciding what survivable loss looks like.'
codeLanguages: [javascript, dart, swift, kotlin]
externalAuthorities:
  - name: 'PostgreSQL — continuous archiving and PITR'
    url: 'https://www.postgresql.org/docs/current/continuous-archiving.html'
  - name: 'Recovery point objective (Wikipedia)'
    url: 'https://en.wikipedia.org/wiki/Recovery_point_objective'
  - name: 'MongoDB backup methods'
    url: 'https://www.mongodb.com/docs/manual/core/backups/'
  - name: 'NIST SP 800-34 — Contingency Planning Guide'
    url: 'https://csrc.nist.gov/pubs/sp/800/34/r1/upd1/final'
cta:
  title: 'Backups you configure in minutes, not maintain for years'
  text: 'Back4app runs scheduled backups of your managed database automatically, with restore available from the dashboard — so your team spends its recovery budget on choosing RPO targets and rehearsing drills, not on wiring log archiving.'
  linkText: 'Start building free'
  linkUrl: 'https://www.back4app.com/signup'
author: 'Back4app Engineering'
publishedDate: '2026-08-05'
translationKey: point-in-time-recovery-backups
---

**Point-in-time recovery is a restore method that replays a change log over a base backup to rebuild a database as of any chosen second.** The scenario it exists for is not hardware failure — replication handles that — but the human one: a migration that corrupted rows at 14:32, a script that deleted the wrong tenant. PITR answers with the only thing that helps: *the database exactly as it was at 14:31:59*.

## Key takeaways

| Question | Answer |
| --- | --- |
| Snapshot | A photograph — restore lands on the moment it was taken |
| PITR | Base backup + replayed change log — restore lands on any second |
| RPO | How much recent data you may lose — set by capture frequency |
| RTO | How long restore may take — set by size and mechanics |
| The split | A BaaS runs the mechanics; you still own the objectives and drills |

## The mechanism, in one working session

```sql
-- The change log is the raw material: every committed write, in order.
-- Before risky work, you can drop a named marker into it:
SELECT pg_create_restore_point('before_pricing_migration');

-- Recovery = base backup + replay, stopped where you say:
--   restore the base backup taken at 02:00
--   replay the log forward…
--   …and stop just before the damage:
--     recovery_target_time = '2026-08-05 14:31:59+00'
--     (or recovery_target_name = 'before_pricing_migration')

-- Everything committed before the target exists; nothing after it does.
```

This is the write-ahead log doing double duty: the same ordered record that gives [transactions their durability](/glossary/acid-transactions/) becomes, when archived continuously, a time machine. Document databases run the identical play with the oplog — capture the operation stream, replay onto a snapshot, stop on demand ([PostgreSQL calls it continuous archiving](https://www.postgresql.org/docs/current/continuous-archiving.html); [MongoDB documents the same architecture](https://www.mongodb.com/docs/manual/core/backups/) over filesystem snapshots).

After any restore, the drill's verification step is application-level — confirm the timeline landed where intended:

**JavaScript:**

```javascript
// JavaScript / Node.js — Back4app JS SDK
// Restore drill: verify the restored data lines up with the incident timeline
const incident = new Date('2026-08-05T14:32:00Z'); // when the bad deploy hit

const latest = new Parse.Query('Order');
latest.lessThan('createdAt', incident);
latest.descending('createdAt');
const lastGood = await latest.first();   // newest order before the incident

const after = new Parse.Query('Order');
after.greaterThanOrEqualTo('createdAt', incident);
const leaked = await after.count();      // must be 0 on a clean PITR restore

console.log(`last good write: ${lastGood?.get('createdAt')}`);
console.log(`rows past the recovery target: ${leaked}`);
```

**Flutter:**

```dart
// Flutter / Dart — Back4app Flutter SDK
// Restore drill: verify the restored data lines up with the incident timeline
final incident = DateTime.parse('2026-08-05T14:32:00Z'); // the bad deploy

final latest = QueryBuilder<ParseObject>(ParseObject('Order'))
  ..whereLessThan('createdAt', incident)
  ..orderByDescending('createdAt')
  ..setLimit(1);
final lastGood = await latest.query();   // newest order before the incident

final after = QueryBuilder<ParseObject>(ParseObject('Order'))
  ..whereGreaterThanOrEqualsTo('createdAt', incident);
final leaked = await after.count();      // must be 0 on a clean PITR restore

print('last good write: '
    '${(lastGood.results?.first as ParseObject?)?.createdAt}');
print('rows past the recovery target: ${leaked.count}');
```

**Swift:**

```swift
// iOS / Swift — Back4app Swift SDK
// Restore drill: verify the restored data lines up with the incident timeline
let incident = ISO8601DateFormatter()
  .date(from: "2026-08-05T14:32:00Z")!   // when the bad deploy hit

let latest = Order.query("createdAt" < incident)
  .order([.descending("createdAt")])
  .limit(1)
latest.first { result in                 // newest order before the incident
  if case .success(let lastGood) = result {
    print("last good write: \(String(describing: lastGood.createdAt))")
  }
}

let after = Order.query("createdAt" >= incident)
after.count { result in                  // must be 0 on a clean PITR restore
  if case .success(let leaked) = result {
    print("rows past the recovery target: \(leaked)")
  }
}
```

**Kotlin:**

```kotlin
// Android / Kotlin — Back4app Android SDK
// Restore drill: verify the restored data lines up with the incident timeline
val incident = Date(1754404320000L)      // 2026-08-05T14:32:00Z, the bad deploy

val latest = ParseQuery.getQuery<ParseObject>("Order")
latest.whereLessThan("createdAt", incident)
latest.orderByDescending("createdAt")
latest.limit = 1
latest.findInBackground { lastGood, _ -> // newest order before the incident
    println("last good write: ${lastGood?.firstOrNull()?.createdAt}")
}

val after = ParseQuery.getQuery<ParseObject>("Order")
after.whereGreaterThanOrEqualTo("createdAt", incident)
after.countInBackground { leaked, e ->   // must be 0 on a clean PITR restore
    if (e == null) println("rows past the recovery target: $leaked")
}
```

## How a restore reaches 14:31:59

```mermaid
flowchart LR
  accTitle: Point-in-time recovery flow
  accDescr: A nightly base backup is restored, then the archived change log is replayed forward in order until the configured recovery target just before the incident, producing a database state at the chosen second.
  B["Base backup<br/>(02:00 snapshot)"] --> R["Replay archived log<br/>02:00 → …"]
  L["Continuous log capture<br/>(WAL / oplog)"] --> R
  R -->|"stop at target:<br/>14:31:59"| S["Database as of<br/>the chosen second"]
  X["Incident at 14:32<br/>(bad migration)"] -. "never replayed" .-> S
```

Two properties fall out of the mechanism. First, **RPO is set by capture frequency**: logs shipped every few seconds mean seconds of maximum loss, regardless of when the last snapshot ran. Second, **RTO is set by replay distance**: restoring to 23:00 from a 02:00 base means replaying 21 hours of writes — which is why PITR systems still take frequent snapshots, not for granularity but to shorten the runway.

## Snapshots vs. PITR

| Dimension | Snapshots alone | PITR (base + log replay) |
| --- | --- | --- |
| Restore granularity | The moments snapshots ran | Any second in the window |
| Typical RPO | Hours (the schedule gap) | Seconds to minutes |
| Storage cost | Low — n copies | Higher — copies + continuous log archive |
| Restore speed | Fast — copy back | Slower — copy + replay |
| Human-error fit | Lose everything since last snapshot | Lose almost nothing before the error |
| Complexity | Minimal | Real — archiving, ordering, targets |

### Which recovery guarantee do you actually need?

| If losing… is survivable | Then you need | Watch |
| --- | --- | --- |
| A day of writes | Nightly snapshots | Retention length |
| An hour | Snapshots + frequent increments | Schedule actually firing |
| Minutes or less | Continuous log capture (PITR) | Archive lag — it *is* your RPO |
| Nothing, ever | PITR + synchronous replication | Cost and write latency, honestly priced |

## Common use cases

- **The bad deploy.** A migration or hotfix corrupts data mid-afternoon — restore to the second before it shipped.
- **Fat-finger deletions.** The wrong tenant, collection, or WHERE clause — recover to just before the statement ran, often into a scratch database to extract only what was lost.
- **Ransomware and account compromise.** Rewind to before the intrusion touched data — with [encryption at rest](/glossary/data-encryption-at-rest-transit/) guarding the archive copies themselves.
- **Compliance retention.** Regulated products must *prove* recoverability — documented windows, tested restores, auditable drills.
- **Pre-launch rehearsal.** The restore drill as a feature gate: teams that have restored to a timestamp once do it calmly the night it matters.

## Should you rely on default backups? A decision matrix

| Defaults are enough when… | Invest beyond them when… |
| --- | --- |
| Losing a day of data is annoying, not fatal | Writes are money — orders, ledgers, bookings |
| The product is pre-launch or internal | An hour of loss is a support catastrophe |
| Data is rebuildable from another source | The database is the only source of truth |
| Nobody has asked for recovery guarantees | A contract or regulator names RPO/RTO figures |
| You have never needed a restore | You have needed one — and it was tense |

Whatever the platform provides, three decisions stay yours: the **RPO** your product can survive, the **RTO** your users will tolerate, and the **drill cadence** that keeps both numbers honest — the discipline [NIST's contingency-planning guidance](https://csrc.nist.gov/pubs/sp/800/34/r1/upd1/final) formalizes as: define objectives, then test against them.

## Limitations and trade-offs

- **Replication is not recovery.** Replicas replicate the mistake within seconds; only backups reach *before* it. Different tools, different failure classes.
- **The window is finite.** PITR reaches any second — inside retention. Damage discovered after the window closes is permanent; size retention to detection time, not storage price alone.
- **Replay takes time.** Log-heavy restores can run long; your real RTO is measured by drills, not quoted by dashboards.
- **Restores land whole.** Classic PITR rebuilds the database at a timestamp; extracting one table's lost rows means restoring to a scratch instance and copying across — plan for that workflow.
- **An untested backup is a rumor.** Silent export failures, expired credentials, missing runbooks — every one is invisible until a drill or a disaster finds it. Drills are cheaper.

## PITR and backups on Back4app

Back4app is an open-source Backend-as-a-Service (BaaS) platform that combines a managed database, auto-generated REST and GraphQL APIs, authentication, file storage, and Cloud Code serverless functions. Backups of the managed database run on schedule without setup, and restore is a dashboard operation rather than a night of log archaeology — the snapshots-and-mechanics half of this article, absorbed by the platform. The half that stays with you is the deciding: your RPO and RTO targets, your retention needs, and the quarterly drill where the code tabs above verify that the restored timeline is exactly the one you asked for.
