Storage and recovery architecture is the way a production app separates runtime, persistent data, durable files, backups, and restore paths before something fails.
For small teams, this matters because storage decisions often happen accidentally. The first VM holds the app, the database, user uploads, generated reports, logs, backup exports, and temporary files. That can work at the beginning, but it creates risk as the product grows. A full disk can bring down the app. A bad deployment can mix runtime failure with data recovery. A missing restore path can turn a simple incident into long downtime.
Raff Technologies gives teams separate building blocks for this problem: Raff VM for compute and app runtime, Raff Volumes for disk-like persistent storage, Raff Object Storage for durable file objects, and Raff Data Protection for snapshots, automated backups, retention, and recovery workflows.
This guide is intentionally architectural. It is not a generic block storage explainer, a backup definition article, or a step-by-step restore tutorial. It answers one practical question: what should live where so a production app can grow and recover cleanly?
If you need the narrower storage decisions first, read Block Storage Volumes for Databases, Containers, and App Data, When to Add a Volume Instead of Resizing a VM Disk, and Restore Testing Checklist for Production VMs.
Production storage should be separated by responsibility
A production app should not treat every byte as the same kind of data.
The operating system, app runtime, database files, user uploads, generated reports, backup exports, logs, and temporary processing files all behave differently.
A clean architecture separates storage by responsibility:

This separation makes the system easier to reason about.
When something fails, the team can answer:
- What failed?
- What data is affected?
- What is rebuildable?
- What must be restored?
- Which recovery point should be used?
- Which storage layer owns the data?
- What can be safely deleted?
- What must be protected?
The goal is not to add complexity. The goal is to avoid making one VM disk responsible for every production concern.
A production app should separate runtime, persistent data, durable files, and recovery points before failure forces the decision.
The quick architecture framework
Use this table as the starting point.

