Published on: October 10, 2025

13 min read

How we built a structured Streamlit Application Framework in Snowflake

Want to transform development from chaos to compliance? Learn how we implemented governance early on rather than retrofitting when maintenance costs climb exponentially.

Recently, the GitLab Data team transformed scattered Streamlit applications into a unified, secure, and scalable solution for our Snowflake environment. To accomplish this, we packed Python, Snowflake, and Streamlit together with GitLab. Follow along on this journey and discover the results we achieved, and learn how you can, too.

The challenge

Imagine this scenario: Your organization has dozens of Streamlit applications across different environments, running various Python versions, connecting to sensitive data with inconsistent security practices. Some apps work, others break mysteriously, and nobody knows who built what or how to maintain them.

This was exactly the challenge our data team faced. Applications were being created in isolation, with no standardization, no security oversight, and no clear deployment process. The result? A compliance nightmare and a maintenance burden that was growing exponentially.

Functional architectural design (high level)

Functional architectural design (high level)
Architecture of the framework (general overview)
Overview of roles and their functions
      ================================================================================
โœ… Snowflake CLI successfully installed and configured!
Connection: gitlab_streamlit
User: [email protected]
Account: gitlab
================================================================================
Using virtualenv: /Users/YOU/repos/streamlit/.venv
๐Ÿ“š Installing project dependencies...
Installing dependencies from lock file
No dependencies to install or update
โœ… Streamlit environment prepared!

    
  • Automated CI/CD pipelines: Handle testing, code review, and deployment from development to production.
  • Secure sandbox environments: Provide for safe development and testing before production deployment.
      โ•ฐโ”€$ make streamlit-rules
๐Ÿ” Running Streamlit compliance check...
================================================================================
CODE COMPLIANCE REPORT
================================================================================
Generated: 2025-07-09 14:01:16
Files checked: 1

SUMMARY:
โœ… Passed: 1
โŒ Failed: 0
Success Rate: 100.0%

APPLICATION COMPLIANCE SUMMARY:
๐Ÿ“ฑ Total Applications Checked: 1
โš ๏ธ Applications with Issues: 0
๐Ÿ“Š File Compliance Rate: 100.0%

DETAILED RESULTS BY APPLICATION:
...

    
  • Template-based application creation: Ensures consistency across all applications and pages.
      โ•ฐโ”€$ make streamlit-new-page STREAMLIT_APP=sales_dashboard STREAMLIT_PAGE_NAME=analytics
๐Ÿ“ Generating new Streamlit page: analytics for app: sales_dashboard
๐Ÿ“ƒ Create new page from template:
Page name: analytics
App directory: sales_dashboard
Template path: page_template.py
โœ… Successfully created 'analytics.py' in 'sales_dashboard' directory from template

    
  • Poetry-based dependency management: Prevents version conflicts and maintains clean environments.
  • Organized project structure: Has dedicated folders for applications, templates, compliance rules, and configuration management.
      โ”œโ”€โ”€ src/
โ”‚   โ”œโ”€โ”€ applications/     # Folder for Streamlit applications
โ”‚   โ”‚   โ”œโ”€โ”€ main_app/     # Main dashboard application
โ”‚   โ”‚   โ”œโ”€โ”€ components/   # Shared components
โ”‚   โ”‚   โ””โ”€โ”€ <your_apps>/  # Your custom application
โ”‚   โ”‚   โ””โ”€โ”€ <your_apps2>/ # Your 2nd custom application
โ”‚   โ”œโ”€โ”€ templates/        # Application and page templates
โ”‚   โ”œโ”€โ”€ compliance/       # Compliance rules and checks
โ”‚   โ””โ”€โ”€ setup/            # Setup and configuration utilities
โ”œโ”€โ”€ tests/                # Test files
โ”œโ”€โ”€ config.yml            # Environment configuration
โ”œโ”€โ”€ Makefile              # Build and deployment automation
โ””โ”€โ”€ README.md             # Main README.md file

    
  • Streamlined workflow: Takes local development through testing schema to production, all automated through GitLab CI/CD pipelines.

GitLab CI/CD pipelines for full automation of the process

GitLab CI/CD pipelines for full automation of the process
      class_rules:
  - name: "Inherit code for the page from GitLabDataStreamlitInit"
    description: "All Streamlit apps must inherit from GitLabDataStreamlitInit"
    severity: "error"
    required: true
    class_name: "*"
    required_base_classes:
      - "GitLabDataStreamlitInit"
    required_methods:
      - "__init__"
      - "set_page_layout"
      - "setup_ui"
      - "run"

function_rules:
  - name: "Main function required"
    description: "Must have a main() function"
    severity: "error"
    required: true
    function_name: "main"

import_rules:
  - name: "Import GitLabDataStreamlitInit"
    description: "Must import the mandatory base class"
    severity: "error"
    required: true
    module_name: "gitlab_data_streamlit_init"
    required_items:
      - "GitLabDataStreamlitInit"
  - name: "Import streamlit"
    description: "Must import streamlit library"
    severity: "error"
    required: true
    module_name: "streamlit"

