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

Adminer Laravel Package

vrana/adminer

Adminer for Laravel embeds the single-file Adminer database manager as a drop-in phpMyAdmin replacement. Publish the config, open the route, and browse, query and edit MySQL, PostgreSQL, SQLite and other databases inside your app, with auth and middleware support.

Deep Wiki
Context7

Getting Started

vrana/adminer is not a Laravel package — it is the upstream Adminer distribution shipped as a Composer dependency. There is no service provider, no config file, no auto-discovery. Installing it gets you a large adminer.php inside vendor/, and nothing else. The whole job is getting that file reachable from your app.

composer require vrana/adminer --dev

Then the quickest possible win: symlink or copy the entry file into public/ and open it.

ln -s ../vendor/vrana/adminer/adminer.php public/adminer.php
php artisan serve
# http://localhost:8000/adminer.php

Log in with the same credentials as your .env (DB_HOST, DB_DATABASE, DB_USERNAME, DB_PASSWORD), pick the driver (MySQL/PostgreSQL/SQLite), and you have schema browsing and ad-hoc SQL for the current project without installing a desktop client.

Where to look first inside vendor/vrana/adminer/:

  • adminer.php — the entry point; read the top ~100 lines to see how it bootstraps and where adminer_object() is resolved.
  • plugins/ — one file per plugin, each a working example of the extension API. This is the best documentation the project has.
  • designs/ — CSS-only themes.
  • lang/ — translations, loaded by locale.

First real use case: inspect a migration you just wrote, or run a EXPLAIN on a slow query, without leaving the repo. Do not try to replace artisan migrate, seeders, or tinker with it.

Implementation Patterns

Route-based mounting (preferred over a public file). A raw file in public/ bypasses all Laravel middleware, so you can't gate it by environment. Mount it through the router instead:

// routes/web.php
if (app()->environment('local')) {
    Route::get('/adminer', function () {
        require base_path('vendor/vrana/adminer/adminer.php');
    })->withoutMiddleware([
        \App\Http\Middleware\EncryptCookies::class,
        \Illuminate\Foundation\Http\Middleware\ValidateCsrfToken::class,
    ]);
}

Adminer emits its own headers and calls exit on several paths, so treat the route as a thin passthrough, not a controller you can post-process.

Use a wrapper for team installs. onecentlin/laravel-adminer wraps vrana/adminer, publishes config, registers the route, and applies auth middleware. If more than one developer needs this, the wrapper is less friction than hand-rolling the route. You still end up depending on vrana/adminer underneath.

Prefill credentials. Adminer reads $_GET/$_POST for server, username, db, driver. Seed those from Laravel's config before the require so devs never retype:

$_GET += [
    'server'   => config('database.connections.mysql.host'),
    'username' => config('database.connections.mysql.username'),
    'db'       => config('database.connections.mysql.database'),
    'driver'   => 'server',
];
require base_path('vendor/vrana/adminer/adminer.php');

Recent 5.x releases also honor ADMINER_DEFAULT_SERVER / ADMINER_DEFAULT_DRIVER / ADMINER_DEFAULT_DB environment variables, but pre-seeding $_GET is the version-independent path.

Plugins via adminer_object(). Define the function in a dedicated file and load it before adminer.php:

function adminer_object(): \Adminer\Plugins {
    return new \Adminer\Plugins([
        new \Adminer\PluginLoginPasswordLess,
        new class extends \Adminer\Plugin {
            public function headers(): void { /* ... */ }
        },
    ]);
}

Read-only guard for shared/staging environments. A small \Adminer\Plugin subclass that refuses POST when the query is destructive, or that overrides dumpFormat(), is far cheaper than trusting everyone to be careful. The readonly plugin in plugins/ is a starting point.

Auto-login bridge. Subclass \Adminer\Adminer (or a plugin hooking login()) to permanently log in using Laravel's DB config, then gate the route behind auth middleware. Good for internal tools; never for anything internet-facing.

Gotchas and Tips

  • Composer install alone does nothing. No provider, no route, no publish. If /adminer 404s, you skipped the mounting step.
  • Namespace changed in Adminer 5. It moved from global Adminer / AdminerPlugin to Adminer\Adminer / Adminer\Plugins. Most blog posts and plugin snippets you'll find are 4.x and will fatal. Check the installed version before copying code.
  • CSRF will reject every POST. ValidateCsrfToken blocks Adminer's form submissions. Either exclude the route (->withoutMiddleware(...)) or mount it in a middleware group without CSRF. Symptom: "Page expired" on login.
  • Session collisions. Adminer uses PHP's native session. If it shares a cookie name/path with your Laravel session you'll get random logouts on both sides. Call session_name('adminer') before the require, or isolate the route on a subdomain.
  • exit/die bypasses the framework. Laravel's termination callbacks, Telescope, Debugbar, and exception handler never see Adminer's output or errors. Debug Adminer with PHP's own error log, not storage/logs/laravel.log.
  • Never ship it to production. The file-upload, SQL-execution, and LOAD DATA surface is enormous. Keep it in require-dev, rely on composer install --no-dev in deploys, and additionally gate the route by app()->environment('local') and auth. Belt and braces. If you must expose it remotely, put it behind an IP allowlist plus basic auth plus throttle.
  • SQLite is the fastest local win. Point Adminer at database/database.sqlite; no server config needed and it doubles as a quick sanity check that your migrations produced the schema you expected.
  • Dumps will OOM on real data. Adminer's export runs in PHP and loads rows into memory. For anything production-sized, use mysqldump/pg_dump; use Adminer's export only for small tables and schema-only dumps.
  • Pin the version. adminer.php is a committed build artifact and upstream restructures it between majors (see the namespace change). Constrain with "vrana/adminer": "^5.0" in require-dev so a composer update doesn't silently break your adminer_object() or plugin classes.
  • adminer_object() must be global. Defining it inside a namespaced file or a class method means Adminer won't find it and plugins silently don't load. Put it in a plain app/Support/adminer.php with no namespace, and require it first.
  • Themes are CSS-only. Drop a stylesheet at adminer.css next to the entry point or reference one from designs/; there is no config setting for it.
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.
skyraptor/chatter
edlugz/sasapay
abbasudo/artisan-route
mirvan/ippanel
ignibyte/aic-framework
glavweb/data-schema-bundle
glavweb/datagrid-bundle
tacticmedia/scim-server
uni-method/frame
neika-ai/sdk
adachsoft/php-code-style
pharaonic/laravel-notification-dependencies
beautinow/translug
dev-brainiac/bot-cloaked
octoberrain/html
octoberrain/extension
octoberrain/exception
octoberrain/contracts
adachsoft/api-version-bundle
cgv/localized-resource