Skip to content

Configuration fields

Sources, destinations, connections, configs, jobs and hooks all have configuration fields. They are pydantic fields, and a set of helpers annotates them with how a form should render them. Every helper is a thin wrapper around pydantic.Field: all standard keywords (default, description, title, ge, default_factory, …) pass through.

Field helpers

Helper Renders as Typical use
il.InputField() Text input Ids, hosts, names
il.SecretField() Masked input API keys, tokens, passwords
il.TextField() Multi-line textarea Queries, PEM keys
il.JsonField() JSON editor Dict-valued settings
il.CronField() Cron editor with presets Schedules
il.TimezoneField() Searchable IANA timezone picker Timezones
il.SelectField(options=[...]) Dropdown with fixed options Regions, modes
il.SelectField(options_from="destinations") Dropdown fed by configured components Picking one of the instance's destinations
il.FetchField(provider="connection.accounts") Dropdown fetched from the service Ad accounts, properties, projects
@il.source
class GoogleAnalytics(il.Source):
    property_id: str = il.FetchField(
        provider="connection.properties",
        label_key="displayName",
        value_key="name",
        description="The GA4 property to read",
        discriminator=True,
    )
    region: str = il.SelectField(
        default="eu",
        options=[{"label": "Europe", "value": "eu"}, {"label": "US", "value": "us"}],
    )

A field without a helper is still a configuration field; it renders with a generic widget.

Presentation keywords

Every helper also accepts:

Keyword Effect
label= The form label (sets the JSON Schema title).
info= Longer help text shown in a tooltip, keeping description short.
discriminator=True Marks the field whose value distinguishes instances of the component. See Sources.
section= The labelled group of the form the field renders under (sets x-section). Fields without one lead the form.

A plain Field declares a section through json_schema_extra={"x-section": "Operation"}.

Fetched options

A FetchField resolves its options by instantiating the resource of the named relation from the credentials the form already holds and calling a method on it. The method must be allow-listed with @il.fetch_field_provider; only such methods may be invoked from a form:

@il.connection(name="Google Analytics", oauth=il.OAuthConfig("google", scope="..."))
class GoogleAnalyticsConnection(il.RefreshTokenOAuthConnection):
    @il.fetch_field_provider
    async def properties(self) -> list[dict]:
        async with httpx2.AsyncClient() as client:
            response = await client.get(ADMIN_URL, headers=self.headers)
        return response.json()["properties"]

The provider returns a list[dict]; the field picks label_key and value_key from each item. The reference is "<name>.<method>", where <name> is a relation of the component declaring the field, whose target class carries the method. Because the method may run inside the API process, which installs connection classes without their heavy SDK extras, providers must use plain HTTP.

References are validated when the component's definition is built: an undeclared relation, or a method without the decorator, raises TypeError at catalog-build time rather than failing silently in a form. il.is_fetch_field_provider(obj) tests whether a callable is a provider.

What ends up in the config schema

Component.config_schema() is the JSON Schema of the component's user-facing fields. The framework strips id, plus anything the class lists in internal_fields (sources hide assets, normalizer, select; assets hide normalizer). Relations (destinations, connection, and so on) are not fields at all and never appear in the schema. Field helpers add x-widget, x-info, x-options, x-options-from, x-fetch, x-discriminator and x-section extensions that forms read. The schema is part of every component definition.

Properties are listed most specific first: the class's own fields, then each ancestor's, closest first, each in declaration order. A source's form therefore opens with its own account field rather than with the settings every source shares, and forms render in this order.