rorecek/laravel-autoincrement
A small Laravel utility for working with auto-increment IDs, offering helpers to inspect and manage increment values on Eloquent models and tables.
Install
composer require rorecek/laravel-autoincrement
The package is a single-purpose utility, so there is nothing to publish or configure. On Laravel 5.5+ package discovery registers whatever service provider it ships with; on older versions check the README for a manual providers entry in config/app.php.
Where to look first
README.md — the entire public surface is usually one or two methods, so the README is the API reference.src/ — with a package this small (12 stars, a single responsibility), read the whole source before using it. It is almost certainly a thin wrapper around ALTER TABLE ... AUTO_INCREMENT = n, and knowing exactly which connection/quoting logic it applies saves you a debugging session later.composer.json — check the illuminate/* constraints against your Laravel version. Small packages age out; if the constraint caps below your framework version, you will need a fork or to inline the logic.First use case
The canonical problem: you seed a table, or truncate it between test runs, or import legacy rows with explicit id values. MySQL keeps the counter where it was, so the next insert jumps to an unexpected number (or collides). Reset it once and the table behaves predictably again:
// illustrative — confirm the exact signature against the source
use Rorecek\AutoIncrement\Facades\AutoIncrement;
AutoIncrement::set('users', 1); // next inserted row gets id = 1
If the package exposes a trait instead of a facade, the shape is typically:
AutoIncrement::setAutoIncrement('users', 1000);
// or a fluent/table-scoped helper
Start by wiring it into DatabaseSeeder::run() after your seeders finish — that is the highest-value, lowest-risk adoption point.
1. Reset after seeding
public function run()
{
$this->call([
RolesSeeder::class,
UsersSeeder::class,
]);
// keep IDs tidy so local/staging data is easy to reason about
AutoIncrement::set('users', User::max('id') + 1);
}
Seeding with explicit IDs is the common cause of a stale counter; recomputing from max('id') is more robust than hardcoding.
2. Test isolation
If your suite uses RefreshDatabase with transactions, the counter is untouched between tests and IDs drift upward forever — which breaks assertions like assertDatabaseHas('users', ['id' => 1]). If you truncate instead, reset explicitly:
protected function setUp(): void
{
parent::setUp();
foreach (['users', 'posts', 'comments'] as $table) {
AutoIncrement::set($table, 1);
}
}
Note that transactional tests will not roll back an ALTER TABLE (see Gotchas), so prefer truncation + reset, or accept monotonic IDs and stop asserting on them.
3. Legacy import with preserved IDs
When importing rows that carry their original primary keys, set the counter after the insert so new records continue past the imported range:
DB::transaction(fn () => $this->importLegacyRows());
AutoIncrement::set('orders', Order::max('id') + 1);
4. Centralize it behind your own helper
Because the package is tiny, wrap it once so you can swap drivers or replace it later without touching call sites:
class TableSequences
{
public static function reset(string $table, int $value = 1): void
{
AutoIncrement::set($table, $value);
}
}
5. Loop over a whitelist, never user input
Table names cannot be bound as parameters, so the package interpolates them into DDL. Keep the list static:
foreach (config('database.reset_tables') as $table) {
AutoIncrement::set($table, 1);
}
6. Artisan command for developer ergonomics
A php artisan db:reset-sequences command that calls the package over a configured table list pays for itself quickly on teams where seeded IDs keep drifting.
Driver support is the big one. AUTO_INCREMENT is MySQL/MariaDB syntax. Postgres uses sequences (setval(pg_get_serial_sequence('users','id'), 1, false)) and SQLite uses the sqlite_sequence table. A package this narrow almost certainly assumes MySQL; verify against your test matrix (sqlite for tests is the classic trap — your resets will silently no-op or throw). Consider an explicit driver check that throws rather than a silent failure.
ALTER TABLE implicitly commits. In MySQL, DDL is not transactional. You cannot roll back an auto-increment reset, and calling it inside DB::transaction() will commit the surrounding work early. Keep sequence resets outside transactions — which means no clean rollback in migrations that use them.
Setting a value below the current maximum is silently ignored. MySQL resets the counter to max(id) + 1 regardless of what you asked for. If you are trying to renumber a table, this package will not do it — you have to delete and reinsert rows. The failure mode is silent, so log the value you applied and re-read it if correctness matters.
Privileges. ALTER is a stronger grant than INSERT/SELECT. On managed databases and read replicas the statement will fail; production app users typically should not have ALTER. Scope this to local, CI, and seeding contexts.
Table prefixes and quoting. If config('database.connections.mysql.prefix') is set, verify the package respects it — otherwise you will target the wrong table name. Backtick-quote identifiers yourself if the package does not.
Concurrency is not handled. max('id') + 1 read-then-write is racy under load. Never run resets against a live table receiving inserts; do it during seeding or in a maintenance window.
MySQL 8.0 vs 5.7 behavior. In 8.0 the auto-increment counter is persisted across server restarts; in 5.7 (InnoDB) it is recomputed as max(id) + 1 on startup. Tests that pass locally on 8.0 can behave differently on an older CI image.
Long-term risk. With 12 stars and a score of 0.12, treat this as a snippet, not infrastructure. If you only need the reset in a handful of places, inlining the three lines of SQL removes a dependency and gives you control over driver branches:
DB::statement("ALTER TABLE `{$table}` AUTO_INCREMENT = {$value}");
Extension points. Check whether the package accepts a connection name (AutoIncrement::on('mysql_import')->set(...)); if not, and you run multi-connection setups, you will need to wrap it or fork. Also confirm it validates the table exists before issuing DDL — a typo'd table name otherwise produces a confusing SQL error deep in a seeder.
How can I help you explore Laravel packages today?