Build a Simple Application
Applications are powerful, reusable groups of derived Components bundled into a single visual unit within your Flow Graph. The Simple Application is a built-in Ascend solution that generates Components from templates using Jinja, enabling flexible and maintainable data pipelines.
When to use Simple Applications
Choose Simple Applications when you need:
- Template-based Component generation with Jinja
- SQL, Python, or YAML templates with parameter substitution
- Multiple related Components that share configuration
- Reusable patterns across different datasets
For complex logic requiring full programmatic control, see Custom Applications.
Quick start
1. Create template directory
my_project/
├── templates/
│ └── customer_pipeline/
│ ├── read_source.yaml
│ ├── clean_data.sql
│ └── aggregate.py
2. Configure the Application
component:
application:
application_id: simple
config:
template_path: templates/customer_pipeline
parameters:
source_table: raw_customers
min_age: 18
include_inactive: false
Template types
Simple Application processes three types of template files:
| Extension | Type | Use case |
|---|---|---|
.yaml, .yml | YAML | Read Components, Write Components, declarative configurations |
.sql, .sql.jinja | SQL | Transform Components with SQL logic |
.py | Python | Transform Components with Python logic |
Context variables
Simple Application provides these variables in all templates:
| Variable | Description |
|---|---|
_ascend_flow_name | Name of the containing Flow |
_ascend_component_name | Component name (without parent prefix) |
_ascend_application_component_name | Parent Application Component name |
_ascend_fully_qualified_component_name | Full name with parent prefix |
SQL templates
SQL templates create Transform Components with Jinja templating.
Basic SQL template
-- Parameters are directly accessible
SELECT *
FROM {{ ref(input_table) }}
WHERE {{ filter_column }} > {{ threshold }}
{% if include_inactive %}
OR status = 'inactive'
{% endif %}
Reference sibling Components
Use application_subcomponent_ref() to reference other Components in the same Application:
-- Reference a sibling component in the same Application
SELECT
s.*,
CURRENT_TIMESTAMP() as processed_at
FROM {{ application_subcomponent_ref('read_source') }} s
WHERE s.value > {{ min_value }}
Reference external Components
Use standard ref() for Components outside the Application:
SELECT
t.*,
l.region_name
FROM {{ application_subcomponent_ref('transform') }} t
LEFT JOIN {{ ref('lookup_regions') }} l
ON t.region_id = l.id
-- Or reference from another Flow
LEFT JOIN {{ ref('dimension_table', flow='dimensions') }} d
ON t.dim_id = d.id
Python templates
Python templates create Transform Components with full Python capabilities.
Basic Python template
from ascend.resources import transform, application_subcomponent_name, application_subcomponent_ref
@transform(name=application_subcomponent_name('aggregate'))
def aggregate(
clean_data=application_subcomponent_ref('clean_data', alias='clean_data'),
context=None
):
# Access parameters from context
group_column = context.parameters.get('group_by', 'category')
return clean_data.group_by(group_column).agg({
'amount': 'sum',
'count': 'count'
})
Python template helpers
| Function | Description |
|---|---|
application_subcomponent_name(name) | Returns fully qualified Component name |
application_subcomponent_ref(name, alias) | Creates reference to sibling Component |
Access Application configuration
In Python templates, access Application configuration through context:
from ascend.resources import transform, application_subcomponent_name, ref
@transform(name=application_subcomponent_name('process'))
def process(input_data=ref('source_table'), context=None):
# Access flow parameters
threshold = context.parameters.get('threshold', 100)
# Access application config through application_component_context
app_config = context.application_component_context.config.get('parameters', {})
enable_filter = app_config.get('enable_filter', False)
if enable_filter:
return input_data.filter(input_data['value'] > threshold)
return input_data
YAML templates
YAML templates define declarative Components, typically Read or Write Components.
Read Component template
component:
read:
connection: {{ connection_name }}
{{ data_platform }}:
table: {{ source_table }}
{% if schema_name is defined %}
schema: {{ schema_name }}
{% endif %}
Write Component template
component:
write:
input:
name: {{ application_subcomponent_name('transform') }}
flow: {{ _ascend_flow_name }}
connection: {{ output_connection }}
{{ output_platform }}:
table: {{ output_table }}
Complete example
Here's a full Simple Application that builds a customer analytics pipeline.
Directory structure
templates/
└── customer_analytics/
├── read_customers.yaml
├── clean_data.sql
├── calculate_metrics.sql
└── aggregate.py
Template files
component:
read:
connection: {{ connection_name }}
snowflake:
table: {{ source_table }}
schema: {{ schema_name | default('PUBLIC') }}
-- Clean and filter customer data
SELECT
customer_id,
email,
created_at,
total_purchases
FROM {{ application_subcomponent_ref('read_customers') }}
WHERE created_at >= '{{ start_date }}'
{% if min_purchases is defined %}
AND total_purchases >= {{ min_purchases }}
{% endif %}
-- Calculate customer metrics
SELECT
customer_id,
email,
created_at,
total_purchases,
DATEDIFF('day', created_at, CURRENT_DATE()) as days_since_signup,
total_purchases / NULLIF(DATEDIFF('day', created_at, CURRENT_DATE()), 0) as purchases_per_day
FROM {{ application_subcomponent_ref('clean_data') }}
Application configuration
component:
application:
application_id: simple
config:
template_path: templates/customer_analytics
parameters:
connection_name: warehouse
source_table: raw_customers
schema_name: SALES
start_date: "2024-01-01"
min_purchases: 5
aggregate_by: region
Reference Application sub-components from outside
From other Components in your Flow, reference Application sub-components using the parent__child naming pattern:
-- In another Component outside the Application
SELECT *
FROM {{ ref('customer_analytics__aggregate') }}
WHERE customer_count > 100
Best practices
- Organize templates logically: Group related templates in directories
- Use descriptive parameter names: Make configuration self-documenting
- Provide defaults: Use
{{ param | default('value') }}for optional parameters - Document parameters: Add comments explaining expected parameter values
- Test templates: Validate templates work with various parameter combinations
- Keep templates focused: Each template should do one thing well
Troubleshooting
| Issue | Cause | Solution |
|---|---|---|
| Template not found | Incorrect template_path | Verify path is relative to project root |
| Parameter undefined | Missing parameter in config | Add parameter or provide default with ` |
| Reference error | Wrong component name | Use application_subcomponent_ref() for siblings |
| Empty output | Template file is empty | Remove empty files or add content |
Next steps
- Learn about Custom Applications for programmatic generation
- Review the Applications concept guide