Documentation Index
Fetch the complete documentation index at: https://mintlify.com/rjdellecese/confect/llms.txt
Use this file to discover all available pages before exploring further.
Components in Confect allow you to create modular, reusable backend functionality that can be shared across projects or within your application.
Components are an advanced feature that builds on Convex’s component system. This page provides an overview of how components work with Confect.
What are Components?
Components are self-contained modules that encapsulate:
Database Tables
Component-specific schemas and tables
Functions
Queries, mutations, and actions
Dependencies
Other components and packages
Configuration
Component-specific settings
Creating a Component
Define a component as a separate package:
import { DatabaseSchema, Table } from "@confect/server";
import { Schema } from "effect";
const commentsTable = Table.make(
"comments",
Schema.Struct({
text: Schema.String,
authorId: Schema.String,
parentId: Schema.String,
createdAt: Schema.Number,
})
)
.index("by_parent", ["parentId", "createdAt"]);
export const componentSchema = DatabaseSchema.make()
.addTable(commentsTable);
import { Api } from "@confect/core";
import { componentSchema } from "./schema";
export const api = Api.make({
name: "comments",
runtime: "Convex" as const,
databaseSchema: componentSchema,
groups: {
comments: {
list: FunctionSpec.query({
args: Schema.Struct({ parentId: Schema.String }),
returns: Schema.Array(
Schema.Struct({
id: Schema.String,
text: Schema.String,
authorId: Schema.String,
createdAt: Schema.Number,
})
),
}),
add: FunctionSpec.mutation({
args: Schema.Struct({
parentId: Schema.String,
text: Schema.String,
}),
returns: Schema.Struct({ id: Schema.String }),
}),
},
},
});
Using Components
Import and use components in your application:
import { CommentsComponent } from "@company/comments-component";
import { Effect } from "effect";
const getPostWithComments = (postId: string) =>
Effect.gen(function* () {
const db = yield* DatabaseReader<typeof databaseSchema>();
const comments = yield* CommentsComponent.queries.list({ parentId: postId });
const post = yield* db.table("posts").get(postId);
return {
post,
comments,
};
});
Component Isolation
Components maintain isolation:
Separate Namespaces
Component tables don’t conflict with app tables
Type Safety
Full type safety across component boundaries
Independent Deploys
Components can be versioned and deployed separately
Encapsulation
Internal component details are hidden
Component Communication
Components communicate through defined interfaces:
// In component
export const api = Api.make({
name: "notifications",
groups: {
notifications: {
send: FunctionSpec.mutation({
args: Schema.Struct({
userId: Schema.String,
message: Schema.String,
}),
returns: Schema.Struct({ sent: Schema.Boolean }),
}),
},
},
});
// In app
const notifyUser = (userId: string, message: string) =>
Effect.gen(function* () {
const result = yield* NotificationsComponent.mutations.send({
userId,
message,
});
return result;
});
Publishing Components
Components can be published as npm packages:
{
"name": "@company/comments-component",
"version": "1.0.0",
"main": "dist/index.js",
"types": "dist/index.d.ts",
"dependencies": {
"@confect/server": "^1.0.0",
"effect": "^3.0.0"
}
}
Example Components
Common component patterns:
Authentication Component
export const authComponent = Component.make({
name: "auth",
functions: {
login: mutation({
args: { email: Schema.String, password: Schema.String },
returns: { token: Schema.String },
}),
logout: mutation({
args: {},
returns: { success: Schema.Boolean },
}),
getCurrentUser: query({
args: {},
returns: Schema.optional(User),
}),
},
});
Analytics Component
export const analyticsComponent = Component.make({
name: "analytics",
functions: {
track: mutation({
args: {
event: Schema.String,
properties: Schema.Record(Schema.String, Schema.Any),
},
returns: { tracked: Schema.Boolean },
}),
getStats: query({
args: { period: Schema.String },
returns: Stats,
}),
},
});
File Storage Component
export const storageComponent = Component.make({
name: "storage",
functions: {
upload: mutation({
args: { filename: Schema.String },
returns: { uploadUrl: Schema.String },
}),
download: query({
args: { fileId: Schema.String },
returns: { url: Schema.String },
}),
},
});
Best Practices
Define Clear Interfaces
Make component APIs explicit and well-documented.
Version Components
Use semantic versioning for component packages.
Minimize Dependencies
Keep components loosely coupled and self-contained.
Test Thoroughly
Write comprehensive tests for component functionality.
Components are a powerful way to share functionality, but they add complexity. Use them when you need reusable, isolated modules.
Component Configuration
Components can accept configuration:
export const createEmailComponent = (config: {
apiKey: string;
fromAddress: string;
}) =>
Component.make({
name: "email",
config,
functions: {
send: mutation({
args: {
to: Schema.String,
subject: Schema.String,
body: Schema.String,
},
handler: ({ to, subject, body }) =>
Effect.gen(function* () {
// Use config.apiKey and config.fromAddress
yield* sendEmail(config, to, subject, body);
return { sent: true };
}),
}),
},
});
Limitations
- Components cannot directly access other components’ tables
- Component communication happens through functions only
- Components must be statically defined (no dynamic component loading)
Components are currently an experimental feature. The API may change in future versions.
Next Steps
Functions
Define component functions
Database
Create component schemas
Project Structure
Organize your components
Convex Components
Learn more about Convex components