- Graphoria
- Contents
⚠️ Pre-1.0 Stability- Features
- Why Graphoria?
- Who is this for?
- How it works
- Coming Before v1.0
- Prerequisites
- Installation
- Try it now
- Quick Start
- API Endpoints
- Supported Databases
- Environment Variables
- Troubleshooting
- Production Checklist
- Packages
- Documentation
- Contributing
- License
- Author & Maintainer
- Acknowledgments
Instant GraphQL & REST APIs from your database — with built-in auth, message queues, cron jobs, and real-time subscriptions.
Graphoria connects to your database, introspects the schema, and generates a complete GraphQL and REST API layer — including CRUD operations, relationships, filtering, and ordering. On top of that, it integrates RabbitMQ and Kafka for event-driven workflows, supports scheduled background tasks with cron, and provides custom operations with type-safe handlers.
Built with Bun and TypeScript for maximum performance.
v0.1.0 — All features are working. Breaking changes are expected before v1.0. See below for details.
Graphoria is under active development. Until v1.0:
- Breaking changes are expected — the configuration shape, API surface, and package structure may change between minor versions.
- Every breaking change is documented in
CHANGELOG.mdwith migration guidance. - Semantic versioning applies from v1.0 onward. Before then, treat each
0.xbump as potentially breaking.
We ship fast and fix forward. If you're evaluating Graphoria for production, pin your version (0.1.0 not ^0.1.0) and read the changelog before upgrading.
- Auto-generated GraphQL API from database schema with zero configuration
- Auto-generated REST API from GraphQL schema for maximum compatibility
- Multi-database support — PostgreSQL, SQL Server (MSSQL), MySQL
- JWT or PASETO authentication with argon2id password hashing and role-based access control (RBAC)
- Row-level security — per-role filters with session variable injection
- Real-time subscriptions via WebSocket (
graphql-wsprotocol) - Message queues — RabbitMQ and Kafka with pub/sub and cache invalidation
- Cron jobs — scheduled background tasks with optional GraphQL query execution
- Custom operations — type-safe query and handler-based endpoints with Zod validation
- Remote GraphQL schemas — stitch external GraphQL APIs into the unified schema
- Remote REST APIs — proxy external OpenAPI services under
/rest - Virtual columns — computed columns powered by SQL expressions or functions
- GraphQL directives —
@where,@truncate,@replace,@concat, and more for data transformation - AI agent — admin-only natural-language → database Q&A, exposed as GraphQL
askquery and REST endpoint - MCP server — Model Context Protocol server so AI editors can explore your schema as tools
- Admin console — web UI at
/_consolefor tables, roles, permissions, API docs, and runtime status - LRU cache with queue-driven invalidation
- Built-in playgrounds — GraphiQL and Scalar API documentation
- OpenAPI spec generation from operations
- React SDK —
@graphoria/reactwith auth hooks, Apollo Client, and route-based access control - Structured logging — pino-based JSON logging with configurable levels
Graphoria gives you a Hasura-grade GraphQL API — plus queues, cron, an AI agent, an MCP server, and an admin console — in a single Bun binary. No stitching together five services. No YAML-driven middleware. Write a TypeScript config file and you're done.
| You want… | Hasura CE | PostGraphile | Graphoria |
|---|---|---|---|
| Auto-generated GraphQL + REST | ✅ | ✅ | ✅ |
| PostgreSQL, MySQL, MSSQL | ✅ | ✅ (PG) | ✅ |
| JWT + PASETO auth with RBAC | ✅ | — | ✅ |
| Built-in message queues (RabbitMQ/Kafka) | — | — | ✅ |
| Built-in cron jobs | ✅ | — | ✅ |
| Admin console UI | ✅ | — | ✅ |
| AI agent (NL → DB queries) | — | — | ✅ |
| MCP server (AI editor integration) | — | — | ✅ |
| Remote schema stitching + REST proxy | ✅ | — | ✅ |
| Virtual columns + directives | — | ✅ (PG) | ✅ |
| Runtime | Haskell | Node.js | Bun |
Graphoria is for backend developers and small-to-medium teams who want:
- A Hasura-grade GraphQL API without the operational overhead of Haskell or the limitations of the Community Edition.
- One binary that handles the API layer, authentication, async workloads (queues + cron), and AI integration — no stitching together five services.
- TypeScript-native configuration — no YAML, no DSL, just a
graphoria.tsfile with full autocomplete. - AI-ready schemas — the built-in MCP server exposes your database as tools to AI editors with zero extra setup.
flowchart TB
subgraph Clients[" "]
GQL["GraphQL<br/>(queries, mutations, subscriptions)"]
REST["REST<br/>(operations, remote proxies)"]
AI["AI / MCP<br/>(agent tools, editor)"]
CONSOLE["Admin Console<br/>(/_console)"]
end
subgraph Graphoria["Graphoria"]
AUTH["Auth<br/>(JWT, PASETO, RBAC)"]
CACHE["Query Cache<br/>(LRU per-role)"]
QUEUES["Queues<br/>(RabbitMQ, Kafka)"]
CRON["Cron<br/>(scheduled jobs)"]
AGENT["AI Agent<br/>(LLM tools)"]
MCP["MCP Server<br/>(schema tools)"]
REMOTE["Remote<br/>(GQL stitch, REST proxy)"]
end
subgraph Data[" "]
PG[("PostgreSQL")]
MSSQL[("SQL Server")]
MYSQL[("MySQL")]
REDIS[("Redis")]
end
Clients --> Graphoria
Graphoria --> Data
What's actively being built or on the near-term roadmap:
| Milestone | Status |
|---|---|
| Website & documentation hub | Planned |
| Configuration stabilization — single source of truth via Zod, final shape lock-in | In progress |
graphoria init CLI — scaffold a project with one command |
Planned |
| Official Docker images — multi-arch, published to GHCR | Planned |
| SQLite support — embedded database for edge and local dev | Planned |
| Rate limiting & throttling — per-role, per-operation | Planned |
| Metrics & tracing — OpenTelemetry integration | Planned |
Want to influence the roadmap? Open an issue or upvote existing ones.
- Bun 1.3.4 or newer
- A running database — PostgreSQL, MySQL, or SQL Server. The examples use PostgreSQL on
localhost:5432. - Redis (or Valkey) — only required if you enable authentication. The default URL is
redis://localhost:6379.
Don't have Postgres/Redis handy? The examples/ folder ships a docker-compose.yml that starts Postgres, Redis, and RabbitMQ with credentials matching the examples below:
docker compose -f examples/docker-compose.yml up -dbun add @graphoria/serverThe examples/taskly/ folder is a complete, ready-to-run demo — a multi-tenant task tracker with auth, RBAC, queues, cron, subscriptions, operations, and a React frontend. Clone the repo, docker compose up, bun run index.ts, and you're live in minutes. Every feature in this README is wired up and documented there.
Secrets are read from the environment, not passed as options. Bun auto-loads a .env file. ADMIN_SECRET is always required (the server will not boot without it), and JWT_SECRET is required for the default JWT auth strategy:
# .env
ADMIN_SECRET=dev-admin-change-me
JWT_SECRET=dev-secret-change-meSee .env.example for every supported variable.
import { createBunServer } from "@graphoria/server";
// ADMIN_SECRET and JWT_SECRET are read from the environment (e.g. a .env file).
const { server, prefixes } = await createBunServer({
port: 3000,
configuration: "./graphoria.ts",
});
console.log(`Server running on http://localhost:${server.port}`);
console.log(`GraphQL: ${prefixes.graphql}`);
console.log(`REST: ${prefixes.rest}`);
console.log(`GraphiQL: ${prefixes.graphiql}`);Graphoria uses pino for structured JSON logging. Set LOG_LEVEL to control verbosity (debug in dev, info in prod by default). In development, pino-pretty formats output for readability.
LOG_LEVEL=trace bun run devTo inject your own pino logger or customize options:
import pino from "pino";
import { createBunServer, configureLogging } from "@graphoria/server";
// Option A: pass via createBunServer
const { server } = await createBunServer({
logger: pino({ level: "trace", redact: ["req.headers.authorization"] }),
});
// Option B: pass pino options (you own full config)
const { server } = await createBunServer({
logger: {
level: "trace",
transport: { target: "pino/file", options: { destination: "/var/log/app.log" } },
},
});
// Option C: call configureLogging before anything else (first-write-wins)
configureLogging({ level: "trace" });import { createHandlers } from "@graphoria/server";
const { serverHandlers } = await createHandlers({
configuration: "./graphoria.ts",
});
const server = Bun.serve({
port: 3000,
routes: {
"/health": () => new Response("OK"),
...serverHandlers.routes,
},
websocket: serverHandlers.websocket,
});Create a graphoria.ts configuration file:
import type { ConfigurationFn } from "@graphoria/server/config";
export default (({ operation }) => ({
name: "my-api",
version: "1.0.0", // your API's version — not Graphoria's
databases: [
{
name: "pg",
type: "pg",
enabled: true,
connection: {
host: "localhost",
port: 5432,
user: "postgres",
password: "postgres",
database: "my_app",
},
},
],
auth: {
enabled: true,
database: "pg",
permissions: {
anonymous: { tables: "ALL", operations: "ALL" },
admin: {
tables: "ALL",
storedProcedures: "ALL",
queues: "ALL",
operations: "ALL",
},
},
},
operations: {
getProducts: operation({
query: `query { public_products { id name price } }`,
description: "Get all products",
rest: { path: "/products", method: "GET" },
}),
},
})) satisfies ConfigurationFn;Start the server:
bun run index.tsOpen http://localhost:3000/graphiql in your browser. The playground lists every table from your database, with relationships, filters, ordering, and pagination wired up automatically. Try a query:
query {
public_products(limit: 10, where: { id: { eq: 1 } }) {
id
name
}
}Or hit the REST endpoint declared by the operation above:
curl 'http://localhost:3000/rest/products'Generated GraphQL fields follow the {schema}_{name} pattern by default — e.g. the products table in the public schema becomes public_products. Override it per database with the fieldNaming config field, using the {database}, {schema}, {name}, and {type} placeholders (e.g. "{database}_{schema}_{name}" to disambiguate tables across multiple databases).
| Verb | Path | Description |
|---|---|---|
| GET/POST | /graphql |
GraphQL HTTP. WebSocket upgrade on GET (graphql-ws protocol). |
| GET/POST | /rest/* |
REST API (operations + remote-REST proxies). |
| GET | /graphiql |
Bundled GraphiQL playground. |
| GET | /scalar |
Bundled Scalar API docs. |
| GET | /openapi.json |
Unified OpenAPI spec (operations + remote-REST). |
| POST | /mcp |
Model Context Protocol server (anonymous, opt-in). |
| POST | /ai |
AI agent — NL → database Q&A (admin-secret only, opt-in). |
| GET | /_console |
Admin console UI + status APIs (admin-secret gated, opt-in). |
All paths are configurable via environment variables. Auth: Authorization: Bearer <token>. Admin: x-admin-secret header.
| Database | Status | Features |
|---|---|---|
| PostgreSQL | Full support | Tables, views, relationships, stored procs |
| SQL Server (MSSQL) | Full support | Tables, views, relationships, stored procs |
| MySQL | Full support | Tables, views, relationships |
The variables you'll most likely touch for a first run. See .env.example for the full list.
| Variable | Default | Description |
|---|---|---|
ADMIN_SECRET |
(required) | Master secret; sent in the admin header it bypasses RBAC. No default — the server won't boot without it. |
JWT_SECRET |
(required for JWT) | HMAC secret for signing tokens under the default jwt strategy. |
PORT |
3000 |
HTTP port the server listens on. |
CACHE_STORE |
memory |
memory or redis. Use redis (and REDIS_URL) when auth is enabled. |
REDIS_URL |
redis://localhost:6379 |
Redis/Valkey URL — required when authentication is enabled. |
AUTH_STRATEGY |
jwt |
jwt, paseto_local, or paseto_public. |
- Server exits immediately on boot —
ADMIN_SECRETis unset. Add it to your.env. - Auth requests fail / token errors — Redis isn't reachable. Start it (
docker compose -f examples/docker-compose.yml up -d redis) and checkREDIS_URL. Cannot connect to database— confirm the database is running and theconnectionblock ingraphoria.tsmatches its host/port/credentials.
Before going to production:
- Set a strong
ADMIN_SECRET— it bypasses all RBAC. - Rotate
JWT_SECRET(orPASETO_SECRET) — never use the dev default. - Put Redis behind authentication — set a password and use
redis://user:pass@host:portinREDIS_URL. - Enable CORS properly — set
CORS_ORIGINto your frontend's origin, not*. - Use a reverse proxy (nginx, Caddy) for TLS termination.
- Pin your Graphoria version —
0.1.0, not^0.1.0— until v1.0.
| Package | Description |
|---|---|
@graphoria/server |
Main server — API generation, auth, queues, cron |
@graphoria/react |
React hooks for auth, Apollo Client, and route-based access control |
Getting started
| Guide | Description |
|---|---|
| Quickstart | Zero to a running server in five minutes |
| Configuration Reference | Full configuration schema — databases, auth, operations, queues, cron |
| API Reference | Complete package exports for server, config, and react |
Features
| Guide | Description |
|---|---|
| Authentication | JWT and PASETO strategies, argon2id passwords, refresh-token rotation |
| Permissions & Access Control | RBAC, row-level filtering, session variables, ordering |
| Operations | Custom query and handler operations, hooks, caching |
| Cron Jobs | Scheduled background work with cron expressions and ISO datetimes |
| Queues | RabbitMQ and Kafka publishers, subscribers, cache invalidation |
| Subscriptions | GraphQL subscriptions over WebSockets |
| GraphQL Directives | Built-in data-transformation and @when control-flow directives |
| Virtual Columns | Computed columns powered by SQL expressions or functions |
| Remote GraphQL Schemas | Stitch external GraphQL APIs into the unified schema |
| Remote REST APIs | Proxy external OpenAPI services under /rest |
| AI Agent | Admin-only natural-language → database Q&A over GraphQL and REST |
| MCP Server | Model Context Protocol server — schema as tools for AI editors |
| Admin Console | Web UI for tables, roles, permissions, API docs, and runtime status |
| React SDK | @graphoria/react hooks, providers, and Apollo integration |
We welcome contributions! Please follow these steps:
git clone https://github.com/graphoria/graphoria.git
cd graphoriabun installcp .env.example .env
bun run dev- Create a feature branch:
git checkout -b feature/amazing-feature - Write tests for new functionality
- Ensure all tests pass:
bun test - Follow the existing code style
- Add documentation for new features
- Commit your changes:
git commit -m 'Add amazing feature' - Push to your branch:
git push origin feature/amazing-feature - Open a Pull Request with a clear description
This project is licensed under the Apache License 2.0 — see the LICENSE and NOTICE files for details.
Copyright 2026 Alex Ferreli
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
Alex Ferreli — Creator & Lead Developer
- GitHub: @Alex-Ferreli
- Email: ferreli.ale@gmail.com
- Repository: graphoria
- Inspired by: Hasura — For pioneering instant GraphQL APIs
- Powered by: Bun — For incredible runtime performance
- Built with: GraphQL — For modern API architecture
- TypeScript — For developer experience and type safety
Star this repo if you find it useful!
Made with care by developers, for developers