Learning the OAA Runner Framework: Part 1 — Your First CSV Upload¶

This is Part 1 of the Learning the OAA Runner Framework series.
What you’ll learn: Create a working config.yaml that reads a CSV file and maps its
columns to OAA user fields. By the end you’ll run the integration and see oaa-runner load
users from a CSV without errors.
Prerequisites¶
oaa-runner installed. See How to install uv and How to run integrations locally.
Setup¶
Create your working directory:
mkdir -p 01-csv-upload/data
cd 01-csv-upload
Copy the following content into a new file at data/users.csv:
user_id,email,first_name,last_name
1001,alice@example.com,Alice,Anderson
1002,bob@example.com,Bob,Baker
1003,carol@example.com,Carol,Chen
Create an empty config.yaml:
touch config.yaml
Your goal: load these three users into Veza as a Custom App called “Example App - CSV Upload”.
Step 1: Define the application¶
Open config.yaml and add the following at the top:
version: v2
log_level: INFO
app:
name: Example App - CSV Upload
application_type: Custom App
version: v2— required header for all oaa-runner configs.app.name— the name that appears in Veza.application_type: Custom App— tells oaa-runner to create a generic custom application.
Step 2: Add a source¶
A source is a named data stream that feeds one type of OAA entity. Add a sources block
below the app block:
sources:
users:
destination: LocalUser
source_type: csv_push
csv_filepath: data/users.csv
csv_provider_id: "!env"
destination: LocalUser— the OAA entity type for users who belong to an application.source_type: csv_push— reads a local CSV and pushes it to Veza’s CSV ingest endpoint. This is the simpler of the two CSV source types: it uploads the file as-is without running it through oaa-runner’s transform or generator pipeline. A second source type,csv, processes the file locally through the full pipeline and is required for features like generators and hooks — it is introduced in Part 3 — Modeling a Custom Application.csv_filepath— path to the CSV, relative to the config file.csv_provider_id: "!env"— tells oaa-runner to read the CSV provider ID from the environment variableCSV_PROVIDER_ID. The!envshorthand derives the env var name from the field name (uppercased). This syntax is deprecated — for connection parameters, userequired_envwith an explicit env var name instead. See How to use required env.csv_provider_idis a source-level field that currently only supports!env; new connection-level params (API keys, base URLs) should userequired_env.
Step 3: Map columns to OAA fields¶
Each CSV column needs to be mapped to an OAA field. Add a field_mapping block inside
the users source:
field_mapping:
user_id:
destination_field: unique_id
email:
destination_field: email
first_name:
destination_field: given_name
last_name:
destination_field: family_name
Each key in field_mapping is a CSV column name. destination_field is the OAA field
it maps to:
Destination field |
OAA meaning |
|---|---|
|
Required. Stable identifier for the user within this app. |
|
User’s email address. Used for cross-system identity matching. |
|
First name, stored as a custom property. |
|
Last name, stored as a custom property. |
Complete config¶
Your config.yaml should now look like this:
version: v2
log_level: INFO
app:
name: Example App - CSV Upload
application_type: Custom App
sources:
users:
destination: LocalUser
source_type: csv_push
csv_filepath: data/users.csv
csv_provider_id: "!env"
field_mapping:
user_id:
destination_field: unique_id
email:
destination_field: email
first_name:
destination_field: given_name
last_name:
destination_field: family_name
Run it¶
From the 01-csv-upload directory:
uv tool run --from oaa-runner oaa app run --config-file=config.yaml --no-push
--no-push loads and validates the data locally without sending anything to Veza.
Environment variables are not required for a dry run — the CSV_PROVIDER_ID value in
your config is read but the push step is skipped. See
How to run integrations locally
for an explanation of the uv tool run --from oaa-runner command pattern.
You should see output like:
INFO - Skipping CSV push to Veza (no_push=True)
status: true
report: []
Note: You may also see a Pydantic serialization warning about
data_plane_id. This is a known cosmetic issue in oaa-runner v0.2.x and does not affect the integration output.
If you see errors, check that:
You’re running from inside the
01-csv-uploaddirectorydata/users.csvexists and has the correct column names
To push to your Veza instance, remove --no-push and set the required environment variables:
export VEZA_URL=https://your-veza-instance.veza.com
export VEZA_API_KEY=your_api_key
export CSV_PROVIDER_ID=your_csv_provider_id
uv tool run --from oaa-runner oaa app run --config-file=config.yaml
What’s next¶
This config maps columns directly — one CSV column to one OAA field, no modifications. The next example adds transforms to handle messy data: mixed-case emails, inconsistent boolean values, date strings, and columns that don’t map to a standard OAA field.