Creating Composite Components
You can extend Kelp's functionality beyond standard components by creating your own composite components or installing custom components from the repository.
Composite components are reusable, shareable building blocks that enable you to encapsulate complex logic and reuse it across your Kelp applications. Think of them as libraries or packages for your flows.
What Are Composite Components?
A composite component (also called a composite) is a self-contained subgraph that can be instantiated multiple times within an application or shared across different applications. Unlike regular groups, all instances of a composite component reference the same underlying definition—similar to how multiple objects instantiate the same class in object-oriented programming.
When you create a composite component, you're defining:
- A set of internal nodes and their connections
- Input and output ports that emit data from/to parent flows
- Configuration options and settings
- A reusable contract that all instances share
Groups vs Composite Components
It's important to understand how composite components differ from groups:
| Feature | Groups | Composites |
|---|---|---|
| Instance behavior | Each copy creates an independent subgraph | All instances reference the same shared definition |
| Updates | Changes affect only that specific group | Changes propagate to all instances automatically |
| Analogy | Like a function or closure | Like a class or library |
| Sharing | Scoped to single application | Can be published and shared across applications |
| Use case | Organizing logic within one app | Creating reusable libraries and patterns |
Key insight: Groups are like inline functions—you copy the code wherever you need it. Composite components are like imported modules—you reference a single definition from multiple places.
When to Use Composite Components
Consider using composite components when you:
1. Need to Reuse Complex Logic
You've built a sophisticated workflow (e.g., error handling, retry logic, data transformation pipeline) that you want to use in multiple places without copying and pasting.
Example: An "AI Agent" composite that handles various operations around Large Language Model (LLM) API.
2. Want Centralized Updates
When you improve or fix a bug in the composite, all instances in your application automatically benefit from the update.
Example: You discover a more efficient way to parse JSON in your "JSON Parser" composite. Update it once, and all 10 instances across your app improve instantly.
3. Building Reusable Libraries
You're creating components that others on your team (or the community) might benefit from.
Example: A "Rate Limiter" composite that enforces API call limits, or a "Cache Manager" that handles cache invalidation strategies.
4. Ensuring Consistency
Multiple parts of your system need to perform the same operation in exactly the same way.
Example: A "Data Validator" composite that enforces the same validation rules across multiple API endpoints.
5. Managing Complexity
Breaking down large applications into smaller, named, testable units.
Example: A multi-step onboarding flow could be decomposed into composites like "Account Creator", "Email Verifier", and "Profile Setup".
Basic Example: Creating a Simple Composite
Let's build a practical example: a URL Validator composite that checks if a URL is valid and extracts its components.

