Skip to content

GraphQL API

Fluxbase provides an auto-generated GraphQL API that exposes your PostgreSQL tables as a fully typed GraphQL schema. The schema is automatically generated from your database tables, including relationships, filters, and mutations.

The GraphQL API provides:

  • Auto-generated types from your PostgreSQL tables
  • Query support with filtering, ordering, and pagination
  • Mutation support for insert, update, and delete operations
  • Nested queries following foreign key relationships
  • Row Level Security (RLS) enforcement on all operations
  • Introspection for schema discovery (configurable)
POST /api/v1/graphql

The GraphQL endpoint uses the same authentication as the REST API. Include a JWT token in the Authorization header:

Terminal window
curl -X POST http://localhost:8080/api/v1/graphql \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{"query": "{ users { id email } }"}'

Configure GraphQL in your fluxbase.yaml or via environment variables:

fluxbase.yaml
graphql:
enabled: true
max_depth: 10
max_complexity: 1000
introspection: true # Disable in production
SettingEnv VariableDefaultDescription
enabledFLUXBASE_GRAPHQL_ENABLEDtrueEnable/disable GraphQL endpoint
max_depthFLUXBASE_GRAPHQL_MAX_DEPTH10Maximum query nesting depth
max_complexityFLUXBASE_GRAPHQL_MAX_COMPLEXITY1000Maximum query complexity score
introspectionFLUXBASE_GRAPHQL_INTROSPECTIONtrueAllow schema introspection
query {
users {
id
email
name
created_at
}
}
query {
users(where: { email: { _eq: "john@example.com" } }) {
id
email
}
}
query {
users(
order_by: { created_at: desc }
limit: 10
offset: 0
) {
id
email
created_at
}
}
query {
users {
id
email
posts {
id
title
comments {
id
content
author {
email
}
}
}
}
}

The GraphQL API supports PostgREST-compatible filter operators:

OperatorDescriptionExample
_eqEqual{ status: { _eq: "active" } }
_neqNot equal{ status: { _neq: "deleted" } }
_gtGreater than{ age: { _gt: 18 } }
_gteGreater than or equal{ age: { _gte: 18 } }
_ltLess than{ price: { _lt: 100 } }
_lteLess than or equal{ price: { _lte: 100 } }
_likePattern match{ name: { _like: "John%" } }
_ilikeCase-insensitive match{ name: { _ilike: "john%" } }
_inIn list{ status: { _in: ["active", "pending"] } }
_is_nullIs null{ deleted_at: { _is_null: true } }
_andLogical AND{ _and: [{ age: { _gte: 18 } }, { status: { _eq: "active" } }] }
_orLogical OR{ _or: [{ role: { _eq: "admin" } }, { role: { _eq: "moderator" } }] }
mutation {
insert_users(objects: [
{ email: "new@example.com", name: "New User" }
]) {
returning {
id
email
}
}
}
mutation {
update_users(
where: { id: { _eq: "user-uuid" } }
_set: { name: "Updated Name" }
) {
affected_rows
returning {
id
name
}
}
}
mutation {
delete_users(where: { id: { _eq: "user-uuid" } }) {
affected_rows
}
}
mutation {
insert_users(
objects: [{ id: "existing-uuid", email: "user@example.com", name: "User" }]
on_conflict: {
constraint: users_pkey
update_columns: [name]
}
) {
returning {
id
name
}
}
}

PostgreSQL types are automatically mapped to GraphQL types:

PostgreSQLGraphQL
text, varchar, charString
integer, smallintInt
bigintString (to preserve precision)
booleanBoolean
numeric, real, double precisionFloat
uuidID
json, jsonbJSON (custom scalar)
timestamp, timestamptzDateTime (custom scalar)
dateDate (custom scalar)
array types[Type] (List)

When enabled, you can query the schema:

query {
__schema {
types {
name
fields {
name
type {
name
}
}
}
}
}

Or get type details:

query {
__type(name: "users") {
name
fields {
name
type {
name
kind
}
}
}
}

The Fluxbase CLI provides a graphql command for executing queries and mutations from the command line.

Terminal window
# Execute a query
fluxbase graphql query '{ users { id email } }'
# Query with variables
fluxbase graphql query 'query($id: ID!) { user(id: $id) { email } }' --var 'id=123'
# Execute from file
fluxbase graphql query --file ./query.graphql
# Execute a mutation
fluxbase graphql mutation 'mutation { insert_users(objects: [{email: "new@example.com"}]) { returning { id } } }'
# Introspect the schema
fluxbase graphql introspect
# List types only
fluxbase graphql introspect --types

