Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Database Backup Laravel Package

marekmiklusek/database-backup

A Laravel package for creating database backups with Artisan commands and scheduler support. Configure where dumps are stored, automate regular backups, and keep your application data protected with minimal setup.

View on GitHub
Deep Wiki
Context7

Getting Started

This release is gated on PHP 8.4+ and Laravel 13. If your app is on Laravel 11 or 12 you cannot upgrade — pin the previous major and treat the security fixes below as unpatched risk in your own environment (restrict the backup directory, or upgrade the app first). Check composer.json constraints before anything else; the package now pulls individual illuminate/* components rather than laravel/framework, so a composer update no longer silently drags your framework version around.

Minimal path from zero to a working nightly backup:

  1. composer require the package, then publish the config: php artisan vendor:publish --tag=<config-tag> (see the README for the exact tag; the class now exposes its config name as a constant rather than a container binding).
  2. Set storage.disk to the disk where the .sql dump lands. If you use Google Drive as the destination, either keep the credentials disk named google or set the new storage.google_disk key to whatever you actually call it.
  3. Fill in database credentials and the notification settings (mail recipient / on-success / on-failure). Both email and storage options were undocumented before this release — read the README sections again even if you have been running the package for a while, because your setup may be relying on defaults you never chose.
  4. Run one backup manually and confirm a file appears on the target disk and, if enabled, that the notification arrives.
  5. Add the schedule entry (see below) only after step 4 succeeds.

The first use case to wire up is the obvious one: nightly mysqldump to a local disk plus a Google Drive copy, with retention keeping N days. Once that is running, add failure notifications before you add retention — a silent failure is worse than a full disk.

Upgrading checklist: run php artisan config:clear and re-cache. Config is now merged in register() instead of boot(), which means stale cached config from the old version can produce confusing half-applied state. Then verify storage.google_disk and, if you have use_both_disks enabled with a local primary disk, expect it to start working for the first time — see the gotchas.

Implementation Patterns

Scheduling. Register the backup command in routes/console.php or Kernel::schedule() at an hour that does not collide with your other cron work, and chain withoutOverlapping() — the credentials-file collision fixed in this release was a real concurrency bug, but overlapping backups still compete for disk and Drive quota. onOneServer() if you run multiple app servers against the same database.

Local-then-cloud with use_both_disks. This is the pattern the flag exists for: storage.disk names your local disk, storage.google_disk names the Drive disk. Before this release that combination was broken and threw Config key [client_id] not found; it now works. If you had a workaround in place — repointing storage.disk at the Google disk, or duplicating the Drive credentials onto the local disk — remove it, or you will end up with the credentials configured in two places and only one of them maintained.

Retention. Configure the retention window explicitly rather than relying on the default. The behavioural contract after this release is narrower than before: cleanup only removes files matching the package's own {prefix}_{date}.sql pattern. That is the fix (it used to delete anything in the directory), but it also means any file you renamed, hand-placed, or generated with a different prefix is now permanent. If you post-process dumps into .sql.gz with your own script, that script owns the cleanup.

Failure handling. Wrap invocations in your own try/catch only if you need to do something the package's failure notification does not — e.g. alert PagerDuty or write an audit row. The package's own cleanup of the temporary credentials file is now in a finally block, so exceptions no longer leak the file; do not add your own temp-file management around it.

Integration tips.

  • For multi-tenant or multi-database apps, run one scheduled job per database with a distinct prefix so retention does not cross-delete between them. The {prefix}_{date}.sql matcher means prefixes must actually differ.
  • If you assert on backups in your own test suite, assert against the filename the package generates rather than file count in the directory — the directory-scoped behaviour changed.
  • The package now ships 75 tests and 100% type coverage, so upgrading it is low risk to your app, but that says nothing about your configuration. Add a smoke test that runs the command against a throwaway SQLite/MySQL instance in CI.

Gotchas and Tips

The credentials file is now 0600 — and that can break things. The file is created empty, chmodded to 0600, then written. If the process that runs mysqldump is a different user from the one that runs your consumer (e.g. queue worker vs. web user, or a supervisor-configured cron user), the write will now fail where it previously succeeded on 0644. Symptom: permission-denied errors that only appear on the scheduler, never when you run the command by hand in your shell. Fix by aligning users, not by loosening the permission.

Concurrent-safe temp files mean you cannot predict the path. Each run gets a unique filename. Any monitoring, log-scraping, or lsof-style debugging that assumed a fixed name needs updating.

Retention uses filename dates, falling back to mtime — not ctime. Previous versions dated by ctime, which moves on chmod, chown, and rsync. That means environments where an rsync or a permissions sweep ran over the directory had retention silently stop, and old backups accumulated until the disk filled. After the upgrade, expect the first cleanup run to delete a large backlog at once. Check disk usage and run one cleanup manually off-hours before letting cron do it, or you will see a suspicious mass-deletion event in your storage metrics.

Cleanup no longer touches foreign files. If you were relying — accidentally — on the package emptying the backup directory, you now have to manage your own artifacts. Conversely, if you had a paranoid check for "cleanup deleted my unrelated file", you can drop it.

use_both_disks with a local primary disk starts working on upgrade. Treat this as a behaviour change, not just a bug fix: setups that were silently failing may now begin uploading to Drive for the first time, consuming quota and bandwidth. Audit your Drive storage before you deploy, and confirm storage.google_disk points at the disk that actually holds the credentials if you ever renamed it from google. The default is google, so untouched setups need no change.

Config merges in register(). Package defaults are now available outside the console — useful for reading config in a web request or a health-check route — but it also means a cached config file from the old version is actively wrong after upgrading. Always config:clear before config:cache during deploy.

The configName container binding is gone. It is a class constant now. If any of your code did app('configName') or similar, it fails at resolve time. Rare, but it is a genuine break beyond the PHP/Laravel bump.

Debugging a backup that produces nothing. Order of checks: (1) can the scheduler user read the DB credentials and write to storage.disk; (2) does the target disk resolve with the right config — this is where the old use_both_disks bug hid; (3) is mysqldump on the PATH of the cron user, not your interactive shell; (4) did a notification fire? Failure notifications were documented only in this release, so a pre-existing install may never have been told about failures at all. Configure them.

Extension points. The config file is the only real extension surface: disk names, prefix, retention, notification recipients. There is no plugin system, and the new static-analysis/Rector/Pint tooling applies to the package's own source, not yours — do not expect those configs to be publishable into your app.

Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
mrnewport/laravel-plaid
mrnewport/laravel-repo
mrnewport/laravel-docsign
mrnewport/laravel-stow
mrnewport/laravel-flow
mrnewport/laravel-priceable
mrnewport/laravel-nestedterms
fredmeng/laravel-apidoc-generator
itstructure/laravel-multilingual-tools
pdustdar/elasticsearch
markupai/php-sdk
rlacerda83/lumem-microservice-shipment
uni-method/symfony-lib
tacticmedia/scim-server-bundle
neika-ai/symfony-bundle
mattleads/agent-publishing-bundle
glavweb/framework-bundle
glavweb/extra-bundle
glavweb/api-bundle
glavweb/admin-bundle