Plugin Best Practices
Architectural guidelines for building maintainable, safe, and isolated plugins.
Adhering to plugin best practices ensures your extensions maintain high performance, avoid naming collisions, and preserve security boundaries.
1. Keep Setup Synchronous
The setup() function must be completely synchronous:
// ❌ Anti-pattern: Async setup functions throw an error at runtime
setup: async ({ service }) => {
await fetchRemoteConfig();
}
// ✅ Correct: Synchronous registration of declarations
setup: ({ service, routes }) => {
routes.action({ ... });
}Never initiate database migrations, connect to external network endpoints, or execute queries during setup(). Plugin installation occurs when defining services before the server boots.
2. Depend on Runtime Context (ctx.db)
Plugins should not instantiate their own database connections or cache clients:
// ✅ Correct: Use ctx.db injected from the host service
execute: async ({ input, ctx }) => {
const db = ctx.db;
return db.select().from(table);
};Using ctx.db guarantees that plugins respect transaction boundaries, tenant routing, and context isolation.
3. Explicit Access and Validation
When registering actions inside a plugin via routes.action(), always specify:
- TypeBox
inputandoutputschemas. - Explicit
methodandpath. - An authorization check or clear documentation indicating the action is public.
4. Avoid Property Collisions on Host Resources
Resource plugins return objects that are assigned directly to the host resource. Never return keys that conflict with core resource properties:
- Reserved resource keys:
name,serviceName,table,id,idField,config,use. - Avoid prototype keys:
__proto__,prototype,constructor.
Brick checks for collisions during plugin installation and throws an immediate error if a collision is detected.
5. Structured Error Handling
When rejecting operations in plugins or hooks, throw ActionExecutionError with standard HTTP error codes:
import { ActionExecutionError } from "@brickkit/core";
if (!isValid) {
throw new ActionExecutionError(
"BAD_REQUEST",
"Invalid plugin parameter",
400,
);
}This ensures errors format into the standard Brick-TS JSON envelope expected by typed clients.