See the CLI Command Reference for complete documentation.


import { createClient } from '@nimbleflux/fluxbase-sdk'
const client = createClient({ url: 'http://localhost:8080' })
// Execute a query
const { data, errors } = await client.graphql.query<UsersQuery>(`
query GetUsers($limit: Int) {
users(limit: $limit) {
id
email
}
}
`, { limit: 10 })
// Execute a mutation
const { data, errors } = await client.graphql.mutation<CreateUserMutation>(`
mutation CreateUser($data: UserInput!) {
insert_users(objects: [$data]) {
returning {
id
email
}
}
}
`, { data: { email: 'new@example.com' } })
import { useGraphQLQuery, useGraphQLMutation } from '@nimbleflux/fluxbase-sdk-react'
function UsersList() {
const { data, isLoading, error } = useGraphQLQuery<UsersQuery>(
'users-list',
`query { users { id email } }`
)
if (isLoading) return <div>Loading...</div>
if (error) return <div>Error: {error.message}</div>
return (
<ul>
{data?.users.map(user => (
<li key={user.id}>{user.email}</li>
))}
</ul>
)
}
function CreateUserForm() {
const mutation = useGraphQLMutation<CreateUserMutation>(
`mutation CreateUser($data: UserInput!) {
insert_users(objects: [$data]) {
returning { id email }
}
}`,
{
onSuccess: (data) => console.log('Created:', data),
invalidateQueries: ['users-list']
}
)
const handleSubmit = (email: string) => {
mutation.mutate({ data: { email } })
}
return (
<button onClick={() => handleSubmit('new@example.com')}>
Create User
</button>
)
}

The Query Editor in the Admin Dashboard supports both SQL and GraphQL modes:

  1. Navigate to Query Editor in the sidebar
  2. Click the GraphQL tab at the top of the editor
  3. Write your GraphQL query with auto-completion support
  4. Press Ctrl+Enter (or Cmd+Enter on Mac) to execute

The editor provides:

  • Syntax highlighting for GraphQL
  • Auto-completion for types, fields, and operations
  • Query history tracking for both SQL and GraphQL queries
  • JSON result formatting with error display

The GraphQL API enforces Row Level Security (RLS) policies exactly like the REST API:

  1. Anonymous users execute queries as the anon PostgreSQL role
  2. Authenticated users execute as the authenticated role
  3. Service role keys bypass RLS for admin operations

Session variables are available in your RLS policies:

-- Example RLS policy
CREATE POLICY "Users can view own data" ON users
FOR SELECT
USING (id = current_setting('request.jwt.claim.sub')::uuid);
graphql:
enabled: true
max_depth: 5 # Reduce depth in production
max_complexity: 500 # Lower complexity limit
introspection: false # Disable introspection in production

The max_depth setting prevents deeply nested queries that could be expensive:

# This query has depth 4 (users -> posts -> comments -> author)
query {
users { # depth 1
posts { # depth 2
comments { # depth 3
author { # depth 4
email
}
}
}
}
}

Query complexity is calculated based on the number of fields and nesting. The max_complexity setting prevents resource-intensive queries.

GraphQL errors are returned in the standard GraphQL error format:

{
"data": null,
"errors": [
{
"message": "permission denied for table users",
"locations": [{ "line": 2, "column": 3 }],
"path": ["users"]
}
]
}

Common error types:

  • Validation errors: Invalid query syntax or unknown fields
  • Authorization errors: RLS policy violations
  • Depth/complexity errors: Query exceeds configured limits
FeatureGraphQLREST
Request formatPOST with query bodyGET/POST/PUT/DELETE
Response shapeExactly what you requestFixed per endpoint
Nested dataSingle requestMultiple requests
CachingRequires client setupHTTP caching
Learning curveHigherLower

Choose GraphQL when you need:

  • Complex nested queries
  • Flexible response shapes
  • Strong typing with introspection

Choose REST when you need:

  • Simple CRUD operations
  • HTTP caching
  • Simpler integration

Ensure GraphQL is enabled in your configuration:

Terminal window
export FLUXBASE_GRAPHQL_ENABLED=true

Reduce the nesting in your query or increase max_depth:

graphql:
max_depth: 15

Check that:

  1. Your JWT token is valid and not expired
  2. RLS policies allow the operation
  3. You’re using the correct role (anon vs authenticated)

Enable introspection (note: disable in production):

graphql:
introspection: true