Database checkpoints for Laravel local development (SQLite only)
Tyro Checkpoint is a simple Laravel package that provides Git-like checkpoint functionality for your SQLite database during local development. Create snapshots of your database state and restore them instantly when needed.
- Create full database snapshots with a single command
- List all available checkpoints with metadata
- Restore any checkpoint to reset your database state
- Delete old checkpoints to save disk space
- Lock checkpoints to prevent accidental deletion
- Add notes to checkpoints for better organization
- Encryption support to secure your database snapshots
- SQLite only (perfect for local development)
- Simple and production-safe
- No configuration required
- PHP 8.1 or higher
- Laravel 10.x, 11.x or 12.x
- SQLite database
Install the package via Composer:
composer require hasinhayder/tyro-checkpoint --devThe package will automatically register itself via Laravel's package discovery.
Run the installation command to setup everything:
php artisan tyro-checkpoint:installThis will:
- Check your SQLite database configuration
- Create the checkpoint storage directory
- Create the checkpoints metadata file (checkpoints.json)
- Optionally create an initial checkpoint
That's it! You're ready to create checkpoints.
Note: No database migrations are needed as checkpoint metadata is stored in a JSON file.
If you want to secure your checkpoints, you can generate an encryption key:
php artisan tyro-checkpoint:generate-keyThis will add a secure TYRO_CHECKPOINT_ENCRYPTION_KEY to your .env file. If a key already exists, the command will warn you before replacing it.
Publish the configuration file to customize settings:
php artisan tyro-checkpoint:publish-configThis creates config/tyro-checkpoint.php where you can customize the storage path.
Create a checkpoint with an auto-generated name:
php artisan tyro-checkpoint:createCreate a checkpoint with a custom name:
php artisan tyro-checkpoint:create my_feature_before_changesCreate an encrypted checkpoint:
php artisan tyro-checkpoint:create secure_snapshot --encryptExample output:
Creating checkpoint...
✓ Checkpoint created successfully!
ID: 1
Name: my_feature_before_changes
Size: 2.45 MB
Created: 2026-02-01 10:30:15
View all available checkpoints:
php artisan tyro-checkpoint:listExample output:
Found 3 checkpoint(s):
+----+---------------------------+---------+---------------------+--------+-----------+-------+
| ID | Name | Size | Created At | Locked | Encrypted | Note |
+----+---------------------------+---------+---------------------+--------+-----------+-------+
| 3 | before_user_migration | 2.48 MB | 2026-02-01 14:20:00 | No | No | |
| 2 | after_seeding | 2.45 MB | 2026-02-01 12:15:30 | Yes | Yes | Clean |
| 1 | clean_database | 1.98 MB | 2026-02-01 10:00:00 | No | No | |
+----+---------------------------+---------+---------------------+--------+-----------+-------+
Restore a checkpoint by ID:
php artisan tyro-checkpoint:restore 1Or restore by name:
php artisan tyro-checkpoint:restore clean_databaseYou'll be asked to confirm before the restore happens. If no identifier is provided, you can choose from a list:
Available checkpoints:
+----+---------------------------+---------+---------------------+-----------+-------+
| ID | Name | Size | Created At | Encrypted | Note |
+----+---------------------------+---------+---------------------+-----------+-------+
| 2 | after_seeding | 2.45 MB | 2026-02-01 12:15:30 | Yes | Clean |
| 1 | clean_database | 1.98 MB | 2026-02-01 10:00:00 | No | |
+----+---------------------------+---------+---------------------+-----------+-------+
Select a checkpoint to restore (enter 0 to quit):
[0] Quit
[1] #2 - after_seeding (encrypted) (Note: Clean)
[2] #1 - clean_database
>
Important: Checkpoints are NOT deleted after restoration. You can restore the same checkpoint multiple times, allowing you to experiment with different approaches and always return to the same state.
Add a descriptive note to help you remember what a checkpoint represents:
php artisan tyro-checkpoint:add-note 1You'll be prompted to enter your note:
Enter note for checkpoint #1 (or press Enter to remove existing note):
> Clean state with seeded users
The note will be displayed when you list checkpoints.
Lock a checkpoint to prevent accidental deletion:
php artisan tyro-checkpoint:lock 1Unlock a checkpoint to allow deletion:
php artisan tyro-checkpoint:unlock 1Locked checkpoints cannot be deleted individually or via the flush command. This is useful for preserving important baseline states.
Delete a checkpoint by ID:
php artisan tyro-checkpoint:delete 1Or delete by name:
php artisan tyro-checkpoint:delete clean_databaseYou'll be asked to confirm before deletion. Note that locked checkpoints cannot be deleted:
Checkpoint to delete:
ID: 2
Name: after_seeding
Size: 2.45 MB
Created: 2026-02-01 12:15:30
Note: Clean state
Are you sure you want to delete this checkpoint? (yes/no) [no]:
Delete all unlocked checkpoints at once with the flush command:
php artisan tyro-checkpoint:flushLocked checkpoints are preserved. You'll see a list of checkpoints to be deleted:
⚠ WARNING: This will delete ALL unlocked checkpoints permanently!
Checkpoints to be deleted:
+----+---------------------------+---------+---------------------+--------+
| ID | Name | Size | Created At | Locked |
+----+---------------------------+---------+---------------------+--------+
| 3 | before_user_migration | 2.48 MB | 2026-02-01 14:20:00 | No |
| 1 | clean_database | 1.98 MB | 2026-02-01 10:00:00 | No |
+----+---------------------------+---------+---------------------+--------+
Total: 2 checkpoint(s) (1 locked checkpoint will be preserved)
Are you sure you want to delete ALL unlocked checkpoints? (yes/no) [no]:
Skip the confirmation prompt with the --force flag:
php artisan tyro-checkpoint:flush --force- Checkpoints are full snapshots: Each checkpoint is a complete copy of your SQLite database file (no diffs or incrementals)
- Stored locally: Checkpoint files are stored in
storage/tyro-checkpoints/ - Metadata tracking: Checkpoint metadata (ID, name, path, size, created_at, locked, note) is stored in
storage/tyro-checkpoints/checkpoints.json- outside the database to prevent loss when restoring - Restore process: Restoring a checkpoint replaces your current database file with the selected checkpoint file
- Persistent checkpoints: Checkpoints are NOT automatically deleted after restoration. You can restore the same checkpoint multiple times and must manually delete checkpoints when no longer needed.
- Safe restoration: Because metadata is stored outside the database, you never lose track of any checkpoint, even when restoring to an earlier state
- Lock protection: Locked checkpoints are protected from deletion to preserve important baseline states
- Automatic Decryption: If a checkpoint is encrypted, the restore command will automatically decrypt it using your
TYRO_CHECKPOINT_ENCRYPTION_KEYbefore replacing your database.
# Create and lock a clean baseline
php artisan tyro-checkpoint:create clean_baseline
php artisan tyro-checkpoint:lock clean_baseline
php artisan tyro-checkpoint:add-note clean_baseline
# Enter: "Fresh install with migrations and seeders"
# Now you can safely flush all other checkpoints
php artisan tyro-checkpoint:flush
# Your locked baseline is preserved!
# Restore to baseline anytime
php artisan tyro-checkpoint:restore clean_baselinephp artisan tyro-checkpoint:create before_migration
php artisan migrate
# If something goes wrong:
php artisan tyro-checkpoint:restore before_migration
# The checkpoint is still available for future restoresphp artisan tyro-checkpoint:create clean_state
php artisan db:seed
# Test your application
php artisan tyro-checkpoint:restore clean_state
# Test again with fresh data - checkpoint is preserved
php artisan tyro-checkpoint:restore clean_state
# Can restore as many times as neededphp artisan tyro-checkpoint:create before_experiment
# Make manual database changes
# Test your changes
php artisan tyro-checkpoint:restore before_experiment
# Try a different approach
php artisan tyro-checkpoint:restore before_experiment
# Try yet another approach - same checkpoint, multiple restoresDisplay package version and system information:
php artisan tyro-checkpoint:versionThis shows:
- Package version and history
- Laravel and PHP versions
- Documentation and GitHub links
Re-run the installation setup:
php artisan tyro-checkpoint:installUseful when:
- Setting up the package on a new environment
- Verifying your SQLite configuration
- Creating the checkpoint storage directory
Publish the configuration file:
php artisan tyro-checkpoint:publish-configThis creates config/tyro-checkpoint.php where you can customize:
- Checkpoint storage path
Checkpoint files and metadata are stored at:
storage/tyro-checkpoints/
├── checkpoints.json # Metadata for all checkpoints
├── checkpoint_name_1.sqlite # Database snapshot 1
├── checkpoint_name_2.sqlite # Database snapshot 2
└── ...
- checkpoints.json: Contains metadata (ID, name, path, size, created_at, locked, note) for all checkpoints
- {checkpoint_name}.sqlite: The actual database snapshot files
Important: The metadata is stored in a JSON file (not in the database) so that restoring a checkpoint doesn't cause you to lose track of other checkpoints.
Publish the configuration file to customize settings:
php artisan tyro-checkpoint:publish-configThe published configuration file (config/tyro-checkpoint.php) allows you to customize:
return [
// Custom storage path for checkpoints
'storage_path' => storage_path('tyro-checkpoints'),
// Encryption key (automatically set via artisan tyro-checkpoint:generate-key)
'encryption_key' => env('TYRO_CHECKPOINT_ENCRYPTION_KEY'),
];- SQLite only: This package only supports SQLite databases. It will throw an error if you try to use it with MySQL, PostgreSQL, or other database drivers.
- Local development only: This package should only be used in local development environments. Install it as a dev dependency with
--dev. - Not for production: Never use this package in production environments.
- In-memory databases not supported: SQLite
:memory:databases cannot be checkpointed. - Metadata stored outside database: Checkpoint metadata is stored in a JSON file, not in the database itself. This ensures you never lose track of checkpoints when restoring.
- Checkpoints persist after restore: Checkpoints are NOT automatically deleted when restored. This allows you to restore the same checkpoint multiple times to test different approaches.
- Manual cleanup required: Use
php artisan tyro-checkpoint:deleteorphp artisan tyro-checkpoint:flushto remove checkpoints you no longer need. - Disk space: Each checkpoint is a full copy of your database, so they can consume disk space. Delete old checkpoints you no longer need.
- Locked checkpoints: Locked checkpoints are protected from deletion. Use this to preserve important baseline states.
- Encryption: Encrypting checkpoints secures the database snapshots. Ensure you back up your
TYRO_CHECKPOINT_ENCRYPTION_KEY, as losing it will make all encrypted checkpoints impossible to restore. Replacing a key will also invalidate older encrypted checkpoints.
The package includes comprehensive error handling:
- Non-SQLite database: Error if your database driver is not SQLite
- In-memory database: Error if using
:memory:SQLite database - Missing database file: Error if the database file doesn't exist
- Duplicate name: Error if creating a checkpoint with an existing name
- Missing checkpoint: Error if trying to restore/delete a non-existent checkpoint
- Locked checkpoint: Error if trying to delete a locked checkpoint
- File operations: Error if checkpoint file operations fail
Contributions are welcome! Please feel free to submit a Pull Request.
This package is open-sourced software licensed under the MIT license.
Created by Hasin Hayder
If you encounter any issues or have questions, please open an issue on GitHub.