SDL-first, directive-driven GraphQL for Ruby on Rails.
Lighthouse lets you build a GraphQL API for your Rails app primarily through your
schema (SDL) and a set of server-side directives — @all, @find,
@paginate, @hasMany, @belongsTo, @whereConditions, @orderBy, @field,
@auth and more — instead of hand-writing a resolver for every field. It is a
Ruby adaptation of the PHP Lighthouse library,
built on top of graphql-ruby, with first-class
Apollo Federation support so a Rails service can act as a subgraph.
type Query {
users: [User!]! @all
user(id: ID! @eq): User @find
}
type User {
id: ID!
customAttributes: String # resolves to user.custom_attributes automatically
posts: [Post!]! @hasMany # batched via a Dataloader
}That's the whole resolver layer for those fields. No Ruby classes required.
Writing a resolver class for every field is repetitive. The vast majority of
GraphQL fields do one of a handful of things: list a model, find one by id,
paginate, walk a relationship, or read an attribute. Lighthouse — like its PHP
inspiration — captures those patterns as directives you attach in the schema,
and falls back to a sensible default reader for plain fields. You write Ruby only
for the genuinely custom parts (@field(resolver: "...")), and your schema stays
the single source of truth.
- Lighthouse (PHP) — the directive vocabulary, the SDL-first philosophy, and the arg-resolver / nested-mutation ideas.
- graphql-ruby — the execution engine,
Dataloader, and the connection/pagination types Lighthouse builds on. - Apollo Federation — so a Rails app can be one subgraph in a larger supergraph.
Add the gem to your Gemfile:
gem 'lighthouse-graphql'It depends on graphql ~> 2.5 and activesupport. For federation you also need
apollo-federation in your app (it is an optional, app-provided dependency).
-
Put your SDL in
app/graphqlor any folder (default:RAILS_ROOT/graphql), split across as many.graphqlfiles as you like:# graphql/users.graphql type Query { users: [User!]! @paginate user(id: ID! @eq): User @find } type User { id: ID! name: String email: String posts: [Post!]! @hasMany }
-
Build the schema (typically in
app/graphql/your_schema.rb):require 'lighthouse-graphql' AppSchema = Lighthouse::GraphQL::RbLightHouse.get_schema( sdl_folder: Rails.root.join('graphql').to_s, options: { base_types: { object: BaseObject } } # your graphql-ruby base classes )
-
Execute it from your controller exactly like any graphql-ruby schema:
AppSchema.execute(params[:query], variables: params[:variables], context: { current_user: current_user })
See docs/getting-started.md for the full setup, including base types and configuration.
| Guide | What it covers |
|---|---|
| Getting started | Install, base types, building & serving the schema |
| Directives reference | Every built-in directive, grouped by purpose |
| Relationships | @hasMany, @belongsTo, @belongsToMany, @hasOne and batching |
| Filtering & ordering | @eq/@where/@in/@like, @whereConditions, @orderBy |
| Authentication & authorization | @guard, @can (policy-based, Pundit by default) |
| Apollo Federation | @key, resolve_reference, the ReferenceResolver registry |
| Custom directives | The contracts, the registry, writing your own directive |
| Configuration | Lighthouse.configure, namespaces, error handling |
| Best practices | Conventions worth adopting |
Lighthouse parses your SDL, runs a manipulation phase (directives that need to
reshape the schema — e.g. @paginate injecting a Paginator type, @whereConditions
generating input types), builds an executable schema with
GraphQL::Schema.from_definition, then runs a resolution phase that attaches
behavior to fields (directives that resolve data, wrap resolvers, or compose query
constraints). Every directive is a small class registered with a
Lighthouse::DirectiveRegistry; adding one is "write a class and register it." A
single Support::Naming rule maps GraphQL camelCase to Rails snake_case, so
attribute reads "just work" with @rename as the explicit override.
MIT. See LICENSE.txt.