mll-lab/laravel-graphiql
Adds a ready-to-use GraphiQL interface to Laravel applications, giving developers an in-browser IDE to explore GraphQL schemas, run queries and mutations, and inspect results. Published config and routes make it easy to point GraphiQL at your GraphQL endpoint.
mll-lab/laravel-graphiql is a thin Laravel wrapper that ships the GraphiQL IDE as a Blade view behind a single route. It is not a GraphQL server — you need an endpoint already in place (Lighthouse, rebing/graphql-laravel, or your own controller).
Minimum path to a working IDE:
composer require mll-lab/laravel-graphiql
php artisan vendor:publish --tag=graphiql-config
php artisan serve
Then open /graphiql. The published config/graphiql.php is the first file to read — it controls the route prefix and middleware, the authorization gate, and the HTTP headers the IDE sends to your endpoint. Everything you are likely to change lives there.
First real use case: iterating on a query against your own schema in a local environment — run it, inspect data/errors, use the docs pane to explore types, then paste the working query into a feature test or a PHP constant.
Upgrading to v4.1.0 is a minor bump: it adds Laravel 13 support. No breaking changes, no deprecations, no config keys removed. If you pin the package, widen the constraint (^4.1) so Composer can resolve it on a Laravel 13 app; if you are staying on Laravel 11/12, nothing changes.
Environment-scoped exposure. The default setup is a web-middleware route with no authentication. The common pattern is to register it only where it belongs:
// config/graphiql.php or a service provider guard
if (! app()->environment('local', 'staging')) {
// do not expose the IDE at all
}
Combine this with a gate rather than relying on either alone.
Gate-based authorization. The config exposes an auth gate (default viewGraphiQL). Define it in AuthServiceProvider so access is auditable and revocable in one place:
Gate::define('viewGraphiQL', fn (User $user) => $user->hasRole('developer'));
This is the extension point most teams use in shared staging environments — the route stays registered, but only staff can reach it.
Header injection instead of client-side tokens. The config's headers array is evaluated server-side when rendering the IDE and injected into the fetcher, so your endpoint receives them automatically. Use this to pass a token for a logged-in user:
'headers' => [
'Authorization' => 'Bearer ' . (auth()->user()?->api_token ?? ''),
],
This keeps developers from pasting long-lived tokens into the browser. Treat it as a secret-bearing surface — anyone who can load the page can read the header out of the DOM.
Middleware substitution. Swap web for auth or auth:api in the route config to make the whole page protected by Laravel's own middleware, which is simpler than a gate when you have a single guard. Adding throttle: here is also a cheap way to prevent the IDE becoming an accidental load test on a shared schema.
Per-environment endpoints. Keep the endpoint the IDE talks to out of hardcoded JS by pointing the config at the same path your app uses (/graphql), and vary the route prefix per environment if you have more than one schema (e.g. /graphiql-admin vs /graphiql-public). Route names are what you reference in Blade — use route('graphiql') in an internal toolbar rather than hardcoding the URL.
Workflow with Lighthouse. The IDE pairs naturally with Lighthouse's introspection: enable introspection in the local Lighthouse config, then use GraphiQL's docs pane as the schema reference while writing resolvers. Disable introspection outside local/staging — GraphiQL will render but the docs pane goes blank, which is the expected signal.
Capturing work back into the repo. Since there is no built-in query persistence, the practical pattern is: develop the query in GraphiQL, then immediately move it into a .graphql fixture or a PHP heredoc consumed by a feature test, so the IDE tab history is never the source of truth.
It is unauthenticated by default. This is the single most common mistake: publishing the config and shipping. The default middleware is web and the gate only applies if you actually configure and define it. Check /graphiql from a logged-out session before every deploy that touches config.
headers are rendered into the page. A static API token in that array is visible to anyone who can view source. Scope the gate tightly, or generate a short-lived token per request rather than referencing a long-lived one.
Config and route caches will bite you. After changing the route prefix or middleware, run php artisan config:clear and php artisan route:clear locally; in CI/deploy pipelines this happens for free, which is why "it works locally but 404s in staging" is usually a stale bootstrap/cache/config.php.
CSRF when the endpoint is behind web. If your GraphQL endpoint uses web middleware, browser POSTs from the IDE need a valid CSRF token. The usual fix is excluding the GraphQL path from VerifyCsrfToken — for API-style endpoints that is correct, but verify the route is still protected by a token guard so you have not traded CSRF for nothing.
Errors look like IDE bugs but are HTTP problems. A blank editor or "Unable to connect" is almost always the endpoint returning 401/403/419 or a 404 from a wrong path — check the browser network tab, not the PHP log. GraphQL-level errors, by contrast, render normally in the results pane.
Laravel 13 upgrade check. v4.1.0 only widens framework support. After bumping, confirm your PHP version satisfies Laravel 13's floor and re-run php artisan about plus one manual query through the IDE — the route registration and config are unchanged, so a failure is far more likely to be a framework-level upgrade issue than this package.
Extension points are deliberately shallow. There is no plugin system; customization means overriding the config, the gate, and the middleware, or replacing the route with your own controller that returns a custom view. If you need a branded, multi-endpoint console, stop configuring this package and build the view yourself — otherwise you end up with a fork you have to maintain against a four-line release history.
How can I help you explore Laravel packages today?