| Workload or data type | Better default | Why |
|---|
| Operating system | VM disk | Part of the server runtime |
| App packages and runtime | VM disk | Rebuildable with the server |
| App configuration | VM disk or secret/config system | Must be documented and recoverable |
| PostgreSQL or MySQL data directory | Managed database or block volume | Needs durable database storage |
| Docker persistent data | Block volume | Needs filesystem persistence |
| User uploads | Object storage | Should live outside the VM lifecycle |
| Generated reports | Object storage | Durable file objects should be separate |
| Media files | Object storage | Easier to retain and share |
| Temporary processing workspace | VM disk or block volume | Depends on size and lifetime |
| Backup exports | Object storage | Retained artifacts should not depend on the VM |
| VM snapshots | Data protection | Short-term recovery points |
| Automated backups | Data protection | Scheduled recovery history |
| Restore evidence | Runbook and test notes | Proof that recovery works |
A useful rule:
VM disk is for runtime. Volumes are for disk-like data. Object storage is for durable files. Backups are for recovery points.
This rule is not perfect, but it prevents many early architecture mistakes.
VM disk is for runtime, not everything
The VM system disk should mostly support the server runtime.
It usually holds:
- Operating system
- System packages
- App runtime
- Deployment files
- Local service files
- Some logs
- Temporary files
- Basic configuration
That is a reasonable job for the VM disk.
The problem begins when the VM disk also becomes the long-term home for:
- Database data
- User uploads
- Media library
- Backup archives
- Generated reports
- Persistent container data
- Large imports
- File-processing workspace
- Long-term logs
- Everything the app ever writes
That mix creates recovery confusion.
If the VM disk fails or needs to be restored, the team has to recover runtime and data together. If uploads grow quickly, the team may resize the whole VM. If logs fill the disk, the database may be affected. If the VM must be rebuilt, file migration becomes harder.
Use the VM disk for what can be rebuilt or redeployed.
A healthy VM disk model:
VM system disk
↓
OS
Packages
App runtime
Service definitions
Local logs with retention
Temporary files with cleanup
A risky VM disk model:
VM system disk
↓
OS
App runtime
Database
Uploads
Reports
Archives
Logs forever
Backups
Temporary processing
The second model works until it suddenly does not.
Block volumes are for disk-like persistent data
Block storage volumes are useful when the workload needs disk behavior but should not live on the VM system disk.
Common volume use cases include:
- Database data directories
- Docker persistent data
- Self-hosted service data
- App-generated local files
- Processing workspace
- Search index data
- Stateful container directories
- Media-processing scratch space
- Development environment storage
- Workload-specific persistent paths
A volume gives the data a clearer boundary.
Raff VM
↓
System disk = OS and app runtime
↓
Raff Volume = database files, container state, app data, workspace
This helps when storage grows faster than compute.
For example, a VM may still have enough CPU and RAM, but its database data may need more disk. Adding a volume can solve the storage problem without turning every disk issue into a VM sizing decision.
A volume is especially useful when:
- Data should be separated from the OS
- Storage should grow independently from compute
- A mount path should have a clear owner
- Disk usage needs specific alerts
- Snapshots should target a specific data area
- The team needs clearer restore planning
- Containers need persistent state
- A self-hosted database needs a dedicated data directory
A volume is not a dumping ground. It should have a purpose, mount path, owner, and recovery policy.
Object storage is for durable file objects
Object storage is usually the better home for files that should not depend on one VM.
Use object storage for:
- User uploads
- Product images
- Profile images
- Documents
- PDFs
- Generated reports
- Export files
- Import files
- Media files
- Backup archives
- Static assets
- Artifacts
- Files accessed by workers or functions
A common production pattern:
App VM
↓
Managed Database stores metadata
↓
Object Storage stores files
The database stores records, permissions, and object keys. Object storage stores the actual files.
This avoids turning the app server into a long-term file server.
Object storage is usually better when files need to:
- Survive VM rebuilds
- Be shared across services
- Be retained independently
- Be accessed by workers or functions
- Avoid filling the system disk
- Scale beyond one app server
- Store archives or generated artifacts
A volume can still help with temporary file processing.
Example:
Object Storage input
↓
Worker VM with attached volume for processing
↓
Object Storage output
↓
Database metadata
Use object storage for durable files. Use volumes for active disk-like work.
For the upload decision, read App Uploads: VM Disk vs Object Storage for SaaS Teams.
Managed databases can remove storage operations
Not every database should be self-hosted on a VM and volume.
A self-hosted database gives the team control, but it also gives the team operational responsibility.
The team must plan:
- Disk layout
- Backups
- Restore testing
- Replication
- Upgrades
- Monitoring
- Connection limits
- Storage growth
- Failure recovery
- Security and access controls
A managed database can move much of that operational burden away from the app VM.
A practical decision:
Need maximum database control?
↓
Self-host on VM with dedicated volume
Want less database operations work?
↓
Use managed database
For many small teams, Raff Managed Databases may be the cleaner default once the application handles real users.
A volume-based database is not wrong. It just needs an owner and a recovery plan.
For the detailed decision, read Managed vs Self-Hosted Databases.
Snapshots and backups are recovery points, not architecture
Snapshots and backups are part of recovery architecture, but they are not the whole architecture.
A snapshot can help recover from a bad change. A backup can provide scheduled recovery history. Object storage archives can retain exported files or database backups. But none of those alone tells the team what data belongs where or how to restore the service.
A clean model:
Storage architecture
↓
Defines what lives where
Data protection
↓
Creates recovery points
Restore testing
↓
Proves those recovery points work
Use snapshots for:
- Pre-deploy recovery points
- Pre-migration recovery points
- Short-term rollback
- Risky configuration changes
- Fast operational recovery
Use backups for:
- Scheduled recovery history
- Longer retention
- Disaster recovery
- Production safety
- Recovering from deletion or corruption
Use object storage archives for:
- Exported database backups
- Retained reports
- Backup artifacts
- Compliance-style archives
- Files that should live outside the VM
Raff Data Protection supports snapshots, automated backups, retention options, replicated storage, and recovery workflows. Use it as part of a full recovery plan, not as a substitute for storage design.
Restore testing proves the architecture works
A backup strategy is incomplete until restore has been tested.
The team should know whether it can restore:
- VM boot
- SSH access
- App service
- Database state
- Attached volumes
- Object storage access
- Firewall rules
- Private network routes
- DNS or test hostname
- Secrets and credentials
- Logs and monitoring
- Cleanup path
A tested restore answers the question:
Can we get this app back into a usable state?
That is different from asking whether a snapshot or backup exists.
A restore test should usually happen in an isolated temporary environment:
Production VM
↓
Snapshot or backup
↓
Temporary restore VM
↓
Private verification
↓
Document result
↓
Delete test resources
This protects production while proving the recovery path.
For the detailed checklist, read Restore Testing Checklist for Production VMs.
Example architecture for a small SaaS app
A simple SaaS app often needs four storage layers.
Raff VM
↓
App runtime and API server
Managed Database
↓
Users, accounts, records, billing state
Object Storage
↓
Uploads, reports, exports, attachments
Data Protection
↓
Snapshots, backups, restore testing
This is a clean architecture because each layer has a clear job.
The VM runs the app. The database stores records. Object storage stores files. Data protection creates recovery points. Restore testing proves the path back.
This is usually better than:
One VM disk
↓
App + database + uploads + reports + backups + logs
That single-disk model is simple at first, but it creates scaling and recovery problems later.
A SaaS team should move uploads and generated files out of the VM disk early. The database should either be managed or clearly separated. The app server should remain replaceable.
Example architecture for a Docker app
A Docker app needs extra care because containers are easy to recreate.
A practical Docker layout:
Raff VM
↓
Docker Compose runtime
Raff Volume
↓
Persistent container data
Object Storage
↓
Uploads, reports, media files
Data Protection
↓
Snapshots, backups, restore tests
Use a volume when containers need persistent filesystem data.
Examples:
- Database container data
- Self-hosted app data
- Plugin state
- Search index data
- Queue state
- Stateful service directories
Use object storage when files should not depend on the container host.
Examples:
- User uploads
- Reports
- Exports
- Media
- Backup archives
A Docker app can be simple, but storage must be intentional. Rebuilding containers should not delete important data.
Example architecture for a database-heavy app
A database-heavy app has stricter recovery needs.
A self-hosted database model:
Raff VM
↓
Database service
Raff Volume
↓
Database data directory
Data Protection
↓
Snapshots around risky changes
Database backups
↓
Exported backups retained separately
This model can work when the team wants database control.
But the team must still handle:
- Database-aware backups
- Restore testing
- Disk usage alerts
- Replication if needed
- Upgrade planning
- Corruption recovery
- Access controls
- Retention rules
A managed database model:
Raff VM
↓
App runtime
Managed Database
↓
Database records and operations
Object Storage
↓
Backup exports or data artifacts where needed
This model is often cleaner when the team wants less database operations work.
Use volume-based databases for control. Use managed databases for operational simplicity.
Example architecture for an upload-heavy app
Upload-heavy apps should not keep user files on the VM disk for long.
A cleaner model:
User upload
↓
App VM validates request
↓
Object Storage stores file
↓
Managed Database stores metadata and permissions
↓
Worker or function processes file if needed
This helps when the app has:
- Images
- PDFs
- CSV files
- Customer documents
- Report exports
- Audio or video
- Backups or generated artifacts
If files need processing, use temporary compute and write the final output back to object storage.
Object Storage input
↓
Raff Function or worker VM
↓
Temporary processing space
↓
Object Storage output
↓
Database status update
This keeps durable files outside the VM lifecycle.
For file-triggered workflows, read Object Storage Events on Serverless Functions: File Processing Without Workers.
Example architecture for a worker-heavy app
Some apps depend on background workers.

