PostGraphile data provider for Refine framework with advanced filtering, real-time subscriptions, and full TypeScript support.
npm install @xuhaojun/refine-postgraphile


A Refine data provider for PostGraphile V5 that enables seamless integration with PostGraphile-generated GraphQL APIs.
- 🚀 Full CRUD Operations: Create, Read, Update, Delete, and List operations
- 🔍 Advanced Filtering: Support for PostGraphile's postgraphile-plugin-connection-filter
- 📊 Pagination: Relay-style cursor-based pagination
- 🔄 Real-time Subscriptions: Live data updates via GraphQL subscriptions
- 🎯 Type Safety: Full TypeScript support with generated type definitions
- 🛡️ Security: Built-in protection against GraphQL injection attacks
- ⚡ Performance: Optimized queries with connection filtering and sorting
``bash`
npm install @xuhaojun/refine-postgraphile @refinedev/core @refinedev/antd graphql-request gql-query-builder
Or with yarn:
`bash`
yarn add @xuhaojun/refine-postgraphile @refinedev/core @refinedev/antd graphql-request gql-query-builder
For a complete setup including UI components, routing, and development tools:
`bash`
npm install @refinedev/react-router react-router antd @ant-design/v5-patch-for-react-19 react react-dom typescript @vitejs/plugin-react vite
Or with yarn:
`bash`
yarn add @refinedev/react-router react-router antd @ant-design/v5-patch-for-react-19 react react-dom typescript @vitejs/plugin-react vite
Ensure your PostGraphile server is configured with the required plugins:
`typescript
// graphile.config.ts
import { makePgService } from "postgraphile/@dataplan/pg/adaptors/pg";
import { PostGraphileAmberPreset } from "postgraphile/presets/amber";
import { PgSimplifyInflectionPreset } from "@graphile/simplify-inflection";
import { PostGraphileConnectionFilterPreset } from "postgraphile-plugin-connection-filter";
const preset: GraphileConfig.Preset = {
extends: [PostGraphileAmberPreset, PgSimplifyInflectionPreset, PostGraphileConnectionFilterPreset],
pgServices: [
makePgService({
connectionString: process.env.DATABASE_URL || "postgres://postgres:test@localhost:5433/postgraphile_example",
schemas: ["public"],
pubsub: true,
}),
],
grafast: {
explain: true,
},
grafserv: {
websockets: true,
},
schema: {
pgJwtSecret: "example-secret-key-change-in-production",
connectionFilterAllowEmptyObjectInput: true,
connectionFilterAllowNullInput: true,
},
};
export default preset;
`
`json`
{
"dependencies": {
"postgraphile": "^5.0.0-rc.1",
"postgraphile-plugin-connection-filter": "3.0.0-rc.1",
"@graphile/simplify-inflection": "^8.0.0-rc.1",
"@graphile/pg-aggregates": "^0.2.0-rc.1"
}
}
Start PostgreSQL with Docker:
`bash`
docker run -d \
--name postgraphile-postgres \
-e POSTGRES_DB=postgraphile_example \
-e POSTGRES_USER=postgres \
-e POSTGRES_PASSWORD=test \
-p 5433:5432 \
postgres:18-alpine
Apply the schema and sample data:
`sql
-- Run this SQL in your PostgreSQL database
CREATE EXTENSION IF NOT EXISTS "uuid-ossp";
CREATE TABLE categories (
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
title TEXT NOT NULL,
created_at TIMESTAMPTZ DEFAULT NOW()
);
CREATE TABLE posts (
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
title TEXT NOT NULL,
content TEXT NOT NULL,
category_id UUID REFERENCES categories(id),
created_at TIMESTAMPTZ DEFAULT NOW()
);
-- Insert sample data...
`
Create a PostGraphile server:
`typescript
// server.ts
import { createServer } from "node:http";
import express from "express";
import cors from "cors";
import { grafserv } from "postgraphile/grafserv/express/v4";
import { pgl } from "postgraphile";
const serv = pgl.createServ(grafserv, {
// Your PostGraphile config here
});
const app = express();
app.use(cors());
const server = createServer(app);
serv.addTo(app, server).catch((e) => {
console.error(e);
process.exit(1);
});
server.listen(5000, "0.0.0.0");
console.log("🚀 PostGraphile server running on http://localhost:5000");
`
`typescript
import { Refine } from "@refinedev/core";
import { dataProvider } from "@xuhaojun/refine-postgraphile";
import { GraphQLClient } from "graphql-request";
const API_URL = "http://localhost:5000/graphql";
const client = new GraphQLClient(API_URL);
const gqlDataProvider = dataProvider(client);
function App() {
return (
resources={[
{
name: "posts",
list: "/posts",
create: "/posts/create",
edit: "/posts/edit/:id",
show: "/posts/show/:id",
},
{
name: "categories",
list: "/categories",
create: "/categories/create",
edit: "/categories/edit/:id",
},
]}
// ... other Refine props
>
{/ Your app content /}
);
}
export default App;
`
Creates a PostGraphile data provider for Refine.
`typescript`
function dataProvider(
client: GraphQLClient,
config?: PostGraphileDataProviderConfig
): PostGraphileDataProvider;
#### Parameters
- client: GraphQL client instance from graphql-requestconfig
- : Optional configuration object
#### PostGraphileDataProviderConfig
`typescript`
interface PostGraphileDataProviderConfig {
endpoint?: string; // GraphQL API endpoint URL (optional, can be set via client)
headers?: Record
namingConvention?: "simplified" | "default"; // Field naming convention (default: "simplified")
filterOptions?: FilterOptions; // Connection filter options
schemaIntrospection?: boolean; // Enable schema introspection
timeout?: number; // Request timeout in milliseconds
retry?: {
attempts?: number; // Maximum retry attempts
delay?: number; // Delay between retries
};
}
Creates a live provider for real-time subscriptions.
`typescript`
function liveProvider(
client: GraphQLClient,
config?: PostGraphileLiveProviderConfig
): LiveProvider;
#### Parameters
- client: GraphQL client instanceconfig
- : Optional live provider configuration
#### PostGraphileLiveProviderConfig
`typescript`
interface PostGraphileLiveProviderConfig {
wsUrl?: string; // WebSocket URL for subscriptions
headers?: Record
connectionTimeout?: number; // Connection timeout
reconnection?: {
enabled?: boolean; // Enable auto-reconnection
initialDelay?: number; // Initial reconnection delay
maxDelay?: number; // Maximum reconnection delay
backoffMultiplier?: number; // Delay multiplier
};
debug?: boolean; // Enable debug logging
}
- getList - Fetch a list of records with filtering, sorting, and paginationgetOne
- - Fetch a single record by IDcreate
- - Create a new recordcreateMany
- - Create multiple recordsupdate
- - Update a record by IDupdateMany
- - Update multiple recordsdeleteOne
- - Delete a record by IDdeleteMany
- - Delete multiple records
The provider supports PostGraphile connection filter operators:
`typescript`
const { data } = useList({
resource: "posts",
filters: [
{ field: "title", operator: "contains", value: "AI" },
{ field: "createdAt", operator: "gte", value: "2023-01-01" },
{ field: "category.title", operator: "eq", value: "Technology" },
],
});
#### Supported Filter Operators
- eq - Equal toneq
- - Not equal togt
- - Greater thangte
- - Greater than or equallt
- - Less thanlte
- - Less than or equalin
- - In arraynotIn
- - Not in arraycontains
- - Contains substring (case-sensitive)notContains
- - Does not contain substringstartsWith
- - Starts withnotStartsWith
- - Does not start withendsWith
- - Ends withnotEndsWith
- - Does not end withisNull
- - Is nullisNotNull
- - Is not null
`typescript`
const { data } = useList({
resource: "users",
sorters: [
{ field: "createdAt", order: "desc" },
{ field: "name", order: "asc" },
],
});
Uses Relay-style cursor-based pagination:
`typescript`
const { data, hasNextPage, hasPreviousPage } = useList({
resource: "users",
pagination: { current: 1, pageSize: 10 },
});
Enable real-time data updates with GraphQL subscriptions:
`typescript`
// In your resource configuration
wsUrl: "wss://your-api.com/graphql"
})}
liveMode="auto" // Automatically refresh data on changes
// ... other props
>
The package exports comprehensive TypeScript types:
`typescript`
import type {
PostGraphileDataProvider,
PostGraphileDataProviderConfig,
PostGraphileLiveProviderConfig,
Connection,
Edge,
PageInfo,
FilterInput,
SortingInput,
PaginationInput,
} from "@xuhaojun/refine-postgraphile";
The provider includes multiple security measures:
- Field Name Validation: Prevents injection through malicious field names
- Operator Validation: Restricts allowed filter operators
- Query Length Limits: Prevents extremely large queries
- GraphQL Identifier Validation: Ensures valid operation names
- URL Validation: Validates endpoint URLs
- Input Sanitization: Cleans and validates all user inputs
The provider includes comprehensive error handling with user-friendly messages:
`typescript
import { PostGraphileError, ErrorCodes } from "@xuhaojun/refine-postgraphile";
try {
// Your data operations
} catch (error) {
if (error instanceof PostGraphileError) {
console.log("Error code:", error.code);
console.log("User message:", getUserFriendlyErrorMessage(error));
}
}
`
A complete working example is available in the examples/data-provider-postgraphile/ directory. This example demonstrates:
- Full CRUD operations for posts and categories
- Advanced filtering with PostGraphile connection filters
- Relay-style pagination
- TypeScript integration with GraphQL codegen
- Docker-based PostgreSQL setup
`bash1. Start PostgreSQL database
cd examples/data-provider-postgraphile
docker-compose up -d
The example will be available at:
- Frontend: http://localhost:5173
- GraphQL API: http://localhost:5000/graphql
- GraphiQL Interface: http://localhost:5000
$3
- Blog Management: CRUD operations for blog posts and categories
- Advanced Filtering: Search posts by title, category, date, etc.
- Pagination: Relay-style cursor-based pagination
- Type Safety: Full TypeScript support with generated types
- Real-time Ready: WebSocket support configured for subscriptions
Migration from Hasura
If you're migrating from
@refinedev/hasura, the API is similar but with PostGraphile-specific differences:`typescript
// Hasura (old)
import dataProvider from "@refinedev/hasura";// PostGraphile (new)
import { dataProvider } from "@xuhaojun/refine-postgraphile";
``Key differences:
- Uses Relay connections instead of direct list queries
- Different mutation patterns (input/payload vs direct field updates)
- Connection-based filtering syntax
- Simplified inflection naming conventions
We welcome contributions! Please see our Contributing Guide for details.
MIT License - see LICENSE for details.
- 📖 Documentation
- 🐛 Bug Reports
- 💬 Community Discussions
- 💡 Feature Requests
Check out our example implementations to see the provider in action.