A series catalog starts with a small domain: a serie has a name, and each season belongs to a serie. Even that model needs list queries, create/update/delete operations, relationship resolvers, validation and database storage.
Simfinity.js generates those recurring pieces from GraphQL object types. Version 3.2.0 provides MongoDB/Mongoose and PostgreSQL adapters, plus an optional package for exposing GraphQL operations as MCP tools. The project is open source under Apache-2.0.
This walkthrough uses the published PostgreSQL starter. It includes a nested series/season example, so there is a relationship to inspect as well as a working API.
Start with the domain
The type definition uses the standard graphql package. A minimal entity looks like this:
import {
GraphQLID,
GraphQLNonNull,
GraphQLObjectType,
GraphQLString,
} from 'graphql';
const SerieType = new GraphQLObjectType({
name: 'Serie',
fields: {
id: { type: GraphQLID },
name: { type: new GraphQLNonNull(GraphQLString) },
},
});
Register the type with the PostgreSQL runtime, supplying the singular and plural operation names:
import pg from 'pg';
import { createPostgres } from '@simtlix/simfinity-postgres';
const pool = new pg.Pool({
connectionString: process.env.DATABASE_URL,
});
const simfinity = createPostgres({ pool, schema: 'series_api' });
simfinity.connect(null, SerieType, 'serie', 'series');
const schema = simfinity.createSchema();
await simfinity.initializeDatabase({ mode: 'create' });
The resulting schema can be served through GraphQL Yoga. The downloaded starter includes that server setup, shutdown handling, a Season type and a controller. The snippets above show the core registration flow; the starter is the complete application.
Run the released starter
Use Node.js 22+ for the starter and PostgreSQL 15+. Download and extract the v3.2.0 starter archive, then enter its postgres directory:
cd simfinity-3.2.0-starters/postgres
npm install
For a disposable local database, run:
docker run --name simfinity-postgres-demo -e POSTGRES_PASSWORD=simfinity -e POSTGRES_DB=series -p 127.0.0.1:5432:5432 -d postgres:18-alpine
In a POSIX shell, set the connection string and start the app:
export DATABASE_URL='postgresql://postgres:simfinity@127.0.0.1:5432/series'
npm start
In PowerShell, use $env:DATABASE_URL = 'postgresql://postgres:simfinity@127.0.0.1:5432/series' before npm start. If port 5432 is occupied, choose another host port and update the connection string. These credentials are for the disposable local example.
Open http://127.0.0.1:4000/graphql. Create a serie and its first season together:
mutation {
addserie(input: {
name: "The Expanse"
seasons: { added: [{ number: 1 }] }
}) {
id
name
createdBy
seasons { id number }
}
}
Then read it back:
query {
series {
name
seasons { number }
}
}
The generated relationship resolves the season from its parent. PostgreSQL also has a real foreign key from the season's serie column to the serie table. The API relationship and the database constraint come from the relationship metadata in the type definitions.
Add application rules where they belong
Generated CRUD is the starting point. Controllers and lifecycle hooks let you add domain behavior; validators, query scopes, state transitions and authorization rules provide other extension points.
Authentication remains application-owned. Configure the authorization policy and trusted request context for your deployment. The starter's fixed quickstart-user context is demonstration code, not a login system.
Storage initialization is explicit. create mode creates missing generated objects and checks existing definitions; validate mode checks the schema without DDL. Schema evolution still needs deliberate migrations.
Expose selected operations to an MCP client
The optional @simtlix/simfinity-mcp package works with either database adapter. Once the application has initialized its GraphQL schema, tool definitions can be generated from selected operations:
import { generateMCPTools } from '@simtlix/simfinity-mcp';
const { tools } = generateMCPTools(schema, {
include: ['series'],
limits: {
maxPageSize: 100,
defaultPagination: { page: 1, size: 20 },
},
});
console.log(tools.map((tool) => tool.name));
Install that package separately when needed. Tool generation needs GraphQL; server/transport factories also use the optional MCP SDK. The MCP guide covers transports, trusted context and authorization.
Choosing a backend
Choose the adapter during application startup. PostgreSQL uses UUID identities, SQL constraints and its own native Model/Session APIs. MongoDB uses Mongoose, and generated mutations require a replica set or sharded cluster. Selecting an adapter does not migrate an existing database or translate arbitrary Mongoose calls into SQL.
Start with the PostgreSQL quick start, review the compatibility boundaries, or explore the larger Series Sample Project.
The downloaded PostgreSQL starter was exercised locally with a nested create, query readback and database foreign-key inspection.
Top comments (0)