Step 1: Design the Interface
First, define what your composite does:
Input ports:
url(string): The URL to validate
Output ports:
result(object): Containsvalid(boolean),protocol,host,path
Step 2: Component Structure
Implement the component logic, wrap it into a group, and export the input/output ports.
Use the following Kelp snippet as an example. Just copy and paste it to your Kelp canvas.
URL Validator component example (click to expand full code block).
{
"nodes": {
"01KG2W0MK0N5Y9PJEJ6X1009T8": {
"name": "01KG2W0MK0N5Y9PJEJ6X1009T8",
"type": "group",
"metadata": {
"x": -500,
"y": 1110,
"sublabel": "URL Validator"
},
"inports": {
"84610ba4-0bea-5d68-bff5-a93ea27ca341": {
"label": "url",
"node": "01KG2VFHE9YW61MY4PPKCMYF8Y",
"port": "input"
}
},
"outports": {
"27a06b7f-8ce5-50af-8948-d12fd7fd6acf": {
"label": "result",
"node": "01KG2VFN3C3M72YT1V22AQTC7R",
"port": "output"
}
}
}
},
"groups": {
"01KG2W0MK0N5Y9PJEJ6X1009T8": {
"name": "01KG2W0MK0N5Y9PJEJ6X1009T8",
"nodes": {
"01KG2VFHE9YW61MY4PPKCMYF8Y": {
"name": "port",
"type": "component",
"version": "~0.0.1",
"metadata": {
"x": 0,
"y": 0,
"sublabel": "url"
},
"inports": {
"input": {
"label": "url",
"node": "01KG2VFHE9YW61MY4PPKCMYF8Y",
"port": "input",
"isExport": true
}
},
"outports": {
"output": {
"label": "url",
"node": "01KG2VFHE9YW61MY4PPKCMYF8Y",
"port": "output"
}
}
},
"01KG2VFN3C3M72YT1V22AQTC7R": {
"name": "port",
"type": "component",
"version": "~0.0.1",
"metadata": {
"x": 60,
"y": 0,
"sublabel": "result"
},
"inports": {
"input": {
"label": "result",
"node": "01KG2VFN3C3M72YT1V22AQTC7R",
"port": "input"
}
},
"outports": {
"output": {
"label": "result",
"node": "01KG2VFN3C3M72YT1V22AQTC7R",
"port": "output",
"isExport": true
}
}
}
},
"edges": [
{
"from": {
"node": "01KG2VFHE9YW61MY4PPKCMYF8Y",
"port": "output"
},
"to": {
"node": "01KG2VFN3C3M72YT1V22AQTC7R",
"port": "input"
},
"attrs": {
"transforms": [
{
"name": "transform_kelpql",
"config": {
"expression": "match(@, regexp('^(https?:\\/\\/)?([\\da-z\\.-]+\\.[a-z\\.]{2,6})([\\/\\w \\.-]*)*\\/?')).allMatches\n| length(@) > 0 && (\n {\n valid: true,\n protocol: [1].match,\n host: [2].match,\n path: [3].match\n }\n) || {valid: false}"
}
}
]
}
}
]
}
},
"edges": [],
"versionInfo": {
"schemaVersion": 6
},
"components": {},
"componentLinks": {},
"runtimeMetadata": {
"components": {}
},
"configuration": {
"credentialsMapping": {},
"storagesMapping": {},
"credentialsConfiguration": {},
"storagesConfiguration": {}
}
}
Step 3: Create Composite Component
Select the group, then go to Main menu > Component > Create component to turn it into a composite component. Specify a name and optional description, category, or config, then click Create to create the component.

Key points:
- The composite behaves like any other component from the parent flow's perspective
- You can create multiple instances that all reference the same definition
- You can "ungroup" any composite instance back to a group
- Manage your application components in the Composites panel on the left
- Composite components can contain other composite components, enabling powerful composition patterns
Repository of Composite Components
Kelp maintains a growing library of community-created composite components that you can use in your applications.
You can find available composites in the Components Library under EXTENSIONS and CUSTOM sections.

Categories:
- AI: AI, Agents and related tools and utilities
- Content Generation: templates, formatters and converters
- Data Conversion: JSON/XML parsers, data transformers, validators
- Flow Control: specialized iterators, routers, repeaters
- Interactive: packaged UI elements, widgets, visualizations
- Kelp Helpers: various system utilities
- Web Tools: API wrappers and processors
Best Practices
Design Clear Interfaces
| Do | Don't |
|---|---|
- Use descriptive port names (user-data, validation-result)- Document what each port expects and returns - Keep the number of ports manageable (typically 1-5 inputs, 1-3 outputs) | - Create generic ports like input1, input2 without clear purpose- Expose internal implementation details through ports |
Keep Composites Focused
| Do | Don't |
|---|---|
| - Build composites that do one thing well - Follow the Single Responsibility Principle - Aim for composites that can be understood in 5 minutes | - Create "god composites" that do everything - Mix unrelated concerns in one composite |
Version Thoughtfully
| Do | Don't |
|---|---|
| - Maintain backward compatibility when possible - Document breaking changes clearly | - Silently change behavior without versioning - Break existing consumers without migration paths |
Handle Errors Gracefully
| Do | Don't |
|---|---|
| - Include explicit error output ports - Provide meaningful error messages- Use the errors port pattern consistently | - Swallow errors silently - Return error strings in success output ports |
Optimize for Reusability
| Do | Don't |
|---|---|
| - Parameterize behavior through input ports or configuration - Avoid hardcoding values - Design for composability (outputs that can feed into other composites) | - Assume specific upstream or downstream components - Create tight coupling to application-specific logic |
Next Steps
Now that you understand composite components, you can:
- Explore the repository: Browse existing composites to see patterns and learn best practices
- Refactor existing flows: Identify repeated logic in your apps and extract it into composites
- Build your library: Create reusable composites for your team's common patterns
- Contribute to the community: Publish your best composites to help others