moharrum/laravel-adminer
moharrum/laravel-adminer integrates Adminer, the lightweight database manager, directly into Laravel. Browse tables, run SQL queries, edit records, and manage connections through a configurable route with middleware and access controls.
Install the package with Composer:
composer require moharrum/laravel-adminer
The service provider is auto-discovered on Laravel 5.5+. Publish the config so you can control where Adminer lives and who can reach it:
php artisan vendor:publish --provider="Moharrum\LaravelAdminer\AdminerServiceProvider"
This drops a config/adminer.php (or similar) into your app. Look there first — it is where the route path, middleware stack, and any Adminer-specific options are defined. Once published, visit the configured URI (typically /adminer) and log in with your normal database credentials from .env.
Your first real use case: open the route, point it at your local MySQL/Postgres/SQLite connection, and use Adminer's Select, Edit, and SQL command tabs to inspect rows, run ad-hoc queries, or export a table — without installing phpMyAdmin or connecting a desktop client. It is essentially a one-file phpMyAdmin that reuses the browser you already have open.
Before you invest further, verify compatibility. The last tagged release is from September 2020, so it targets the Laravel 5.5–8 era. On Laravel 9+ you may need to allow the install with --ignore-platform-reqs or fork/patch the composer.json constraints; test in a scratch branch first.
Environment-gated registration. The single most important pattern: only expose Adminer where it belongs. Wrap registration so the route exists in local/staging but never in production:
// AppServiceProvider::register()
if (app()->environment(['local', 'staging'])) {
$this->app->register(\Moharrum\LaravelAdminer\AdminerServiceProvider::class);
}
Combined with removing the provider from config/app.php providers (relying on package discovery), this is the safest default.
Lock the route behind Laravel auth. In config/adminer.php, set the middleware to your web guard plus an authorization gate:
'middleware' => ['web', 'auth', 'can:viewAdminer'],
Define viewAdminer in a policy or Gate::define so only admins reach it. This converts the anonymous DB login page into something tied to your app's session — a big improvement over a raw Adminer install.
IP / network restriction. In staging, add a middleware that checks request()->ip() against an allowlist, or front the whole app with a VPN. Adminer accepts arbitrary DB credentials at its login form, so anyone who can reach the URL can attempt connections to any host the server can see — not just your app's database.
Auto-fill for developer convenience (local only). Where supported by the config, preseed the server/host so the login form is one field shorter. Do not commit credentials; pull them from config('database.connections.mysql') at runtime, and only in local.
Daily workflow integration. Typical patterns that pay off:
EXPLAIN checks on slow queries before wiring up a debug bar.failed_jobs payloads while debugging async work.migrations and sessions tables when behavior doesn't match expectations.Seeding and fixture work. Adminer's multi-row edit is faster than tinker for hand-tuning seed data. Pair it with php artisan db:seed --class=... for repeatable resets and use Adminer only for ad-hoc corrections.
Alternative connections. Because Adminer is a generic DB tool, you can point it at a second server (a read replica, a teammate's staging DB, a SQLite file) without adding Laravel connections — just enter different credentials in the login form. Useful for cross-checking data between environments.
?server= parameter). The wrapper does not patch Adminer. Never expose this on a public production host, and keep the bundled Adminer version in mind when assessing risk.config/adminer.php, run php artisan config:clear (and config:cache if you cache in that env). After changing route registration, php artisan route:clear. A stale route cache is the most common "why is it 404" cause.composer dump-autoload and bootstrap/cache/packages.php), route cached before the provider was registered, or an environment check silently skipping registration.storage/logs/laravel.log and set APP_DEBUG=true locally to see the real trace.database/database.sqlite (or an absolute path) in the login form; a bare filename will create an empty DB next to public/index.php.127.0.0.1 in Docker/Laravel Sail (not localhost, which may resolve to the container itself), and the port must match your compose mapping.vendor/ or forking — which is a strong signal to consider alternatives.adminer.php in a Docker sidecar, phpmyadmin/pgadmin compose services, or desktop clients (TablePlus, DBeaver, DataGrip). For day-to-day Laravel work these usually beat a stale wrapper and remove a public attack surface from your app entirely.Route::middleware([...])->prefix('_tools/adminer') override with an unguessable prefix, register only in local, and document it in README so teammates know to run composer install before expecting the route.How can I help you explore Laravel packages today?