file_rules:
  - name: "Snowflake configuration required (snowflake.yml)"
    description: "Each application must have a snowflake.yml configuration file"
    severity: "error"
    required: true
    file_pattern: "**/applications/**/snowflake.yml"
    base_path: ""
  - name: "Snowflake environment required (environment.yml)"
    description: "Each application must have a environment.yml configuration file"
    severity: "error"
    required: true
    file_pattern: "**/applications/**/environment.yml"
    base_path: ""
  - name: "Share specification required (share.yml)"
    description: "Each application must have a share.yml file"
    severity: "warning"
    required: true
    file_pattern: "**/applications/**/share.yml"
    base_path: ""
  - name: "README.md required (README.md)"
    description: "Each application should have a README.md file with a proper documentation"
    severity: "error"
    required: true
    file_pattern: "**/applications/**/README.md"
    base_path: ""
  - name: "Starting point recommended (dashboard.py)"
    description: "Each application must have a dashboard.py as a starting point"
    severity: "warning"
    required: true
    file_pattern: "**/applications/**/dashboard.py"
    base_path: ""

sql_rules:
  - name: "SQL files must contain only SELECT statements"
    description: "SQL files and SQL code in other files should only contain SELECT statements for data safety"
    severity: "error"
    required: true
    file_extensions: [".sql", ".py"]
    select_only: true
    forbidden_statements:
      - ....
    case_sensitive: false
  - name: "SQL queries should include proper SELECT statements"
    description: "When SQL is present, it should contain proper SELECT statements"
    severity: "warning"
    required: false
    file_extensions: [".sql", ".py"]
    required_statements:
      - "SELECT"
    case_sensitive: false

share_rules:
  - name: "Valid functional roles in share.yml"
    description: "Share.yml files must contain only valid functional roles from the approved list"
    severity: "error"
    required: true
    file_pattern: "**/applications/**/share.yml"
    valid_roles:
      - ...
    safe_data_roles:
      - ...
  - name: "Share.yml file format validation"
    description: "Share.yml files must follow the correct YAML format structure"
    severity: "error"
    required: true
    file_pattern: "**/applications/**/share.yml"
    required_keys:
      - "share"
    min_roles: 1
    max_roles: 10


    

With one command running:

      โ•ฐโ”€$ make streamlit-rules

    

We can verify all the rules we have created and validate that the developers (who are building a Streamlit application) are following the policy specified by the creators (who determine the policies and building blocks of the framework), and that all the building blocks are in the right place. This ensures consistent behavior across all Streamlit applications.

      ๐Ÿ” Running Streamlit compliance check...
================================================================================
CODE COMPLIANCE REPORT
================================================================================
Generated: 2025-08-18 17:05:12
Files checked: 4

SUMMARY:
โœ… Passed: 4
โŒ Failed: 0
Success Rate: 100.0%

APPLICATION COMPLIANCE SUMMARY:
๐Ÿ“ฑ Total Applications Checked: 1
โš ๏ธ Applications with Issues: 0
๐Ÿ“Š File Compliance Rate: 100.0%

DETAILED RESULTS BY APPLICATION:
================================================================================
โœ… PASS APPLICATION: main_app
------------------------------------------------------------
๐Ÿ“ FILES ANALYZED (4):
โœ… dashboard.py
๐Ÿ“ฆ Classes: SnowflakeConnectionTester
๐Ÿ”ง Functions: main
๐Ÿ“ฅ Imports: os, pwd, gitlab_data_streamlit_init, snowflake.snowpark.exceptions, streamlit

โœ… show_streamlit_apps.py
๐Ÿ“ฆ Classes: ShowStreamlitApps
๐Ÿ”ง Functions: main
๐Ÿ“ฅ Imports: pandas, gitlab_data_streamlit_init, snowflake_session, streamlit

โœ… available_packages.py
๐Ÿ“ฆ Classes: AvailablePackages
๐Ÿ”ง Functions: main
๐Ÿ“ฅ Imports: pandas, gitlab_data_streamlit_init, streamlit

โœ… share.yml
๐Ÿ‘ฅ Share Roles: snowflake_analyst_safe

๐Ÿ“„ FILE COMPLIANCE FOR MAIN_APP:
โœ… Required files found:
โœ“ snowflake.yml
โœ“ environment.yml
โœ“ share.yml
โœ“ README.md
โœ“ dashboard.py

RULES CHECKED:
----------------------------------------
Class Rules (1):
- Inherit code for the page from GitLabDataStreamlitInit (error)

Function Rules (1):
- Main function required (error)

Import Rules (2):
- Import GitLabDataStreamlitInit (error)
- Import streamlit (error)

File Rules (5):
- Snowflake configuration required (snowflake.yml) (error)
- Snowflake environment required (environment.yml) (error)
- Share specification required (share.yml) (warning)
- README.md required (README.md) (error)
- Starting point recommended (dashboard.py) (warning)

SQL Rules (2):
- SQL files must contain only SELECT statements (error)
๐Ÿ—„ SELECT-only mode enabled
๐Ÿšจ Forbidden: INSERT, UPDATE, DELETE, DROP, ALTER...
- SQL queries should include proper SELECT statements (warning)

