Skip to main content

Biml Basics for Data Engineers

Why Biml Matters for Pipeline Development

Building ETL pipelines manually is time-consuming and error-prone:

  • Creating 50 staging tables means writing 50 nearly-identical SSIS packages
  • A column rename requires updating multiple packages by hand
  • Inconsistent error handling across packages causes debugging headaches
  • Testing and deploying changes takes hours instead of minutes

Biml solves this by generating pipelines from metadata:

  • Define a pattern once, apply it to all tables automatically
  • Change metadata, regenerate all pipelines instantly
  • Enforce consistent patterns across your entire solution
  • Integrate with CI/CD for automated builds and deployments

Time savings example: A 100-table staging layer that takes 2-3 weeks to build manually can be generated in 1-2 hours with Biml.

Core Biml Concepts

Biml files are XML documents that conform to the Biml schema. If you know XML, you just need to learn a few conventions to start generating SSIS packages.

The Biml File Structure

Every Biml file starts with the root element and namespace declaration:

<Biml xmlns="http://schemas.varigence.com/biml.xsd">
<!-- Your Biml content goes here -->
</Biml>

Most Biml tools auto-generate this declaration, so you don't need to memorize it.

Collections Use Wrapper Elements

When adding objects to a Biml file, wrap them in a collection element. This pattern applies throughout Biml:

Collection ElementChild Elements
<Packages><Package>
<Connections><OleDbConnection>, <AdoNetConnection>
<Tables><Table>
<Tasks><Dataflow>, <ExecuteSQL>, <Container>

Example: Adding a package requires the <Packages> wrapper:

<Biml xmlns="http://schemas.varigence.com/biml.xsd">
<Packages>
<Package Name="MyPackage">
<Tasks>
<Dataflow Name="LoadData" />
</Tasks>
</Package>
</Packages>
</Biml>

Referencing Objects by Name

Biml uses name-based references to connect objects. Attribute names ending with Name indicate a reference:

  • ConnectionName="SourceDB" - references a connection named "SourceDB"
  • VariableName="User.Counter" - references a variable (with namespace prefix)
  • TableName="Sales.Customer" - references a table

Scoped names resolve ambiguity when multiple objects share a name. Like SQL Server's multi-part names (Server.Database.Schema.Table), Biml uses dot notation:

<!-- Reference a specific variable when duplicates exist -->
<ForEachFromVariableLoop Name="Loop1"
VariableName="MyPackage.User.LoopVariable">

The Biml compiler finds the closest matching object by default, so you only need scoped names when disambiguation is required.

Your First SSIS Package

Copy this code into a new .biml file in your Visual Studio project with BimlExpress installed:

<Biml xmlns="http://schemas.varigence.com/biml.xsd">
<Packages>
<Package Name="HelloBiml" ProtectionLevel="EncryptSensitiveWithUserKey">
<Tasks>
<ExecuteSQL Name="LogStart" ConnectionName="TargetDB">
<DirectInput>
PRINT 'Package started at ' + CONVERT(VARCHAR, GETDATE(), 120)
</DirectInput>
</ExecuteSQL>
</Tasks>
</Package>
</Packages>

<Connections>
<OleDbConnection Name="TargetDB"
ConnectionString="Provider=SQLNCLI11;Server=localhost;Initial Catalog=master;Integrated Security=SSPI;" />
</Connections>
</Biml>

To build:

  1. Right-click the .biml file in Solution Explorer
  2. Select Generate SSIS Packages
  3. The HelloBiml.dtsx package appears in your project

Generating Multiple Packages with BimlScript

The real power of Biml comes from BimlScript - embedded C# code that generates Biml dynamically. This example creates a package for each table in a list:

<#@ template language="C#" #>
<Biml xmlns="http://schemas.varigence.com/biml.xsd">
<Packages>
<#
// Define your source tables
var tables = new[] { "Customer", "Product", "Order", "OrderDetail" };

