When our team set out to rebuild our supplier data management and carbon rate calculation tool, we had two clear goals: maintain feature parity with our existing Power Apps solution while dramatically improving performance and debuggability. Our Power Apps implementation was functional but suffered from slow performance and debugging difficulties that slowed development and frustrated users. After evaluating options, we chose Streamlit with Snowflake as our backend, and the results exceeded our expectations.
This article shares the lessons I learned migrating a production application from Power Apps to Streamlit in Snowflake, focusing on practical insights that might help others considering a similar move.
The Context: Why We Migrated
Our application handles Excel files from multiple suppliers, each containing product data that we need to validate, process, and analyse for carbon footprint calculations. The workflow includes:
- Reading and parsing supplier Excel files
- Running comprehensive data quality checks
- Calculating carbon rates for each product
- Loading validated data into our data warehouse
- Visualising statistics on historical data
Why We Chose Streamlit
After evaluating options, Streamlit stood out for three reasons. First, the technical team already knew Python and the client were on Snowflake, so the learning curve would be manageable. Second, Streamlit is built specifically for data applications and featured in Snowflake, which aligned perfectly with our use case. Third, it would give us access to proper development tools, the kind software engineers take for granted but that were frustratingly absent in Power Apps.
While Power Apps served us initially, two critical issues drove the migration decision:
Performance: Processing times were becoming unacceptable as our data volume grew, creating bottlenecks in daily operations.
Debugging challenges: When issues arose, troubleshooting Power Apps was difficult and time-consuming. The lack of traditional debugging tools made it hard to identify root causes quickly.
The mandate was clear: rebuild with the same features, but make it faster and easier to debug and maintain.
Key Lessons Learned
Performance Gains Were Immediate and Dramatic
The most striking difference was speed. What took minutes in Power Apps now takes seconds in Streamlit. This wasn’t about optimisation or clever coding, Streamlit paired with Snowflake is simply fast out of the box.
Lesson: If performance is your primary pain point, Streamlit delivers without requiring extensive optimisation. Python’s mature data processing ecosystem (Pandas, NumPy) combined with Streamlit’s efficient rendering and Snowflake data processing makes it naturally suited for data-heavy applications.
Debugging Went from Painful to Pleasant
In Power Apps, debugging meant clicking through screens, checking formulas in various places, and often resorting to trial-and-error. With Streamlit and Python, I had access to proper debugging tools: breakpoints, print statements, stack traces, and logging.
Lesson: The ability to use standard development tools is invaluable. When something breaks, you can see exactly where and why. Stack traces, VS Code debugging, and even simple print statements make troubleshooting exponentially faster.
Example:
import logging
# Set up logging
logging.basicConfig(level=logging.DEBUG)
logger = logging.getLogger(__name__)
def calculate_carbon_rate(product_data):
logger.debug(f"Calculating carbon rate for: {product_data['product_id']}")
try:
rate = (product_data['emissions'] / product_data['weight']) * 100
logger.info(f"Carbon rate calculated: {rate}")
return rate
except KeyError as e:
logger.error(f"Missing required field: {e}")
raise
except ZeroDivisionError:
logger.error(f"Zero weight for product: {product_data['product_id']}")
return None
This level of visibility into what’s happening was nearly impossible in Power Apps.
Data Quality Checks Are Easier to Implement and Maintain
In Power Apps, implementing complex validation logic required working across multiple screens and formulas. In Streamlit with Python, data quality checks became straightforward functions.
Lesson: When your application is fundamentally about data validation and transformation, using a general-purpose programming language gives you flexibility that visual builders can’t match.
Pattern that worked well:
def run_data_quality_checks(df):
"""Run all validation checks and return results"""
checks = {
'missing_values': check_missing_values(df),
'data_types': validate_data_types(df),
'range_validation': check_value_ranges(df),
'business_rules': validate_business_rules(df)
}
return checks
# Display results with clear visual feedback
results = run_data_quality_checks(df)
for check_name, check_result in results.items():
if check_result['passed']:
st.success(f"✓ {check_name}")
else:
st.error(f"✗ {check_name}: {check_result['errors']}")
Snowflake Integration Was Seamless
Connecting to Snowflake from Streamlit was simple because it came with Snowflake 3 years ago. Loading validated data to tables became a few lines of code.
Lesson: Streamlit works beautifully with modern data stacks. If you’re already using Snowflake (or similar cloud data warehouses), the integration is natural and well-documented.
Session State Management Requires Thought
One area where Power Apps had an advantage was automatic state management. In Streamlit, you need to explicitly manage state using st.session_state .
Lesson: Plan your session state strategy early. Decide what needs to persist across reruns (uploaded files, user selections, calculation results) and what can be recomputed.
Useful pattern:
# Initialize session state
if 'processed_data' not in st.session_state:
st.session_state.processed_data = None
if 'quality_check_results' not in st.session_state:
st.session_state.quality_check_results = None
# Use it throughout your app
if st.button("Process File"):
st.session_state.processed_data = process_excel(uploaded_file)
st.session_state.quality_check_results = run_checks(st.session_state.processed_data)
Visualisation Capabilities Are Superior
While Power Apps has charting capabilities, Streamlit’s access to the entire Python visualisation ecosystem (Plotly, Matplotlib, Altair) gave us much more flexibility for our statistics dashboard.
Lesson: If data visualisation is important to your application, Streamlit’s integration with Python’s visualisation libraries provides professional-grade charts with minimal code.
Deployment and Version Control Are Developer-Friendly
With Power Apps, version control and deployment were managed through Microsoft’s platform. With Streamlit, we used Azure DevOps for code deployment so we gained:
Git-based version control (standard software development practices)
Easy rollbacks and feature branching
CI/CD integration possibilities
Lesson: Treating your application as code rather than a low-code configuration makes team collaboration and deployment much smoother for technical teams.
Caching Is Your Friend
Streamlit’s caching decorators ( @st.cache_data and @st.cache_resource ) were crucial for maintaining performance, especially for expensive operations like file parsing and database connections.
Lesson: Learn Streamlit’s caching mechanisms early. They’re powerful but require understanding when to cache and when not to.
Key caching pattern:
@st.cache_data
def load_and_parse_excel(file):
"""Cache expensive file parsing"""
return pd.read_excel(file)
@st.cache_data(ttl=3600) # Cache for 1 hour
def get_historical_statistics():
"""Cache database queries with TTL"""
return query_snowflake_for_stats()
Error Handling Needs to Be Explicit
Power Apps provided built-in error handling UI. In Streamlit, you need to handle exceptions and display user friendly messages yourself.
Lesson: Wrap operations in try-except blocks and use Streamlit’s message containers ( st.error , st.warning , st.info ) to communicate with users effectively.
Pattern:
try:
df = pd.read_excel(uploaded_file)
validate_excel_structure(df)
st.success("File loaded successfully!")
except Exception as e:
st.error(f"Error processing file: {str(e)}")
st.info("Please check that your file matches the required format.")
st.stop()
User Feedback Loops Are Important
Without Power Apps’ native notification systems, we had to be more intentional about user feedback (progress bars, status messages, confirmation dialogs).
Lesson: Use Streamlit’s feedback components liberally. Users need to know what’s happening, especially during long-running operations.
Useful components:
# Progress bars for long operations
progress_bar = st.progress(0)
for i, row in enumerate(df.iterrows()):
process_row(row)
progress_bar.progress((i + 1) / len(df))
# Status containers for multi-step processes
with st.status("Processing supplier data...", expanded=True) as status:
st.write("Loading file...")
df = load_file()
st.write("Running quality checks...")
results = run_checks(df)
st.write("Calculating carbon rates...")
df = calculate_rates(df)
status.update(label="Complete!", state="complete")
Architecture Overview
Our final architecture is straightforward:
- Frontend: Streamlit application
- Processing: Python (Pandas for data manipulation)
- Storage: Snowflake (validated data, historical records)
- Deployment: Azure DevOps
Data flow:
1. User uploads supplier Excel file
2. Application parses and validates data
3. Quality checks run on the dataset
4. Passing records have carbon rates calculated
5. Validated data loads to Snowflake
6. Dashboard displays statistics from historical data
What I’d Do Differently
Start with a clear data model: While Streamlit is flexible, I wish I’d spent more time upfront designing our data structure in Snowflake. We made several schema adjustments that required data migration.
Implement logging earlier: For production applications, proper logging is essential. We added comprehensive logging after encountering issues that were hard to debug without it.
Create reusable components sooner: After building several pages, I noticed patterns that could have been abstracted into reusable functions earlier, saving development time.
When Should You Choose Streamlit Over Power Apps?
Based on this experience, consider Streamlit if:
- Your team has Python developers or is comfortable learning Python
- Performance is critical (especially for data processing)
- You need complex data transformations or calculations
- You want standard version control and CI/CD practices
- Your use case involves heavy integration with data tools (Snowflake, databases, APIs)
- Power Apps might still be better if:
- Your team is non-technical and prefers visual builders
- You’re deeply embedded in the Microsoft ecosystem
- You need tight integration with Microsoft 365 tools
- Your application is workflow-heavy rather than data-heavy
Conclusion
Migrating from Power Apps to Streamlit transformed our application from a functional but sluggish tool into a fast, maintainable solution that our team actually enjoys using. The performance improvement alone justified the migration, but the gains in developer experience and maintainability were equally valuable.
For technical teams working with data-intensive applications, Streamlit offers a compelling alternative to low-code platforms. The learning curve is gentle if you know Python, and the results can be production-ready surprisingly quickly.
The best part? Our users immediately noticed the difference. When your application responds in seconds instead of minutes, it changes how people work with it.