Share Rules (2):
- Valid functional roles in share.yml (error)
๐Ÿ‘ฅ Valid roles: 15 roles defined
๐Ÿ”’ Safe data roles: 11 roles
- Share.yml file format validation (error)
------------------------------------------------------------
โœ… Compliance check passed
-----------------------------------------------------------

    

Developer experience that works

Whether you prefer your favorite IDE, a web-based development environment, or Snowflake Snowsight, the experience remains consistent. The framework provides:

  • Template-driven development: New applications and pages are created through standardized templates, ensuring consistency and best practices from day one. No more scattered design and elements.
      โ•ฐโ”€$ make streamlit-new-app NAME=sales_dashboard
๐Ÿ”ง Configuration Environment: TEST
๐Ÿ“ Configuration File: config.yml
๐Ÿ“œ Config Loader Script: ./setup/get_config.sh
๐Ÿ Python Version: 3.12
๐Ÿ“ Applications Directory: ./src/applications
๐Ÿ—„ Database: ...
๐Ÿ“Š Schema: ...
๐Ÿ— Stage: ...
๐Ÿญ Warehouse: ...
๐Ÿ†• Creating new Streamlit app: sales_dashboard
Initialized the new project in ./src/applications/sales_dashboard

    
  • Poetry package management: All dependencies are managed through Poetry, creating isolated environments that won't disrupt your existing Python setup.
      [tool.poetry]
name = "GitLab Data Streamlit"
version = "0.1.1"
description = "GitLab Data Team Streamlit project"
authors = ["GitLab Data Team <*****@gitlab.com>"]
readme = "README.md"

[tool.poetry.dependencies]
python = "<3.13,>=3.12"
snowflake-snowpark-python = "==1.32.0"
snowflake-connector-python = {extras = ["development", "pandas", "secure-local-storage"], version = "^3.15.0"}
streamlit = "==1.22.0"
watchdog = "^6.0.0"
types-toml = "^0.10.8.20240310"
pytest = "==7.0.0"
black = "==25.1.0"
importlib-metadata = "==4.13.0"
pyyaml = "==6.0.2"
python-qualiter = "*"
ruff = "^0.1.0"
types-pyyaml = "^6.0.12.20250516"
jinja2 = "==3.1.6"

[build-system]
requires = ["poetry-core"]
build-backend = "poetry.core.masonry.api"

    
  • Multi-page application support: Creators can easily build complex applications with multiple pages and add new libraries as needed. Multi-page applications are part of the framework and a developer is focusing on the logic, not the design and structuring.

Multipage application example (in Snowflake)

Multipage application example (in Snowflake)
      make streamlit-push-test APPLICATION_NAME=sales_dashboard
๐Ÿ“ค Deploying Streamlit app to test environment: sales_dashboard
...
------------------------------------------------------------------------------------------------------------
๐Ÿ”— Running share command for application: sales_dashboard
Running commands to grant shares
๐Ÿš€ Executing: snow streamlit share sales_dashboard with SOME_NICE_ROLE
โœ… Command executed successfully
๐Ÿ“Š Execution Summary: 1/1 commands succeeded

    
  • Comprehensive Makefile: All common commands are wrapped in simple Makefile commands, from local development to testing and deployment, including CI/CD pipelines.
  • Safe local development: Everything runs in isolated Poetry environments, protecting your system while providing production-like experiences.

Same experience despite the environment (example of the local development)

Same experience despite the environment (example of the local development)

Deploy the application in Snowflake

The application deployed in Snowflake

The bigger picture

This framework represents more than just a technical solution โ€” it's a paradigm shift toward treating data applications as first-class citizens in your enterprise (data) architecture. By providing structure without sacrificing flexibility, the GitLab Data team created an environment where anyone in the company with minimal technical knowledge can innovate rapidly while maintaining the highest standards of security and compliance.

What's next?

We're continuing to enhance the framework based on user feedback and emerging needs. Future improvements include expanded template libraries, enhanced monitoring capabilities, more flexibility, and a smoother user experience. The goal isn't just to solve today's problems, but to create a foundation that scales with your organization's growing data application needs.

Summary

The GitLab Data Team transformed dozens of scattered, insecure Streamlit applications with no standardization into a unified, enterprise-grade framework that separates roles cleanly:

  1. Maintainers handle infrastructure and security.
  2. Creators focus on building applications without deployment headaches.
  3. Viewers access polished, compliant apps.

And we used these building blocks:

  1. Automated CI/CD pipelines
  2. Fully collaborative and versioned code in git
  3. Template-based development
  4. Built-in security compliance, testing
  5. Poetry-managed environments We eliminated the maintenance nightmare while enabling rapid innovation โ€” proving that you can have both structure and flexibility when you treat data applications as first-class enterprise assets rather than throwaway prototypes.

We want to hear from you

Enjoyed reading this blog post or have questions or feedback? Share your thoughts by creating a new topic in the GitLab community forum.

Share your feedback

50%+ of the Fortune 100 trust GitLab

Start shipping better software faster

See what your team can do with the intelligent

DevSecOps platform.