Skip to main content

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:

FeatureGroupsComposites
Instance behaviorEach copy creates an independent subgraphAll instances reference the same shared definition
UpdatesChanges affect only that specific groupChanges propagate to all instances automatically
AnalogyLike a function or closureLike a class or library
SharingScoped to single applicationCan be published and shared across applications
Use caseOrganizing logic within one appCreating 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.

composite component example

Step 1: Design the Interface

First, define what your composite does:

Input ports:

  • url (string): The URL to validate

Output ports:

  • result (object): Contains valid (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.

composite component example

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.

composite component example

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

DoDon'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

DoDon'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

DoDon't
- Maintain backward compatibility when possible
- Document breaking changes clearly
- Silently change behavior without versioning
- Break existing consumers without migration paths

Handle Errors Gracefully

DoDon'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

DoDon'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:

  1. Explore the repository: Browse existing composites to see patterns and learn best practices
  2. Refactor existing flows: Identify repeated logic in your apps and extract it into composites
  3. Build your library: Create reusable composites for your team's common patterns
  4. Contribute to the community: Publish your best composites to help others