Content Creation
#ai
convex-component-authoring
How to create, structure, and publish self-contained Convex components with proper isolation, exports, and dependency management
DeepseekModel
Curated skill
Quality Excellent · 78
v1.0.0
Get
https://deepseekmodel.com/api/download.php?id=waynesutton-convexskills-skills-convex-component-authoring-skill-md&format=skill
Download .skill
Standard format with system_prompt and model_config, ready for any agent framework
The actual content of the system_prompt field in the .skill file.
name convex-component-authoring displayName Convex Component Authoring description How to create, structure, and publish self-contained Convex components with proper isolation, exports, and dependency management version 1.0.0 author Convex tags ["convex","components","reusable","packages","npm"] Convex Component Authoring Create self-contained, reusable Convex components with proper isolation, exports, and dependency management for sharing across projects. Documentation Sources Before implementing, do not assume; fetch the latest documentation: Primary: https://docs.convex.dev/components Component Authoring: https://docs.convex.dev/components/authoring For broader context: https://docs.convex.dev/llms.txt Instructions What Are Convex Components? Convex components are self-contained packages that include: Database tables (isolated from the main app) Functions (queries, mutations, actions) TypeScript types and validators Optional frontend hooks Component Structure my-convex-component/ ├── package.json ├── tsconfig.json ├── README.md ├── src/ │ ├── index.ts # Main exports │ ├── component.ts # Component definition │ ├── schema.ts # Component schema │ └── functions/ │ ├── queries.ts │ ├── mutations.ts │ └── actions.ts └── convex.config.ts # Component configuration Creating a Component 1. Component Configuration // convex.config.ts import { defineComponent } from "convex/server" ; export default defineComponent ( "myComponent" ); 2. Component Schema // src/schema.ts import { defineSchema, defineTable } from "convex/server" ; import { v } from "convex/values" ; export default defineSchema ({ // Tables are isolated to this component items : defineTable ({ name : v. string (), data : v. any (), createdAt : v. number (), }). index ( "by_name" , [ "name" ]), config : defineTable ({ key : v. string (), value : v. any (), }). index ( "by_key" , [ "key" ]), }); 3. Component Definition // src/component.ts import { defineComponent, ComponentDefinition } from "convex/server" ; import schema from "./schema" ; import * as queries from "./functions/queries" ; import * as mutations from "./functions/mutations" ; const component = defineComponent ( "myComponent" , { schema, functions : { ...queries, ...mutations, }, }); export default component; 4. Component Functions // src/functions/queries.ts import { query } from "../_generated/server" ; import { v } from "convex/values" ; export const list = query ({ args : { limit : v. optional (v. number ()), }, returns : v. array (v. object ({ _id : v. id ( "items" ), name : v. string (), data : v. any (), createdAt : v. number (), })), handler : async (ctx, args) => { return await ctx. db . query ( "items" ) . order ( "desc" ) . take (args. limit ?? 10 ); }, }); export const get = query ({ args : { name : v. string () }, returns : v. union (v. object ({ _id : v. id ( "items" ), name : v. string (), data : v. any (), }), v. null ()), handler : async (ctx, args) => { return await ctx. db . query ( "items" ) . withIndex ( "by_name" , ( q ) => q. eq ( "name" , args. name )) . unique (); }, }); // src/functions/mutations.ts import { mutation } from "../_generated/server" ; import { v } from "convex/values" ; export const create = mutation ({ args : { name : v. string (), data : v. any (), }, returns : v. id ( "items" ), handler : async (ctx, args) => { return await ctx. db . insert ( "items" , { name : args. name , data : args. data , createdAt : Date . now (), }); }, }); export const update = mutation ({ args : { id : v. id ( "items" ), data : v. any (), }, returns : v. null (), handler : async (ctx, args) => { await ctx. db . patch (args. id , { data : args. data }); return null ; }, }); export const remove = mutation ({ args : { id : v. id ( "items" ) }, returns : v. null (), handler : async (ctx, args) => { await ctx. db . delete (args. id ); return null ; }, }); 5. Main Exports // src/index.ts export { default as component } from "./component" ; export * from "./functions/queries" ; export * from "./functions/mutations" ; // Export types for consumers export type { Id } from "./_generated/dataModel" ; Using a Component // In the consuming app's convex/convex.config.ts import { defineApp } from "convex/server" ; import myComponent from "my-convex-component" ; const app = defineApp (); app. use (myComponent, { name : "myComponent" }); export default app; // In the consuming app's code import { useQuery, useMutation } from "convex/react" ; import { api } from "../convex/_generated/api" ; function MyApp ( ) { // Access component functions through the app's API const items = useQuery (api. myComponent . list , { limit : 10 }); const createItem = useMutation (api. myComponent . create ); return ( < div > {items?.map((item) => ( < div key = {item._id} > {item.name} </ div > ))} < button onClick = {() => createItem({ name: "New", data: {} })}> Add Item </ button > </ div > ); } Component Configuration Options // convex/convex.config.ts import { defineApp } from "convex/server" ; import myComponent from "my-convex-component" ; const app = defineApp (); // Basic usage app. use (myComponent); // With custom name app. use (myComponent, { name : "customName" }); // Multiple instances app. use (myComponent, { name : "instance1" }); app. use (myComponent, { name : "instance2" }); export default app; Providing Component Hooks // src/hooks.ts import { useQuery, useMutation } from "convex/react" ; import { FunctionReference } from "convex/server" ; // Type-safe hooks for component consumers export function useMyComponent ( api : { list: FunctionReference< "query" >; create: FunctionReference< "mutation" >; } ) { const items = useQuery (api. list , {}); const createItem = useMutation (api. create ); return { items, createItem, isLoading : items === undefined , }; } Publishing a Component package.json { "name" : "my-convex-component" , "version" : "1.0.0" , "description" : "A reusable Convex component" , "main" : "dist/index.js" , "types" : "dist/index.d.ts" , "files" : [ "dist" , "convex.config.ts" ] , "scripts" : { "build" : "tsc" , "prepublishOnly" : "npm run build" } , "peerDependencies" : { "convex" : "^1.0.0" } , "devDependencies" : { "convex" : "^1.17.0" , "typescript" : "^5.0.0" } , "keywords" : [ "convex" , "component" ] } tsconfig.json { "compilerOptions" : { "target" : "ES2020" , "module" : "ESNext" , "moduleResolution" : "bundler" , "declaration" : true , "outDir" : "dist" , "strict" : true , "esModuleInterop" : true , "skipLibCheck" : true } , "include" : [ "src/**/*" ] , "exclude" : [ "node_modules" , "dist" ] } Examples Rate Limiter Component // rate-limiter/src/schema.ts import { defineSchema, defineTable } from "convex/server" ; import { v } from "convex/values" ; export default defineSchema ({ requests : defineTable ({ key : v. string (), timestamp : v. number (), }) . index ( "by_key" , [ "key" ]) . index ( "by_key_and_time" , [ "key" , "timestamp" ]), }); // rate-limiter/src/functions/mutations.ts import { mutation } from "../_generated/server" ; import { v } from "convex/values" ; export const checkLimit = mutation ({ args : { key : v. string (), limit : v. number (), windowMs : v. number (), }, returns : v. object ({ allowed : v. boolean (), remaining : v. number (), resetAt : v. number (), }), handler : async (ctx, args) => { const now = Date . now (); const windowStart = now - args. windowMs ; // Clean old entries const oldEntries = await ctx. db . query ( "requests" ) . withIndex ( "by_key_and_time" , ( q ) => q. eq ( "key" , args. key ). lt ( "timestamp" , windowStart) ) . collect (); for ( const entry of oldEntries) { await ctx. db . delete (entry. _id ); } // Count current window const currentRequests = await ctx. db . query ( "requests" ) . withIndex ( "by_key" , ( q ) => q. eq ( "key" , args. key )) . collect (); const remaining = Math . max ( 0 , args. limit - currentRequests. length ); const allowed = remaining > 0 ; if (allowed) { await ctx. db . insert ( "requests" , { key : args. key , timestamp : now, }); } const oldestRequest = currentRequests[ 0 ]; const resetAt = oldestRequest ? oldestRequest. timestamp + args. windowMs : now + args. windowMs ; return { allowed, remaining : remaining - (allowed ? 1 : 0 ), resetAt }; }, }); // Usage in consuming app import { useMutation } from "convex/react" ; import { api } from "../convex/_generated/api" ; function useRateLimitedAction ( ) { const checkLimit = useMutation (api. rateLimiter . checkLimit ); return async ( action : () => Promise < void >) => { const result = await checkLimit ({ key : "user-action" , limit : 10 , windowMs : 60000 , }); if (!result. allowed ) { throw new Error ( `Rate limited. Try again at ${ new Date (result.resetAt)} ` ); } await action (); }; }
Keywords that activate this skill. Click one to copy it.
This skill does not provide trigger words.
The downloaded .skill package contains the following fields.
| Field | Description |
|---|---|
| format | Format tag (skill/v1) |
| skill_id | Unique skill ID |
| name | Skill name |
| version | Version |
| description | Description |
| category | Categories (array) |
| trigger_words | Trigger words |
| tags | Tags |
| source | Source |
| source_url | Source URL (this page) |
| exported_at | Exported at (set per download) |
| system_prompt | System prompt body |
| model_config | Model config: provider / model / temperature / max_tokens / top_p |
| examples | Examples |
| install_guide | Import guide for Coze / Dify / Claude / custom frameworks |
The same skill can be exported in different platform formats.