Examples:
- Queue workers
- Report generators
- Media processors
- Import processors
- AI or ETL jobs
- Scheduled jobs
- Webhook processors
- File conversion tasks
A worker-heavy architecture might look like this:
App VM
↓
Receives user requests
Database or queue
↓
Stores work state
Worker VM or Raff Function
↓
Processes jobs
Raff Volume
↓
Temporary disk-like workspace when needed
Object Storage
↓
Inputs, outputs, archives
Data Protection
↓
Recovery points and restore testing
Use functions when jobs are event-driven and bounded. Use worker VMs when the processing environment needs persistent services, custom binaries, SSH debugging, or always-on capacity.
Storage should follow the job.
If the job needs temporary disk, use a volume. If the job creates durable files, use object storage. If the job updates records, use the database.
Cost planning should include recovery cost
Storage cost is not only active disk size.
A production architecture should include:
- VM disk
- Attached volumes
- Object storage
- Snapshots
- Backups
- Backup retention
- Restore test resources
- Temporary processing storage
- Database storage
- Logs and monitoring
- Engineering time
A cheap layout can become expensive during an incident.
For example:
Low monthly cost:
Everything on one VM disk
Possible incident cost:
Long restore time
Unclear data ownership
Mixed app and database recovery
Large backup size
Manual file recovery
Customer downtime
A better cost question:
What does it cost to recover this app?
Sometimes the cleaner architecture costs a little more each month but reduces operational risk. Sometimes a simple single-VM layout is enough for an early product. The decision should be intentional.
Storage and recovery checklist
Use this checklist before calling an app production-ready.
Runtime
Persistent data
Files and objects
Protection
Recovery
Common mistakes to avoid
Putting everything on the VM disk
This is simple at first, but it mixes runtime, data, files, logs, and recovery into one place.
Separate data when growth or recovery matters.
Using volumes for uploads by default
User uploads are usually better in object storage.
Use volumes when the workload needs disk behavior.
Treating snapshots as architecture
Snapshots create recovery points. They do not decide what should live on the VM disk, volume, or object storage.
Forgetting database-aware backups
A VM-level recovery point may not be enough for database recovery.
Production databases need database-aware backup planning.
Never testing restores
A backup that has never been restored is an assumption.
Restore testing turns the assumption into evidence.
Keeping backup archives on the same VM
If the VM fails, archives stored only on that VM may not help.
Retained backup artifacts should often live outside the VM.
Adding storage without ownership
Every volume, bucket, backup, and restore path should have an owner.
Unowned storage becomes forgotten infrastructure.
Production architecture should be recoverable by design
Storage architecture and recovery architecture should be designed together.
Use Raff VM for compute and runtime. Use Raff Volumes when a workload needs disk-like persistent storage. Use Raff Object Storage for uploads, reports, media, backup archives, and durable file objects. Use Raff Data Protection for snapshots, automated backups, retention policies, and recovery workflows. Use restore testing to prove that those choices work together.
The goal is not to build the most complex architecture. The goal is to make sure each layer has a clear job.
When a production app fails, the team should not need to guess where the data lives, which backup matters, or how to bring the service back.
A recoverable architecture is one the team can explain, test, and repeat.