SSIS¶
This section describes the dbt output format for SSIS: how Data Flow Tasks are converted into dbt projects and Control Flow tasks and containers into Snowflake orchestration. For a before/after example of each Data Flow component, see Mappings and transformations.
The default conversion path is a dbt project. Eligible Data Flow graphs that connect a Flat File Source to an OLE DB Destination emit Direct COPY and do not create a dbt project. The --SimplifySsisDataFlows flag is not part of this dbt documentation series.
How a Data Flow becomes a dbt project¶
Each Data Flow Task is converted into a standalone dbt project with a three-tier model architecture.
| Layer | Materialization | Purpose |
|---|---|---|
models/staging/ | View | Clean, type-safe access to source data referenced in sources.yml. Generated from OLE DB Source, Flat File Source, ADO.NET Source, Excel Source, and Oracle Source. |
models/intermediate/ | Ephemeral by default | Transformation logic from the original Data Flow. Generated from Derived Column, Lookup, Aggregate, Conditional Split, and other transformations. Some components override that default: a Sort is materialized so its ORDER BY is preserved, and an OLE DB Command path can change the materialization of the models it feeds. |
models/marts/ | Table, incremental, or view | Business-ready data models that correspond to destinations. An OLE DB Destination, Excel Destination, Oracle Destination, or Flat File Destination becomes a mart named after the target. An OLE DB Command can produce an incremental model instead. |
Each Data Flow produces this project structure:
Important
Before deploying, replace the YOUR_SCHEMA and YOUR_DB placeholders in sources.yml and profiles.yml with your actual Snowflake schema and database names.
Most Data Flows follow the default path: the Data Flow becomes a dbt project, and the Control Flow Task that runs it calls EXECUTE DBT PROJECT. One case skips the dbt project. When a Data Flow only moves a Flat File Source into an OLE DB Destination, the conversion emits a Direct COPY instead: the Task runs a COPY INTO statement against the staged file, and no dbt project is generated for that Data Flow. Eligibility depends on the shape of the Data Flow, so check the generated output to see which path each Data Flow took. For the generated statements, see Mappings and transformations.
Ingestion¶
Generated flat-file reads bind to the shared public.landing_stage, and Flat File Destinations unload to it. Files consumed by the reads must be in the stage before the converted code runs. The conversion inventories each read, binds it to a stable stage prefix, and writes an ingestion manifest with importable Openflow flows that land the files.
| Generated file | Contents |
|---|---|
ingestion-manifest.json | One entry per landed source: the owning package and connection manager, original locations, bound stage prefix, selected file or pattern, generated consumers, and expected object-store and stage paths. With an artifacts path and session timestamp, find it at <artifacts path>/ingestion/<session timestamp>/ingestion-manifest.json. Without a timestamp, the timestamp segment is omitted. Without an artifacts path, find it at ETL/ingestion-manifest.json. |
ETL/openflow/SnowConvert ETL Landing.json | An Openflow flow that lists, fetches, and puts your source files into the landing stage from an S3-compatible store. SnowConvert ETL Landing (Azure).json and SnowConvert ETL Landing (GCS).json are the Azure Blob Storage and Google Cloud Storage variants of the same flow. |
Landing the files¶
- Read the manifest: each source carries the bound stage prefix, the original locations found in the package, and the object-store prefix to upload to.
- Map each original location to a prefix in your own object store: SnowConvert can’t infer a bucket from
C:\Landing\Salesor from a UNC share, so that mapping is yours to decide. The stage side of the mapping is already fixed by the generated SQL. - Import the flow that matches your object store: every component is emitted disabled. The flow carries parameter names such as
SOURCE_BUCKET,SOURCE_ENDPOINT, andSOURCE_REGIONplus Snowflake connection settings, never values or credentials. Fill in the parameters and credentials service, then enable the flow. The canvas has one process group per package and aSharedgroup for project-level connection managers. A source that still needs a customer mapping, such as a connection string built from an SSIS expression, is omitted. - Confirm the files landed:
LIST @public.landing_stage/ssis/shows the objects that arrived under the generated prefixes. - Run the converted code: the Direct COPY tasks, dbt projects, and orchestration procedures all read from those prefixes. Destination keys stay the same on every run, so
COPY INTOload history keeps working.
Stage prefixes¶
Each converted read binds to a prefix built from the SSIS identity that owns the file, not from the original folder:
| Source | Bound stage prefix |
|---|---|
| Flat File Source with a package connection manager | ssis/<package>/<connection manager>/ |
| Flat File Source with a project connection manager | ssis/projects/<connection manager>_<12 hexadecimal characters>/ |
| Excel Source | ssis/<package>/, the package folder without a connection manager segment |
| Any of those inside a ForEach File container | The same prefix followed by the normalized enumerated folder, so C:\Landing\Sales becomes c/landing/sales/ and \\corp-fs\finance\incoming becomes unc/corp_fs/finance/incoming/ |
A read of one exact file keeps the file name observed in the package, so a FinanceLoad package whose OrdersFile connection manager points at \\corp-fs\finance\incoming\orders.csv reads @public.landing_stage/ssis/FinanceLoad/OrdersFile/orders.csv. When the package doesn’t resolve to a file name, the path keeps UNKNOWN_FILE and no destination is invented for it.
ForEach File containers¶
A ForEach File container is the only shape where a file pattern, subfolder recursion, or a folder-only connection string is eligible. The land prefix carries the enumerated folder. FileSpec becomes the PATTERN, and TraverseSubfolders decides whether nested keys are preserved.
When the body is eligible, the loop collapses into a single patterned load: see ForEach File loads. A nested or otherwise ineligible body keeps the loop and falls back to LIST plus a cursor over the same bound prefix, as described in ForEach Loop Containers.
Sources that are inventoried¶
The manifest covers the reads that can bind to the landing stage:
- Flat File Sources with a delimited connection manager.
- Flat File Sources with a fixed-width connection manager when every column declares a width. The generated SQL slices those rows with
SUBSTR. - Excel Sources.
MultiFlatFile connection managers aren’t inventoried, and neither is a fixed-width connection manager whose column layout is incomplete.
Data flow components¶
These SSIS Data Flow sources, transformations, and destinations are supported. Unlisted Data Flow components generate EWI SSC-EWI-SSIS0001. Raw File Source, Raw File Destination, and XML Source are not yet available. For a before/after example of each, see Mappings and transformations.
| Component | Category | dbt mapping | Naming | Status |
|---|---|---|---|---|
| Source | Staging model | stg_raw__{component_name} | Available | |
| Source | Staging model | stg_raw__{component_name} | Available. See Ingestion | |
| Source | Staging (source() or embedded SQL) | stg_raw__{component_name} | Available | |
| Source | Staging (READ_EXCEL UDF) | stg_raw__{component_name} | Available with limitations. See Ingestion | |
| Source | Staging | stg_raw__{component_name} | Available with limitations | |
| Transformation | Intermediate (SELECT with expressions) | int_{component_name} | Available | |
| Transformation | Intermediate (CAST) | int_{component_name} | Available | |
| Transformation | Intermediate (UPPER/LOWER) | int_{component_name} | Available | |
| Transformation | Intermediate (LEFT JOIN) | int_{component_name} | Available. See SSC-FDM-SSIS0001 | |
| Transformation | Intermediate (UNION ALL) | int_{component_name} | Available | |
| Transformation | Intermediate (UNION ALL) | int_{component_name} | Available. See SSC-FDM-SSIS0002 | |
| Transformation | Intermediate (JOIN) | int_{component_name} | Available. See SSC-FDM-SSIS0004 | |
| Transformation | Intermediate (router pattern with CTEs) | int_{component_name} | Available | |
| Transformation | Intermediate (SELECT pass-through) | int_{component_name} | Available | |
| Transformation | Intermediate with macro | int_{component_name} | Available | |
| Transformation | Intermediate (QUALIFY / ORDER BY) | int_{component_name} | Available | |
| Transformation | Intermediate (GROUP BY) | int_{component_name} | Available | |
| Transformation | Intermediate (conditional aggregation) | int_{component_name} | Available | |
| Transformation | Intermediate (UNPIVOT) | int_{component_name} | Available | |
| Transformation | Passthrough SELECT | int_{component_name} | Available with limitations | |
| Transformation | Intermediate (CROSS JOIN + Jaro-Winkler) | int_{component_name} | Available | |
| Transformation | Incremental mart + delete/update macro | {target} | Available | |
| Script Component | Transformation | EWI SSC-EWI-SSIS0001 | — | Not yet available |
| Destination | Mart | {target} | Available | |
| Destination | Mart | {target} | Available. Unloads to the stage prefix described in Ingestion | |
| Destination | Mart | {target} | Available | |
| Destination | Mart | {target} | Available |
Control flow components¶
These SSIS Control Flow tasks and containers are supported:
| Element | Category | Conversion target | Status | Notes |
|---|---|---|---|---|
| Task | dbt project or Direct COPY | Available | Eligible Flat File Source to OLE DB Destination graphs emit COPY and no dbt project. Staged files come from Ingestion | |
| Task | Inline SQL or stored procedure | Available | See Execute SQL Task | |
| Task | Inline EXECUTE TASK or CALL | Available | See Execute Package Task | |
| Task | SYSTEM$SEND_EMAIL | Available with limitations | See Send Mail Task | |
| Task | COPY INTO + FILE_FORMAT | Available with limitations | See Bulk Insert Task; native format stays EWI | |
| Task | Stage COPY FILES / REMOVE | Available with limitations | Stage operations, not dbt models | |
| Task | Assignment (:=) or SELECT | Available | Converts SSIS expressions to Snowflake Scripting assignments | |
| Container | Inline sequential | Available | See Sequence Containers | |
| Container | WHILE when Init/Eval/Assign present; else once + EWI | Available with limitations | See For Loop Containers | |
| Container | COPY with PATTERN, or LIST / CURSOR | Available with limitations | Reads the bound landing-stage prefix, described in Ingestion; an unresolved folder emits SSC-EWI-SSIS0014 | |
| Container | Cursor + variable assignments | Available with limitations | Source query placeholder emits SSC-EWI-SSIS0004 | |
| Container | FLATTEN + RESULT_SCAN | Available | Iterates values from a variable collection | |
| Container | EWI stub | Not yet available | Item, NodeList, SMO, HDFS, SchemaRowset | |
| Container | Stored procedures; supported scoped OnPre/Post handlers are CALL-wired | Available with limitations | Package-level and OnError/Warning handlers can remain untriggered; Partial + SSC-FDM-SSIS0006 | |
| Task | EWI SSC-EWI-SSIS0004 | Not yet available | Script logic requires manual migration |
Note: Unlisted Control Flow elements generate EWI SSC-EWI-SSIS0004.
Container Conversion Details¶
Sequence, For Loop, and ForEach containers are converted inline within the parent task or procedure. Event Handlers are converted to stored procedures; supported scoped handlers can be wired into the parent orchestration with CALL.
Sequence Containers¶
Sequence containers are converted inline within the parent TASK. The container’s boundaries are marked with comments in the generated code, and all tasks within the container execute sequentially in the same TASK scope.
Conversion characteristics:
- No separate procedure or TASK is created for the container
- Container boundaries are clearly marked BEGIN … END blocks
- All tasks execute sequentially within the parent TASK
- Task execution order based on precedence constraints is maintained
- Limitation: Only “Success” precedence constraints are fully supported. Conditional execution based on task outcomes (Failure or Completion constraints) is not currently implemented and will require manual post-migration adjustments
Behavioral differences:
- FDM generated: SSC-FDM-SSIS0003
- Variable scoping differs from SSIS: Container variables are accessible throughout the entire parent TASK, not just within the container scope
Example:
For Loop Containers¶
For Loop containers convert to Snowflake Scripting WHILE loops when InitExpression, EvalExpression, and AssignExpression are present.
Conversion behavior¶
| Source | Snowflake | Notes |
|---|---|---|
| InitExpression | Assignment before the loop | Sets the loop counter |
| EvalExpression | WHILE condition | Loop continues while the condition is true |
| AssignExpression | Assignment at the end of the loop body | Increments or updates the counter |
| Missing Init/Eval/Assign | Body once + EWI | SSC-EWI-SSIS0004 |
Example¶
Limitations¶
- When Init, Eval, or Assign expressions are not present, the converted body runs once and SSC-EWI-SSIS0004 is generated.
ForEach Loop Containers¶
File Enumerator (Supported)
ForEach File Enumerator containers bind the enumerated folder to @public.landing_stage/ssis/<package>/<connection manager>/<enumerated folder>/. That bound prefix is the default. LIST @<STAGE_PLACEHOLDER> is not.
Eligible bodies that only move a Flat File Source into an OLE DB Destination collapse to Direct COPY. Patterned, recursive, retained-loop, and complete-fallback goldens live in ForEach File loads. A flat file connection manager whose connection string names a folder instead of a file can be bound only inside a ForEach File container, because the enumerator is what supplies the file names.
A container that can’t collapse keeps the loop. A nested container, a body that does more than the load, or a downstream task that reads the enumerated file name still reads the same bound prefix, this time with LIST and a cursor. A container whose folder can’t be resolved at all, such as one whose FileSpec comes from a property expression, falls back to LIST @<STAGE_PLACEHOLDER> and emits SSC-EWI-SSIS0014. Replace that placeholder with the stage that holds the folder before you run the task.
The files themselves reach the landing stage through the generated ingestion artifacts. See Ingestion.
ADO enumerator
ForEach ADO enumerators emit a cursor plus per-row variable assignments. The cursor source is a placeholder SELECT null until you replace it with the upstream result-set query. That placeholder emits SSC-EWI-SSIS0004. This is not a LIST pattern.
Conversion behavior¶
| Source | Snowflake | Notes |
|---|---|---|
| ADO enumerator | Cursor over a query | Replace SELECT null with the query that populated the recordset |
| Column mappings | Variable assignments inside FOR | Each mapped column is assigned and persisted with UpdateControlVariable |
Example¶
Limitations¶
- SSC-EWI-SSIS0004. Replace
SELECT nullwith the upstream result-set query before running the task.
From Variable enumerator
ForEach From Variable enumerators flatten a collection variable and iterate with RESULT_SCAN, not LIST.
Conversion behavior¶
| Source | Snowflake | Notes |
|---|---|---|
| Collection variable | TABLE(FLATTEN(...)) | One row per collection element |
| Cursor | RESULT_SCAN(LAST_QUERY_ID()) | Feeds the FOR loop |
| Mapped variable | Assignment from VALUE | Updated with UpdateControlVariable |
Example¶
Other enumerator types
ForEach Item, NodeList, SMO, HDFS, and SchemaRowset enumerators are not yet available. An EWI (SSC-EWI-SSIS0004) is generated for these cases.
Event Handlers¶
Event handlers are converted to stored procedures. Supported scoped OnPreExecute and OnPostExecute handlers can be CALL-wired from the converted orchestration. Package-level handlers and OnError or OnWarning procedures can remain untriggered.
Conversion behavior¶
| Source | Snowflake | Notes |
|---|---|---|
| Scoped OnPreExecute / OnPostExecute | Stored procedure + CALL | Wired around the converted task or container |
| OnError / OnWarning | Stored procedure | Can remain untriggered |
| Package-level handlers | Stored procedure | Can remain untriggered |
Example¶
Limitations¶
- OnError, OnWarning, and package-level handler procedures can remain untriggered and require manual invocation or a triggering mechanism. See SSC-FDM-SSIS0006.
Execute SQL Task¶
Execute SQL Tasks are converted as inline SQL statements or separate stored procedures, depending on complexity and result set bindings.
Conversion approach:
- Simple SQL statements: Converted inline within the parent TASK
- Complex statements with result sets: May be converted to separate stored procedures
- Result bindings: Handled where possible; unsupported patterns generate EWI SSC-EWI-SSIS0011
Execute Package Task¶
Execute Package Tasks are handled differently based on package type:
| Package Type | Conversion | Notes |
|---|---|---|
| Local (single reference) | Inline execution within parent TASK | Package logic expanded inline |
| Reusable (2+ references or parameters) | CALL to stored procedure | Enables synchronous execution with parameters; generates FDM SSC-FDM-SSIS0005 |
| External | CALL with path resolution | Generates EWI SSC-EWI-SSIS0008 for manual verification |
Asynchronous execution note:
TASK-based Execute Package conversions run asynchronously. For synchronous behavior, packages are converted to stored procedures. See EWI SSC-EWI-SSIS0005.
File System Task¶
File System Tasks convert to Snowflake stage operations (COPY FILES and REMOVE). They do not become dbt models.
When the task acts on a file that a Flat File Source already binds, the generated statements use the same @public.landing_stage/ssis/<package>/ prefixes that the load reads, so the archive follows the loaded file rather than an unrelated path. See Ingestion.
Conversion behavior¶
| Source operation | Snowflake | Notes |
|---|---|---|
| Copy | COPY FILES INTO ... FROM ... | Destination is treated as a directory prefix |
| Move | COPY FILES then REMOVE | Removes the source after copy |
| Delete directory content | REMOVE then a .keep COPY INTO | Prefix-based stage paths |
Example¶
Limitations¶
- Destination paths are directory prefixes (SSC-EWI-SSIS0044).
- Snowflake stages use prefix-based paths rather than real directories, so
REMOVEwith a trailing slash deletes every file matching the prefix (SSC-FDM-SSIS0028). - Variable values must contain a valid Snowflake stage path (SSC-FDM-SSIS0025).
Expression Task¶
Expression Tasks convert SSIS expressions to Snowflake Scripting assignments (:=). They do not become dbt models.
Conversion behavior¶
| Source | Snowflake | Notes |
|---|---|---|
| Expression Task | variable := <converted expression> | Functions such as UPPER are rewritten to Snowflake |
Example¶
Send Mail Task¶
Send Mail Tasks are converted to Snowflake Tasks that use SYSTEM$SEND_EMAIL with a dynamically created Notification Integration.
Conversion behavior¶
| Aspect | SSIS | Snowflake |
|---|---|---|
| Email Service | Custom SMTP server | Snowflake’s built-in email service |
| Configuration | SMTP Connection Manager | Notification Integration |
| Sender Address | Custom FROM address | Fixed by Snowflake account |
| CC/BCC Support | Full support | Not supported (merged into recipients) |
| Attachments | File attachments supported | Not supported |
| HTML Body | Supported | Plain text only |
| Priority | High/Normal/Low | Not supported |
Property mapping¶
| SSIS Property | Snowflake Equivalent | Notes |
|---|---|---|
| ToLine | ALLOWED_RECIPIENTS + recipients parameter | Direct mapping |
| FromLine | Prepended to message body | FDM SSC-FDM-SSIS0008 |
| CCLine | Added to recipients list | FDM SSC-FDM-SSIS0009 |
| BCCLine | Added to recipients list | FDM SSC-FDM-SSIS0010 (privacy concern) |
| Subject | subject parameter | Direct mapping |
| MessageSource | message parameter | Direct mapping |
| MessageSourceType (DirectInput) | Supported | - |
| MessageSourceType (Variable) | Supported | Variable reference converted |
| MessageSourceType (FileConnection) | Not supported | EWI SSC-EWI-SSIS0017 |
| Priority | Not supported | EWI SSC-EWI-SSIS0016 |
| FileAttachments | Not supported | EWI SSC-EWI-SSIS0015 |
| SMTPConnection | Managed by Snowflake | FDM SSC-FDM-SSIS0007 |
| BodyFormat (HTML) | Not supported | EWI SSC-EWI-SSIS0018 |
Example¶
Each Send Mail Task is converted to a Snowflake Task containing:
- Notification Integration Creation: Created dynamically via
EXECUTE IMMEDIATE - SYSTEM$SEND_EMAIL Call: Sends the email through the integration
Basic Email (To, Subject, Body):
Email with FROM Address:
Email with Multiple Features (attachments, priority, CC):
Prerequisites for Snowflake Email¶
Before using converted Send Mail Tasks:
- Email Notification Integration permissions: Account admin must grant
CREATE INTEGRATION ON ACCOUNTto the executing role - Recipient verification: All email addresses in
ALLOWED_RECIPIENTSmust be verified in Snowflake - Update warehouse name: Replace
DUMMY_WAREHOUSEwith your actual warehouse name
Limitations¶
File Attachments:
Upload files to a Snowflake stage and share links instead:
BCC Privacy:
Send separate emails to maintain recipient privacy:
Bulk Insert Task¶
Bulk Insert Tasks are converted to Snowflake Tasks that use COPY INTO with an inline FILE_FORMAT. The conversion generates a stage placeholder that you must configure before execution.
Conversion behavior¶
| Aspect | SSIS | Snowflake |
|---|---|---|
| Data Source | File system path or UNC path | Snowflake Stage (internal or external) |
| File Format | Format file (.fmt/.xml) or inline options | FILE_FORMAT object or inline options |
| Native Format | Native/WideNative supported | Not supported (CSV, JSON, Parquet, etc.) |
| Row Filtering | FirstRow/LastRow options | Not directly supported |
| Batch Control | BatchSize configurable | Automatic management |
| Error Handling | MaximumErrors count | ON_ERROR behavior |
| Triggers | FireTriggers option | Not supported (use Streams/Tasks) |
| Table Locking | TableLock option | Not needed (MVCC) |
Property mapping¶
| SSIS Property | Snowflake Equivalent | Notes |
|---|---|---|
| DestinationTableName | COPY INTO table | Square brackets [] removed |
| DataFileType (Char) | TYPE = 'CSV' | Direct mapping |
| DataFileType (Native) | Not supported | EWI SSC-EWI-SSIS0020 |
| FieldTerminator | FIELD_DELIMITER | Parsed from SSIS format |
| RowTerminator | RECORD_DELIMITER | Parsed from SSIS format |
| FirstRow | SKIP_HEADER | Value - 1 |
| LastRow | Not supported | EWI SSC-EWI-SSIS0021 |
| MaximumErrors | ON_ERROR | FDM SSC-FDM-SSIS0011 |
| KeepNulls=True | NULL_IF = () | Empty tuple |
| KeepNulls=False | NULL_IF = ('', 'NULL', 'null') | Default behavior |
| KeepIdentity=False | FDM generated | FDM SSC-FDM-SSIS0017 |
| TableLock=True | Not needed | FDM SSC-FDM-SSIS0014 |
| FireTriggers=True | Not supported | EWI SSC-EWI-SSIS0022 |
| FormatFile | Not supported | EWI SSC-EWI-SSIS0023 |
| CheckConstraints=True | Always enforced | FDM SSC-FDM-SSIS0016 |
| BatchSize | Automatic | FDM SSC-FDM-SSIS0012 |
| SortedData | Not available | FDM SSC-FDM-SSIS0015 |
Terminator Parsing¶
SSIS uses specific tokens for field and row terminators. These are converted to Snowflake escape sequences:
| SSIS Format | Snowflake Output |
|---|---|
{CR}{LF} | \r\n |
{CR} | \r |
{LF} | \n |
{TAB} | \t |
Tab | \t |
Comma {,} | , |
Semicolon {;} | ; |
Vertical Bar {|} | | |
Example¶
Each Bulk Insert Task is converted to a Snowflake Task containing a COPY INTO statement with an inline FILE_FORMAT:
Basic Bulk Insert (CSV with default options):
Bulk Insert with Tab Delimiter and Header Skip:
Bulk Insert with Multiple EWIs (Native format, LastRow, FireTriggers):
Stage Setup (Required)¶
Before executing converted Bulk Insert Tasks, you must:
- Create a Snowflake stage:
- Upload files using SnowSQL CLI:
- Replace the stage placeholder in generated code:
- Verify files are staged:
Limitations¶
Native Data Format:
Export SQL Server data to CSV format before migration. The native binary format is not supported by Snowflake.
LastRow Filtering:
Load to staging table and filter:
FireTriggers (Trigger-like Behavior):
Use Snowflake Streams and Tasks:
dbt Project Execution¶
Within the orchestration code, Data Flow Tasks are executed using Snowflake’s EXECUTE DBT PROJECT command:
Important requirements:
- The
project_namemust match the name you used when deploying the dbt project (viaCREATE DBT PROJECTor Snowflake Workspace deployment) - Arguments passed are standard dbt CLI arguments (like
build,run,test) - Each execution runs the entire dbt project with all models in dependency order
Deployment:
Before executing dbt projects in orchestration, deploy them using:
- Snowflake CLI:
snow dbt deploy --schema schema_name --database database_name package_name - Snowflake Workspace: Upload and deploy via UI