foreach (var tableName in tables) {
#>
<Package Name="Load_<#=tableName#>" ProtectionLevel="EncryptSensitiveWithUserKey">
<Tasks>
<Dataflow Name="DFT_<#=tableName#>">
<Transformations>
<OleDbSource Name="SRC_<#=tableName#>" ConnectionName="SourceDB">
<DirectInput>SELECT * FROM dbo.<#=tableName#></DirectInput>
</OleDbSource>
<OleDbDestination Name="DST_<#=tableName#>" ConnectionName="TargetDB">
<ExternalTableOutput Table="dbo.<#=tableName#>" />
</OleDbDestination>
</Transformations>
</Dataflow>
</Tasks>
</Package>
<# } #>
</Packages>

<Connections>
<OleDbConnection Name="SourceDB"
ConnectionString="Provider=SQLNCLI11;Server=SourceServer;Initial Catalog=SourceDB;Integrated Security=SSPI;" />
<OleDbConnection Name="TargetDB"
ConnectionString="Provider=SQLNCLI11;Server=TargetServer;Initial Catalog=TargetDB;Integrated Security=SSPI;" />
</Connections>
</Biml>

Result: One build generates four SSIS packages: Load_Customer.dtsx, Load_Product.dtsx, Load_Order.dtsx, and Load_OrderDetail.dtsx.

BimlScript Code Nugget Types

NuggetSyntaxPurpose
Control<# code #>Execute C# logic (loops, conditionals)
Text<#= expression #>Output a value into the Biml
Directive<#@ directive #>Configure template settings

Beyond SSIS: Cloud Platform Support

While this guide focuses on SSIS package generation using BimlExpress and BimlStudio, the Biml ecosystem extends to modern cloud data platforms through BimlFlex:

  • Azure Data Factory - JSON pipeline generation
  • Databricks - Notebooks and Delta Lake DDL
  • Snowflake - Stored procedures and tasks
  • Microsoft Fabric - Lakehouse pipelines

BimlFlex provides a metadata-driven approach with pre-built patterns for data vault, dimensional modeling, and staging layers across all these platforms. For cloud platform automation, see the BimlFlex documentation.

Practical Automation Benefits

Reducing Manual Coding

ApproachTime for 50-Table Staging Layer
Manual SSIS design100-150 hours (2-3 hours per package)
Biml automation~2 hours (template + generation)
Time saved98%

Improving Error Handling Consistency

Define error handling once in your Biml template:

<Package Name="Load_<#=tableName#>">
<Events>
<Event EventType="OnError" Name="OnError">
<Tasks>
<ExecuteSQL Name="LogError" ConnectionName="LogDB">
<DirectInput>
INSERT INTO ErrorLog (PackageName, ErrorTime, ErrorMessage)
VALUES ('<#=tableName#>', GETDATE(), ?)
</DirectInput>
</ExecuteSQL>
</Tasks>
</Event>
</Events>
<!-- Package tasks... -->
</Package>

Every generated package includes identical error handling - no forgotten logging calls or inconsistent patterns.

CI/CD Integration

Biml projects integrate with standard build pipelines:

# Azure DevOps example
- task: MSBuild@1
displayName: 'Build Biml Solution'
inputs:
solution: '**/*.mst'
msbuildArguments: '/p:OutputPath=$(Build.ArtifactStagingDirectory)/SSIS'

- task: PublishBuildArtifacts@1
inputs:
pathToPublish: '$(Build.ArtifactStagingDirectory)/SSIS'
artifactName: 'SSISPackages'

Benefits:

  • Version control your Biml templates (not generated packages)
  • Automated package generation on every commit
  • Consistent builds across development, test, and production

Key Conventions Summary

ConventionDescription
Collection wrappers<Packages> contains <Package>, <Tasks> contains task elements
Name referencesAttributes ending in Name reference other objects
Scoped namesUse dot notation for disambiguation: Package.Task.Variable
Required propertiesMost properties are optional; Name is almost always required

Next Steps

Now that you understand Biml basics, continue with these guides:

Learning Resources

  • IntelliSense: BimlExpress and BimlStudio provide autocomplete for all Biml elements
  • Import existing packages: Use BimlStudio to reverse-engineer SSIS packages into Biml
  • API Reference: Complete Biml language documentation at varigence.com/Documentation/Language/Index