<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Anvil</title>
    <description>The latest articles on DEV Community by Anvil (@anvil).</description>
    <link>https://dev.to/anvil</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Forganization%2Fprofile_image%2F3302%2F28b847cf-a316-45a5-9560-48568acdf2cb.png</url>
      <title>DEV Community: Anvil</title>
      <link>https://dev.to/anvil</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/anvil"/>
    <language>en</language>
    <item>
      <title>Build a Web App with MongoDB Using Just Python</title>
      <dc:creator>Love Otudor</dc:creator>
      <pubDate>Tue, 13 Jan 2026 16:37:03 +0000</pubDate>
      <link>https://dev.to/anvil/build-a-web-app-with-mongodb-using-just-python-321a</link>
      <guid>https://dev.to/anvil/build-a-web-app-with-mongodb-using-just-python-321a</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Build and deploy a full-stack web app that interacts with your external database using only Python. No HTML, CSS, or JavaScript required.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/OX5L_8hH7xM"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;In this tutorial, we guide you step-by-step on how to create a &lt;strong&gt;Customer Relationship Management (CRM) system&lt;/strong&gt; connected to a &lt;strong&gt;MongoDB Atlas cluster&lt;/strong&gt;, starting completely from scratch. You'll see how to build both the frontend and backend in Python using Anvil and deploy it to the web with &lt;strong&gt;two clicks&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://anvil.works/build#clone:UJ3PW3CWLBQVGO6Q%3d3WYYRMWKPSTUZJV2NSW7ACBK?utm_source=crosspost:dev.to:/blog/crm-with-mongodb"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpkvbvqp0y0tdl5jyjcic.png" alt="Open in Anvil" width="461" height="140"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://anvil.works/?utm_source=crosspost:dev.to:/blog/crm-with-mongodb"&gt;&lt;strong&gt;Anvil&lt;/strong&gt;&lt;/a&gt; lets you build full-stack web apps with all the power of Python and the flexibility of code.&lt;/p&gt;

&lt;p&gt;In this tutorial, we will cover:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Installing Python packages in your Server Module&lt;/li&gt;
&lt;li&gt;Securing passwords with App Secrets&lt;/li&gt;
&lt;li&gt;Communicating between Forms with custom events&lt;/li&gt;
&lt;li&gt;Authentication with the Users Service&lt;/li&gt;
&lt;li&gt;Deploying your app on Anvil's free hosting&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  More about Anvil
&lt;/h2&gt;

&lt;p&gt;If you're new here, welcome! &lt;a href="https://anvil.works/?utm_source=crosspost:dev.to:/blog/crm-with-mongodb"&gt;Anvil&lt;/a&gt; is a platform for building full-stack web apps with nothing but Python. No need to wrestle with JS, HTML, CSS, Python, SQL and all their frameworks – just &lt;strong&gt;build it all in Python&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://anvil.works/build?utm_source=crosspost:dev.to:/blog/crm-with-mongodb"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fz95af95e963brxl2o9zt.png" alt="Sign up for Anvil" width="800" height="191"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>python</category>
      <category>anvil</category>
      <category>webdev</category>
      <category>mongodb</category>
    </item>
    <item>
      <title>Showcasing three recent improvements to Anvil</title>
      <dc:creator>Tony</dc:creator>
      <pubDate>Tue, 11 Nov 2025 11:26:11 +0000</pubDate>
      <link>https://dev.to/anvil/showcasing-three-recent-improvements-to-anvil-25e8</link>
      <guid>https://dev.to/anvil/showcasing-three-recent-improvements-to-anvil-25e8</guid>
      <description>&lt;h2&gt;
  
  
  We've made changes to improve your developer experience
&lt;/h2&gt;

&lt;p&gt;Anvil is always evolving to give its users full power to make any web app they wish. In this article, we'll go over three recent features that we made specifically to give more control and options when building web apps with Anvil.&lt;/p&gt;

&lt;p&gt;Here's what our latest efforts empower you to do, with nothing but Python:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Use industry-standard design language, with the &lt;strong&gt;Material 3 theme&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Use smart and secure databases, with &lt;strong&gt;Model Classes&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Build easily navigable multi-page apps, with Anvil's &lt;strong&gt;routing dependency&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you want to see all these features in action, take a look at &lt;a href="http://anvil.works/learn/examples/hr-workflow?utm_source=devto_feature_roundup" rel="noopener noreferrer"&gt;this example app&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Apply industry-standard design language
&lt;/h2&gt;

&lt;p&gt;How your app looks is, understandably, a huge priority when it comes to building an Anvil app. So, we've given you more tools to get your app to look exactly how you want it to.&lt;/p&gt;

&lt;p&gt;First off, our new &lt;strong&gt;Material 3 Theme&lt;/strong&gt; is here with plenty of shiny and sleek components for you to use.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgjpsyzhw3t5fe86zbazb.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgjpsyzhw3t5fe86zbazb.png" alt="The updated homepage of the HR Workflow App. Its sleek new look uses the new Material 3 Theme." width="800" height="552"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The Anvil Material 3 Theme is available for both &lt;a href="https://anvil.works/docs/ui/app-themes/material-3#how-to-use-the-material-3-theme?utm_source=devto_feature_roundup" rel="noopener noreferrer"&gt;new apps and existing apps&lt;/a&gt;. It is &lt;a href="http://anvil.works/docs/ui/app-themes/material-3?utm_source=devto_feature_roundup" rel="noopener noreferrer"&gt;exhaustively documented&lt;/a&gt; and updated regularly.&lt;/p&gt;

&lt;p&gt;Secondly, we've changed our approach to themes and enhanced the ability for you to &lt;strong&gt;create your own themes and components&lt;/strong&gt;. &lt;a href="https://anvil.works/docs/deployment/dependencies?utm_source=devto_feature_roundup" rel="noopener noreferrer"&gt;Apps used as dependencies can now share their custom components&lt;/a&gt;. You can make an entire app filled with components styled exactly how you see fit, and then use this app as a dependency. This lets you build a library of components, themes and layouts that you can then use in any other app. In fact, that's exactly how we built the Material 3 Theme!&lt;/p&gt;

&lt;h2&gt;
  
  
  Ensure secure and powerful database interactions
&lt;/h2&gt;

&lt;p&gt;Dealing with data can be difficult -- you need your data to be flexible, modifiable and accessible, yet secure. This is where &lt;strong&gt;Model Classes&lt;/strong&gt; come in. Model Classes let you handle all validation, observation and transformation in one single Python script, letting you enjoy all the benefits of a secure database without compromising on flexibility.&lt;/p&gt;

&lt;p&gt;Here are a few things Model Classes enable you to do:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Have your user rows automatically calculate the age of the user they represent, using their registered date of birth.
&lt;/li&gt;
&lt;li&gt;Ensure the execution of specific code whenever a new row is created or updated.
&lt;/li&gt;
&lt;li&gt;Check for permission when a user attempts to modify a row.
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For example, let's say that we have an app where users can create accounts, and we want to notify the app owner whenever a new user is created.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;from anvil.tables import app_tables
import anvil.email

class User(app_tables.users.row):
    # We inherit from the Row class from our users table.
    # Through Model Classes, this allows us to add logic to our row objects.

    def _do_create():
        # This method is run every time a new row object is created.
        anvil.email.send(
            to="owner@email.com",
            subject="New User Registered",
            text = """Hello Owner!
            A new user has registered to your app.
            """
        )
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With just this simple script, we have added logic to our data table, and now, you can too!&lt;/p&gt;

&lt;p&gt;All this and much more is dutifully explained in &lt;a href="https://anvil.works/docs/data-tables/model-classes?utm_source=devto_feature_roundup" rel="noopener noreferrer"&gt;Model Classes' documentation&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Provide clear navigation
&lt;/h2&gt;

&lt;p&gt;We've built a new way to use routing for page navigation within Anvil. Our new &lt;a href="https://routing-docs.anvil.works/" rel="noopener noreferrer"&gt;routing dependency&lt;/a&gt; makes the set-up process very easy, letting you set up and configure URL routes via a script, as you would any other element of your app.&lt;/p&gt;

&lt;p&gt;Routing empowers you to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Let your users &lt;strong&gt;use browser bookmarks&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Redirect your users&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;Enable &lt;strong&gt;navigation to specific app states from an external link&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fuxcv56rxbxmcldwse59a.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fuxcv56rxbxmcldwse59a.gif" alt="Navigation through the HR Workflow App, handled through the Anvil routing dependency." width="600" height="429"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Using routing for navigation offers a very native experience for your users, and the routing dependency lets you implement it the same way you would any other component. Our &lt;a href="(https://anvil.works/docs/client/navigation/routing?utm_source=devto_feature_roundup)"&gt;routing documentation&lt;/a&gt; is a great starting-off point, and the &lt;a href="https://routing-docs.anvil.works/" rel="noopener noreferrer"&gt;dependency's standalone documentation&lt;/a&gt; has all the technical details you could possibly ask for.&lt;/p&gt;

&lt;h2&gt;
  
  
  Dive in!
&lt;/h2&gt;

&lt;p&gt;We hope that these additional tools empower our users to build exactly what they have in mind, with all the features they desire. All you need to get started is &lt;a href="https://anvil.works/sign-up?utm_source=devto_feature_roundup" rel="noopener noreferrer"&gt;sign up&lt;/a&gt;, and get coding. It's that easy.&lt;/p&gt;

&lt;p&gt;If you're looking for an example, &lt;a href="http://anvil.works/learn/examples/hr-workflow?utm_source=devto_feature_roundup" rel="noopener noreferrer"&gt;this example app&lt;/a&gt; showcases all the features described here, with explanatory comments throughout the code.&lt;/p&gt;

&lt;p&gt;We also have a bunch of &lt;a href="https://anvil.works/learn/tutorials?utm_source=devto_feature_roundup" rel="noopener noreferrer"&gt;tutorials&lt;/a&gt; to help if you're ever lost, and the &lt;a href="https://anvil.works/forum?utm_source=devto_feature_roundup" rel="noopener noreferrer"&gt;Anvil community forum&lt;/a&gt; is filled to the brim with brilliant and helpful people, so you're never alone.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>python</category>
      <category>programming</category>
    </item>
    <item>
      <title>AnkiBuddy: Automating Flashcard Creation for Medical Students</title>
      <dc:creator>Ryan</dc:creator>
      <pubDate>Mon, 18 Aug 2025 15:03:39 +0000</pubDate>
      <link>https://dev.to/anvil/ankibuddy-automating-flashcard-creation-for-medical-students-1n</link>
      <guid>https://dev.to/anvil/ankibuddy-automating-flashcard-creation-for-medical-students-1n</guid>
      <description>&lt;h2&gt;
  
  
  Executive Summary
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://www.ankibuddy.com/" rel="noopener noreferrer"&gt;AnkiBuddy&lt;/a&gt; transforms the way medical students create study materials by using AI to generate high-quality &lt;a href="https://apps.ankiweb.net/" rel="noopener noreferrer"&gt;Anki&lt;/a&gt; flashcards from PDF documents in minutes - eliminating hours of manual card creation. Built by Dr. David Topf and using &lt;a href="https://anvil.works?utm_source=devto_ankibuddy_case_study" rel="noopener noreferrer"&gt;Anvil&lt;/a&gt;, AnkiBuddy went from initial idea to working prototype in just 2 months, with Anvil enabling rapid iteration and continuous improvement ever since.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Built by a solo developer&lt;/li&gt;
&lt;li&gt;Prototype ready in 2 months&lt;/li&gt;
&lt;li&gt;Users: 18,000+&lt;/li&gt;
&lt;li&gt;Customer lifetime value: €70
&lt;/li&gt;
&lt;li&gt;MoM user growth: 32%&lt;/li&gt;
&lt;li&gt;50,000+ PDFs parsed&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;Anvil has allowed me to do this as a solo entrepreneur. Any other solo entrepreneur that builds a software product needs to basically be a full stack developer who's also had experience with DevOps and has the skills to build a business.&lt;br&gt;
Dr. David Topf&lt;br&gt;
Founder and CEO, AnkiBuddy&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  The Challenge: When Manual Study Card Creation Meets Medical School
&lt;/h2&gt;

&lt;p&gt;Every medical student knows the struggle: You have tonnes of PDF study materials, and you know that spaced repetition with flashcards is one of the most effective ways to learn. But creating quality flashcards manually is incredibly time-consuming. Turning a single PDF into comprehensive Anki cards can take hours.&lt;/p&gt;

&lt;p&gt;David's sister Danielle, a medical student, experienced this firsthand. She asked David how she could use AI to transform her medical study summaries into flashcards. As David recalls, "When she showed me how long it takes her to manually generate Anki cards, I wanted to try to help".&lt;/p&gt;

&lt;h3&gt;
  
  
  What If We Let AI Do the Heavy Lifting?
&lt;/h3&gt;

&lt;p&gt;David saw an opportunity - what if AI could handle the tedious process of reading through study materials and creating well-structured flashcards? This wasn't just about automation, it was about creating scientifically-sound study materials that would actually improve learning outcomes.&lt;/p&gt;

&lt;p&gt;The idea became AnkiBuddy: an AI-powered platform that transforms PDF study materials into customizable, high-quality Anki flashcards optimized for medical education.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Solution: AI-Powered Flashcard Generation
&lt;/h2&gt;

&lt;p&gt;AnkiBuddy is a web-based platform that lets medical students upload their study materials and receive well-structured Anki flashcards within minutes. The platform:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Analyzes PDF content using AI&lt;/li&gt;
&lt;li&gt;Generates professionally-structured flashcards&lt;/li&gt;
&lt;li&gt;Allows easy customization and personalization of cards&lt;/li&gt;
&lt;li&gt;Integrates with existing Anki workflows&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdti0asvse6dhucmf65hr.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdti0asvse6dhucmf65hr.png" width="800" height="407"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;No more spending hours manually creating cards. No more inconsistent formats. Just high-quality study materials, ready when you need them.&lt;/p&gt;

&lt;h2&gt;
  
  
  Building AnkiBuddy: Rapid Development with Anvil
&lt;/h2&gt;

&lt;p&gt;David had already worked hard building an AI-powered PDF parser using Python - the next challenge was building a UI and getting it all deployed online. That's where Anvil came in.&lt;/p&gt;

&lt;p&gt;He'd already learned Python for the AI part of the app, so he reached for Anvil to simplify the web development process and handle his DevOps and hosting. Within two months of working with Anvil, David had a working prototype of AnkiBuddy which he could give to users.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;It basically simplified it to a place where, if I learn Python and I learn the rules of Anvil, I can do pretty much what I want.&lt;br&gt;
Dr. David Topf&lt;br&gt;
Founder and CEO, AnkiBuddy&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;More than just accelerating development, Anvil allowed David to offload database management, DevOps, and hosting. It saved him the headaches of navigating complex cloud platforms like AWS - letting him focus entirely on building his product and business.&lt;/p&gt;

&lt;p&gt;He also took advantage of the support package offered by Anvil to help maximise his development speed and get answers to questions fast.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;I completely underestimated how valuable the support plan would be. I’ve been able to work directly with the Anvil development team. They’re not just responsive; they’re some of the most skilled engineers I’ve ever encountered.&lt;br&gt;
Dr. David Topf&lt;br&gt;
Founder and CEO, AnkiBuddy&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  The Results: From Idea to Impact
&lt;/h2&gt;

&lt;p&gt;Since its launch, AnkiBuddy has helped 18,000 medical students transform their study workflows. It has proven that there's real demand for AI-powered study tools that are tuned to specific needs.&lt;/p&gt;

&lt;p&gt;Anvil has enabled fast iteration ever since the prototype was launched. When users reported bugs or suggested improvements, David could implement changes in no time.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fomq1fxugqge88psml4vn.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fomq1fxugqge88psml4vn.png" width="800" height="394"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;AnkiBuddy is a perfect example of how modern AI can solve real educational challenges and how the right development platform can help solo entrepreneurs move from idea to impact in record time.&lt;/p&gt;

&lt;h2&gt;
  
  
  More Information
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;AnkiBuddy&lt;/strong&gt; creates high-quality Anki flashcards from your PDF study materials in minutes.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.ankibuddy.com/" rel="noopener noreferrer"&gt;Visit ankibuddy.com&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you’re new to &lt;strong&gt;Anvil&lt;/strong&gt; and want to see how you can build powerful web apps using just Python—up to 7× faster than traditional development:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://anvil.works?utm_source=devto_ankibuddy_case_study" rel="noopener noreferrer"&gt;Learn more about Anvil&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Have questions or want to get in touch? Visit &lt;a href="https://anvil.works/contact?utm_source=devto_ankibuddy_case_study" rel="noopener noreferrer"&gt;anvil.works/contact&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>startup</category>
    </item>
    <item>
      <title>The Best Python Web App Frameworks in 2025</title>
      <dc:creator>Brooke Myers</dc:creator>
      <pubDate>Tue, 22 Jul 2025 13:48:46 +0000</pubDate>
      <link>https://dev.to/anvil/the-best-python-web-app-frameworks-in-2025-48dk</link>
      <guid>https://dev.to/anvil/the-best-python-web-app-frameworks-in-2025-48dk</guid>
      <description>&lt;h1&gt;
  
  
  The Top 5 Python GUI Builders
&lt;/h1&gt;

&lt;p&gt;Python is a popular language amongst beginners, academics and data scientists, and its popularity is steadily growing. In 2024, Python became the &lt;a href="https://github.blog/news-insights/octoverse/octoverse-2024/" rel="noopener noreferrer"&gt;most used language on GitHub&lt;/a&gt;, surpassing JavaScript for the first time. With the number of Python developers steadily increasing, there is more demand than ever to be able to build graphical user interfaces (GUIs) with Python.&lt;/p&gt;

&lt;p&gt;While Python has long been used as a backend language for web development, more and more developers are looking to use it on the frontend too. There are now several frameworks for building full-stack web applications entirely in Python, each with their own approach to solving the issue. Let's take a look at a few of them.&lt;/p&gt;

&lt;p&gt;In this article, we'll compare and contrast five tools for building GUIs in Python:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Streamlit&lt;/li&gt;
&lt;li&gt;Shiny for Python&lt;/li&gt;
&lt;li&gt;NiceGUI&lt;/li&gt;
&lt;li&gt;Reflex&lt;/li&gt;
&lt;li&gt;Anvil&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  TL;DR
&lt;/h2&gt;

&lt;p&gt;Don't have the time? Skip the in-depth comparison and go straight to the summary.&lt;/p&gt;

&lt;h2&gt;
  
  
  Streamlit
&lt;/h2&gt;

&lt;p&gt;&lt;a href="//streamlit.io"&gt;Streamlit&lt;/a&gt; is a popular open-source Python library for building data-driven apps. Streamlit's approach to building web applications is simple and pythonic, which makes it easy to adapt existing Python scripts into Streamlit apps.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1ic6rwqo2fjl0qvkc6tt.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1ic6rwqo2fjl0qvkc6tt.png" alt="Screenshot of a Streamlit app showing data on NYC Uber pickups" width="800" height="518"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Although the Streamlit benefits from being straightforward and user friendly, its simplicity is also its biggest weakness. Any time a user interacts with a Streamlit app, &lt;a href="https://docs.streamlit.io/get-started/fundamentals/main-concepts#data-flow" rel="noopener noreferrer"&gt;the script reruns from top to bottom&lt;/a&gt;. This causes two issues: apps can be slow and state management is tricky. It's also not easy to customize Streamlit apps, which results in most Streamlit apps all looking alike.&lt;/p&gt;

&lt;p&gt;Overall, Streamlit is great for prototyping or building small data-based apps, but it's not the best solution when your app requires more complexity or customization.&lt;/p&gt;

&lt;h3&gt;
  
  
  Pros
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Easy to turn an existing script into an app&lt;/li&gt;
&lt;li&gt;Great for building dashboards&lt;/li&gt;
&lt;li&gt;Intuitive and straightforward to understand&lt;/li&gt;
&lt;li&gt;Large and active developer community&lt;/li&gt;
&lt;li&gt;Completely free and open-source&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Cons
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Apps can be slow&lt;/li&gt;
&lt;li&gt;Not good for bigger, more complex apps&lt;/li&gt;
&lt;li&gt;Hard to customize&lt;/li&gt;
&lt;li&gt;Minimal features&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Shiny for Python
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://shiny.posit.co/py/" rel="noopener noreferrer"&gt;Shiny for Python&lt;/a&gt; is a relatively new library for building interactive web applications in Python. Originally a popular tool for the language R, Shiny has now branched out into Python. Shiny's approach is very &lt;a href="https://shiny.posit.co/py/docs/comp-streamlit.html" rel="noopener noreferrer"&gt;similar to Streamlit's&lt;/a&gt;, but it aims to correct two of Streamlit's biggest flaws: the need to rerun the entire script and the lack of customizability.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fd9n6fzwp8tlgcywn2um9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fd9n6fzwp8tlgcywn2um9.png" alt="A screenshot of a Shiny dashboard" width="800" height="437"&gt;&lt;/a&gt;&lt;/p&gt;
An example Shiny dashboard: &lt;a href="https://gallery.shinyapps.io/template-dashboard-tips1/" rel="noopener noreferrer"&gt;https://gallery.shinyapps.io/template-dashboard-tips1/&lt;/a&gt;



&lt;p&gt;&lt;br&gt;&lt;br&gt;
Instead of reruning the entire script after any user interaction, Shiny only &lt;a href="https://shiny.posit.co/py/docs/overview.html#reactivity" rel="noopener noreferrer"&gt;re-renders elements that have been affected&lt;/a&gt; by that user interaction. This means the entire Shiny script doesn't need to rerun every time a user makes a change, but it leads to less readable and intuitive code. &lt;/p&gt;

&lt;p&gt;Unlike Streamlit, Shiny also allows you to &lt;a href="https://shiny.posit.co/py/docs/ui-customize.html#custom-css" rel="noopener noreferrer"&gt;add CSS classes&lt;/a&gt; to have more control over the look and feel of your app.&lt;/p&gt;

&lt;h3&gt;
  
  
  Pros
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;The script doesn't rerun after every user interaction&lt;/li&gt;
&lt;li&gt;Can use CSS to customize your apps&lt;/li&gt;
&lt;li&gt;Great for building dashboards&lt;/li&gt;
&lt;li&gt;Good documentation and examples&lt;/li&gt;
&lt;li&gt;Completely free and open-source&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Cons
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Less straightforward code&lt;/li&gt;
&lt;li&gt;Minimal features&lt;/li&gt;
&lt;li&gt;Newer library with a smaller community&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  NiceGUI
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://nicegui.io/" rel="noopener noreferrer"&gt;NiceGUI&lt;/a&gt; is Python library for building web applications that was &lt;a href="https://nicegui.io/#why" rel="noopener noreferrer"&gt;developed explicitly as an alternative to Streamlit&lt;/a&gt;. Like Shiny for Python, NiceGUI doesn't rerun the entire script after every user interaction. It also allows you to add CSS classes, including Tailwind classes, to your code for &lt;a href="https://nicegui.io/documentation/section_styling_appearance" rel="noopener noreferrer"&gt;more customization of the look and feel&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqah4vta8rz9ybh9t6j33.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqah4vta8rz9ybh9t6j33.png" alt="Screenshot of NiceGUI's website" width="800" height="504"&gt;&lt;/a&gt;&lt;/p&gt;
NiceGUI's website was built using NiceGUI.



&lt;p&gt;&lt;br&gt;&lt;br&gt;
NiceGUI code lacks the simplicity and intuitiveness of Streamlit code, and its approach to reactivity and state management is more opaque than Shiny's. There are different methods and decorators for different types of UI updating, so it can be difficult to know how to get the UI to update. In addition, NiceGUI's documentation is less robust than Streamlit's or Shiny's, and there are no tutorials or live examples. This makes getting started with NiceGUI more of a challenge.&lt;/p&gt;

&lt;h3&gt;
  
  
  Pros
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;The script doesn't rerun after every user interaction&lt;/li&gt;
&lt;li&gt;Can use inline CSS, stylesheets and Tailwind to customize your apps&lt;/li&gt;
&lt;li&gt;Completely free and open-source&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Cons
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Incomplete documentation&lt;/li&gt;
&lt;li&gt;No official tutorials&lt;/li&gt;
&lt;li&gt;Not great for building dashboards&lt;/li&gt;
&lt;li&gt;Updating the UI is not always straightforward or consistent&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Reflex
&lt;/h2&gt;

&lt;p&gt;While &lt;a href="https://reflex.dev/" rel="noopener noreferrer"&gt;Reflex&lt;/a&gt; is also a Python library for building interactive GUIs, its approach is different than Streamlit, Shiny and NiceGUI. Unlike the previous options, Reflex doesn't abstract away much of traditional web development. This means that if you are not familiar with traditional web development, Reflex comes with a bit of a learning curve. However, it also means that Reflex uses less magic to deal with reactivity and state management.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvgovyyusabojllulvgdm.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvgovyyusabojllulvgdm.png" alt="Screenshot of a Reflex app" width="800" height="437"&gt;&lt;/a&gt;&lt;/p&gt;
An example Reflex app: &lt;a href="https://dashboard-new.reflex.run/" rel="noopener noreferrer"&gt;https://dashboard-new.reflex.run&lt;/a&gt; 



&lt;p&gt;&lt;br&gt;&lt;br&gt;
Reflex uses a &lt;a href="https://reflex.dev/docs/state/overview/" rel="noopener noreferrer"&gt;State class&lt;/a&gt; to keep track of the state of the app, and methods within the State class update the app's state. Although Reflex code is more verbose than the previous examples, it is more explicit about state management and separating front-end and back-end code. This means there is less "magic" involved in Reflex apps so they are easier to adapt and extend.&lt;/p&gt;

&lt;h3&gt;
  
  
  Pros
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Explicit state management&lt;/li&gt;
&lt;li&gt;Robust documentation with lots of examples&lt;/li&gt;
&lt;li&gt;Templates to get started&lt;/li&gt;
&lt;li&gt;Has an AI app generator&lt;/li&gt;
&lt;li&gt;Customizable&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Cons
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Need to learn web development &lt;/li&gt;
&lt;li&gt;Code is not that simple and straightforward&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Anvil
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://anvil.works" rel="noopener noreferrer"&gt;Anvil&lt;/a&gt; takes a very different approach to building Python web applications. While the previous options are Python packages built as alternatives to Streamlit, Anvil was built to be &lt;a href="https://en.wikipedia.org/wiki/Visual_Basic_(classic)" rel="noopener noreferrer"&gt;Visual Basic&lt;/a&gt; for the web.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqqumqv950p86j8mbbqlh.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqqumqv950p86j8mbbqlh.png" alt="Screenshot of an Anvil application" width="800" height="484"&gt;&lt;/a&gt; &lt;/p&gt;
An example Anvil app. Learn more: &lt;a href="https://anvil.works/learn/examples/task-manager-app" rel="noopener noreferrer"&gt;https://anvil.works/learn/examples/task-manager-app&lt;/a&gt;





&lt;p&gt;Anvil is a cloud-based IDE where you visually build your user interfaces and write Python code for the front-end and back-end. Like Reflex, Anvil &lt;a href="https://anvil.works/articles/client-vs-server" rel="noopener noreferrer"&gt;doesn't abstract away web development&lt;/a&gt;, but it aims to make it more approachable for non-web developers. To build an Anvil app, you &lt;a href="https://anvil.works/docs/ui/quickstart" rel="noopener noreferrer"&gt;drag and drop components onto the page&lt;/a&gt; to build your UI (you can also create components in code), then write client-side code to make the components interactive and server-side code for back-end functions. To call server functions from your UI, you just use &lt;code&gt;anvil.server.call&lt;/code&gt;. Client-side code runs entirely in the browser which makes it super fast.&lt;/p&gt;

&lt;p&gt;Anvil allows you to do everything in Python, but doesn't try to stop you &lt;a href="https://anvil.works/blog/escape-hatches-and-ejector-seats" rel="noopener noreferrer"&gt;if you want to break out&lt;/a&gt;. You can still use HTML, CSS and JS in your Anvil apps. What's more, Anvil includes a whole host of features that none of the other options having including a &lt;a href="https://anvil.works/docs/data-tables" rel="noopener noreferrer"&gt;built-in database&lt;/a&gt;, &lt;a href="https://anvil.works/docs/users" rel="noopener noreferrer"&gt;out-of-the-box user management&lt;/a&gt; and &lt;a href="https://anvil.works/docs/deployment/quickstart" rel="noopener noreferrer"&gt;instant cloud hosting&lt;/a&gt;. &lt;/p&gt;

&lt;h3&gt;
  
  
  Pros
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Visually build your User Interface&lt;/li&gt;
&lt;li&gt;Lots of built-in features and integrations&lt;/li&gt;
&lt;li&gt;Instant unlimited cloud hosting&lt;/li&gt;
&lt;li&gt;Explicit state management and separation of client and server&lt;/li&gt;
&lt;li&gt;In-depth documentation and tutorials&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Cons
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Need to get used to a new IDE&lt;/li&gt;
&lt;li&gt;Client-server architecture may be unfamiliar to non-web developers&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://streamlit.io/" rel="noopener noreferrer"&gt;Streamlit&lt;/a&gt;&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Strengths&lt;/strong&gt;: Quick to learn, straightforward code, easy for simple dashboards&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Weakness&lt;/strong&gt;: The entire script re-runs with user interaction, limited in features and flexibility&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;strong&gt;&lt;a href="https://shiny.posit.co/py/" rel="noopener noreferrer"&gt;Shiny for Python&lt;/a&gt;&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Strengths&lt;/strong&gt;: Only re-runs relevant functions, great for building dashboards, good documentation and examples&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Weaknesses&lt;/strong&gt;: Newer library with a smaller community, minimal features&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;strong&gt;&lt;a href="https://nicegui.io/" rel="noopener noreferrer"&gt;NiceGUI&lt;/a&gt;&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Strengths&lt;/strong&gt;: Doesn't re-run the script after each interaction, can use CSS and Tailwind for customixation&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Weaknesses&lt;/strong&gt;: Code isn't always straightforward, not great for dashboarding, incomplete documentation with no official tutorials&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;strong&gt;&lt;a href="https://reflex.dev/" rel="noopener noreferrer"&gt;Reflex&lt;/a&gt;&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Strengths&lt;/strong&gt;: Uses explicit state management, very customizable, robust documentation and examples&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Weaknesses&lt;/strong&gt;: Larger learning curve, need to understand web development&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;strong&gt;&lt;a href="https://anvil.works/" rel="noopener noreferrer"&gt;Anvil&lt;/a&gt;&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Strengths&lt;/strong&gt;: Out-of-the-box instant cloud hosting , drag-and-drop UI builder, more features for complex apps, in-depth documentation with lots of tutorials&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Weaknesses&lt;/strong&gt;: Unfamiliar IDE, client-server architecture may be unfamiliar as well&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;With Python being the most popular programming language, there are more tools than ever for building interactive web applications entirely in Python.&lt;/p&gt;

&lt;p&gt;&lt;a href="//streamlit.io"&gt;Streamlit&lt;/a&gt; is one such tool that offers a simple, Pythonic approach. However, it suffers from two main weaknesses: the script needs to be re-run after every user interaction, and customizing the look and feel of a Streamlit app is dificult. &lt;a href="https://shiny.posit.co/py/" rel="noopener noreferrer"&gt;Shiny for Python&lt;/a&gt; is a great alternative for building dashboards and small data-backed apps. Shiny only re-renders code as necessary - not the entire script, and offers more flexibility in styling your app. &lt;a href="https://nicegui.io/" rel="noopener noreferrer"&gt;NiceGUI&lt;/a&gt; offers a similar approach, but with less intuitive code and no tutorials or live examples, is more of a challenge to get started with. &lt;a href="https://reflex.dev/" rel="noopener noreferrer"&gt;Reflex&lt;/a&gt; is a great option if you want more flexibility in building your app's UI, but you'll need to learn a bit of traditional web development.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://dev.to/"&gt;Anvil&lt;/a&gt; takes a different approach to building Python web apps. With Anvil, you &lt;a href="https://anvil.works/docs/ui/quickstart" rel="noopener noreferrer"&gt;drag and drop components&lt;/a&gt; to build your user interface then write Python code to make it interactive. Anvil also comes with many out-of-the-box features such as a &lt;a href="https://anvil.works/docs/data-tables" rel="noopener noreferrer"&gt;built-in database&lt;/a&gt;, &lt;a href="https://anvil.works/docs/users" rel="noopener noreferrer"&gt;user management&lt;/a&gt; and &lt;a href="https://anvil.works/docs/deployment/quickstart" rel="noopener noreferrer"&gt;instant cloud hosting&lt;/a&gt;. If you want to build more complex apps and host them easily for free, then Anvil is your best bet.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>python</category>
      <category>programming</category>
    </item>
    <item>
      <title>What makes Anvil so easy to learn?</title>
      <dc:creator>Ryan</dc:creator>
      <pubDate>Fri, 18 Jul 2025 10:47:59 +0000</pubDate>
      <link>https://dev.to/anvil/what-makes-anvil-so-easy-to-learn-3ggi</link>
      <guid>https://dev.to/anvil/what-makes-anvil-so-easy-to-learn-3ggi</guid>
      <description>&lt;h1&gt;
  
  
  Anvil's Shallow Learning Curve
&lt;/h1&gt;

&lt;p&gt;When evaluating a new dev tool, a common question is "How long will it take to learn?". Lengthy learning curves cost time, effort, and money - but one of the beauties of Anvil is its shallow learning curve.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;I don’t want all the things slowing me down. I don’t want learning curves, I don’t want any of that. I want it quick, and that’s what Anvil gave me. — &lt;strong&gt;Shonna Smith, Product Manager, Consultant&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Anvil lets you become productive in days, not months. This isn't just a marketing claim, it's an experience shared by many Anvil users. Let's take a look at why Anvil is quick to learn.&lt;/p&gt;




&lt;h2&gt;
  
  
  Why Is Anvil Easy To Learn?
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. It's All Python
&lt;/h3&gt;

&lt;p&gt;It's all Python, and much like Python, the learning curve of Anvil is gentle and shallow.&lt;/p&gt;

&lt;p&gt;You don't need to learn new languages or frameworks for each layer of your web app - saving you time. You can use Python for UI components, front-end code, back-end code and interacting with your database.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Simple Anvil event handler - just Python
&lt;/span&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;button_click&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;event_args&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="c1"&gt;# Updating the display text of a label component
&lt;/span&gt;    &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;output_label&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Hello, &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name_box&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;!&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  2. No Boilerplate Code
&lt;/h3&gt;

&lt;p&gt;Anvil eliminates the need for boiler plate code and setup. The platform wraps common tasks like database access, user authentication, and API endpoints in easy-to-use APIs, letting you focus on what your application does.&lt;/p&gt;

&lt;p&gt;Consider how much effort you typically spend on:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Setting up projects&lt;/li&gt;
&lt;li&gt;Configuring build tools&lt;/li&gt;
&lt;li&gt;Managing deployment pipelines&lt;/li&gt;
&lt;li&gt;Creating databases and access controls&lt;/li&gt;
&lt;li&gt;Building secure user authentication&lt;/li&gt;
&lt;li&gt;Configuring email services and servers&lt;/li&gt;
&lt;li&gt;Checking software security&lt;/li&gt;
&lt;li&gt;Developing API endpoints&lt;/li&gt;
&lt;li&gt;Setting up version control&lt;/li&gt;
&lt;li&gt;Implementing secrets management&lt;/li&gt;
&lt;li&gt;Integrating external services&lt;/li&gt;
&lt;li&gt;Connecting to IoT devices&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Anvil simplifies and handles all this and more for you, dramatically saving you time. It has the added benefit of making your app more secure - less code equals fewer opportunities for vulnerabilities.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;If data is ever at risk in the journey, we can't move forward with a solution, full stop... They've thought about all of this so that you don't have to. - &lt;strong&gt;Jacque Van Niekerk, Data Scientist, CFC Underwriting&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h3&gt;
  
  
  3. Extensive Documentation
&lt;/h3&gt;

&lt;p&gt;Anvil's documentation and tutorials are extensive. They cover everything from the basics to advanced topics, making it easy to get up to speed.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://anvil.works/learn/tutorials?utm_source=devto_learning_curve" rel="noopener noreferrer"&gt;Try a tutorial&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://anvil.works/docs/overview?utm_source=devto_learning_curve" rel="noopener noreferrer"&gt;Read the docs&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Additionally, we have an extremely active &lt;a href="https://anvil.works/forum?utm_source=devto_learning_curve" rel="noopener noreferrer"&gt;community forum&lt;/a&gt; where you can ask questions if you're stuck, share knowledge, and get help from our team.&lt;/p&gt;




&lt;h3&gt;
  
  
  4. Traditional Web Architecture
&lt;/h3&gt;

&lt;p&gt;Anvil follows the traditional web architecture approach, with a separation between client and server code. This makes it familiar, easy to understand, and maintain. &lt;/p&gt;

&lt;p&gt;For people who aren't familiar with web architecture, i.e. non-web developers, it's still useful. The clear separation of concerns makes it easier for you to debug and think about. The underlying principles are also widely understood by other people, meaning they can help even without experience of Anvil.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://anvil.works/articles/client-vs-server?utm_source=devto_learning_curve" rel="noopener noreferrer"&gt;Learn more about client vs server&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  A Different Kind of Investment With Real-World Impact
&lt;/h2&gt;

&lt;p&gt;Anvil being quick to learn means:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Faster time-to-market for your applications&lt;/li&gt;
&lt;li&gt;Reduced training costs for your team&lt;/li&gt;
&lt;li&gt;Lower risk when evaluating the platform&lt;/li&gt;
&lt;li&gt;Increased productivity rather than delayed returns&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And the impact has been felt by many Anvil users:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;We wanted a web app urgently during the Covid-19 lockdown. With only intermediate skills in Python, and no knowledge of HTML/CSS/JavaScript/Flask/Django etc, Anvil enabled us to share a Minimum Viable Product in just 7 days.-&lt;strong&gt;Peter Fison, Managing Director, South West London TV&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Next Steps
&lt;/h2&gt;

&lt;p&gt;Ready to see how shallow Anvil's learning curve is? Or do you have some questions?&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Try Anvil's &lt;a href="https://anvil.works/learn/tutorials/feedback-form?utm_source=devto_learning_curve" rel="noopener noreferrer"&gt;intro tutorial&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Ask questions on our friendly &lt;a href="https://anvil.works/forum?utm_source=devto_learning_curve" rel="noopener noreferrer"&gt;community forum&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href="//mailto:sales@anvil.works"&gt;Talk to an Anvil engineer&lt;/a&gt; to discuss your specific use case&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  More about Anvil
&lt;/h2&gt;

&lt;p&gt;If you're new here, welcome! &lt;a href="https://anvil.works?utm_source=devto_learning_curve" rel="noopener noreferrer"&gt;Anvil&lt;/a&gt; is a platform for building full-stack web apps with nothing but Python. No need to wrestle with JS, HTML, CSS, Python, SQL and all their frameworks – just &lt;strong&gt;build it all in Python&lt;/strong&gt;.&lt;/p&gt;

</description>
      <category>python</category>
      <category>webdev</category>
      <category>learning</category>
      <category>programming</category>
    </item>
    <item>
      <title>Case Study: How Chris Houston Built a BI Tool with Anvil</title>
      <dc:creator>Love Otudor</dc:creator>
      <pubDate>Fri, 11 Jul 2025 14:45:28 +0000</pubDate>
      <link>https://dev.to/anvil/case-study-how-chris-houston-built-a-bi-tool-with-anvil-4l7n</link>
      <guid>https://dev.to/anvil/case-study-how-chris-houston-built-a-bi-tool-with-anvil-4l7n</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Query Streams transforms Excel and Google Sheets into powerful BI tools by enabling real-time database queries directly within the spreadsheet—no coding required. Built as a nights-and-weekends side project by Chris using Anvil, Query Streams soft launched just four weeks ago and is already being used by data analysts across multiple companies.&lt;/em&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;em&gt;Built by a solo developer&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Production-ready in under 5 months&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Google Sheets add-on is live&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Microsoft Excel add-in is live&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  The Challenge: When BI Tools Meet Reality
&lt;/h2&gt;

&lt;p&gt;Every data team knows the cycle: Companies invest heavily in BI tools because everyone loves beautiful dashboards. Yet somehow, the most common follow-up question is still:&lt;/p&gt;

&lt;p&gt;&lt;em&gt;"The dashboards look great… uh, how do I export this to a spreadsheet?"&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;And then it all ends up in a spreadsheet anyway. Despite years of trying to move away from Excel and Google Sheets, spreadsheets are more popular than ever. According to a 2025 survey by &lt;a href="https://www.alteryx.com/about-us/newsroom/press-release/new-research-reveals-that-ai-brings-productivity-gains-but-reliance-on-spreadsheets-puts-data-quality-at-risk" rel="noopener noreferrer"&gt;Alteryx&lt;/a&gt;, &lt;strong&gt;76% of data analysts still use spreadsheets as their primary tool&lt;/strong&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  What If We Stopped Fighting Spreadsheets?
&lt;/h3&gt;

&lt;p&gt;Chris had been thinking about this for years. What if, instead of replacing spreadsheets, we empowered them?&lt;br&gt;
&lt;em&gt;“What if we didn’t try to replace spreadsheets with BI tools? What if we made spreadsheets the BI tool?”&lt;/em&gt;&lt;br&gt;
This idea stuck with him until just after Thanksgiving 2024, when he started building a solution.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Solution: Turn Spreadsheets Into the BI Tool
&lt;/h2&gt;

&lt;p&gt;Query Streams is a real-time data integration platform that lets users run SQL queries from Google Sheets and Excel directly against remote databases, without exposing credentials, setting up VPNs, or configuring firewalls. It supports SQL Server, MySQL, PostgreSQL, SQLite, Access, and other databases. You can:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Share and receive queries&lt;/li&gt;
&lt;li&gt;Build live dashboards&lt;/li&gt;
&lt;li&gt;Securely expose specific database queries&lt;/li&gt;
&lt;li&gt;Choose what data to share and with whom&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqxj7yb3ru10rddalwv9f.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqxj7yb3ru10rddalwv9f.png" alt="Query Streams Image" width="800" height="389"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;No hassle. No copy-pasting. No manual exports. Just real-time data, right where analysts already work.&lt;/p&gt;

&lt;h2&gt;
  
  
  Building Query Streams: Smarter Tools, Built Faster with Anvil
&lt;/h2&gt;

&lt;p&gt;The most challenging part of building Query Streams was building the network agent in C# and other technologies that Chris wasn’t familiar with. Once he overcame that technical hurdle, building the web app in Anvil was straightforward.&lt;/p&gt;

&lt;p&gt;With minimal experience in HTML, CSS, and JavaScript, Chris leaned heavily on &lt;a href="https://anvil.works/docs/ui/custom-components/html-components?utm_source=crosspost:dev.to:/case-studies/querystreams"&gt;Anvil’s custom HTML support &lt;/a&gt; and Anvil components to bring his unique UI ideas to life.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;I thought we were locked into the Anvil components on the designer. But as I explored custom components in Anvil, I realised that, wow, you can build anything in Anvil.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://dev.to/chris_houston_7d34a375ece"&gt;&lt;strong&gt;Chris Houston&lt;/strong&gt;&lt;/a&gt; — &lt;em&gt;Founder and CEO, Query Streams&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;In just four months, Query Streams was ready to use. Built entirely in Chris's spare time while working a full-time job. Since Anvil is web-based, he could work on Query Streams wherever and whenever he had time—whether at home, in early mornings, or even while travelling with just his laptop.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Results: From Idea to Impact
&lt;/h2&gt;

&lt;p&gt;Query Streams has begun gaining traction even before its official launch. In the four weeks since its soft launch with the Google Sheets add-on, teams and analysts across several organisations have started using the platform.&lt;/p&gt;

&lt;p&gt;Now, with the Excel add-in also live on the Microsoft AppSource marketplace, Query Streams has expanded its reach to both major spreadsheet platforms. With both add-ons available, Chris is preparing for the official launch and broader publicity efforts. You can follow along and get updates on &lt;a href="https://x.com/querystreams" rel="noopener noreferrer"&gt;X&lt;/a&gt; and &lt;a href="https://www.linkedin.com/company/querystreams/" rel="noopener noreferrer"&gt;LinkedIn&lt;/a&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Anvil is like a Swiss army knife of awesome! It allowed me to build Query Streams with a lot of ease while working alone.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://dev.to/chris_houston_7d34a375ece"&gt;&lt;strong&gt;Chris Houston&lt;/strong&gt;&lt;/a&gt; — &lt;em&gt;Founder and CEO, Query Streams&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fngnel9z8255z7xkbw135.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fngnel9z8255z7xkbw135.png" alt=" " width="800" height="389"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  More Information
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Query Streams&lt;/strong&gt; lets you run real-time database queries directly from Excel or Google Sheets — no code required.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.querystreams.com/" rel="noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fle7jxf944svyjd9kxnba.png" alt=" " width="608" height="140"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you’re new to &lt;strong&gt;Anvil&lt;/strong&gt; and want to see how you can build powerful web apps using just Python, up to 7× faster than traditional development:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://anvil.works?utm_source=crosspost:dev.to:/case-studies/querystreams"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flywzy5mdmou1v27k104o.png" alt=" " width="608" height="140"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Have questions or want to get in touch? Visit &lt;a href="https://anvil.works/contact?utm_source=crosspost:dev.to:/case-studies/querystreams"&gt;anvil.works/contact&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>businessintelligence</category>
      <category>webdev</category>
      <category>python</category>
      <category>startup</category>
    </item>
    <item>
      <title>How We Brought the GOV.UK Design System into Anvil</title>
      <dc:creator>Ryan</dc:creator>
      <pubDate>Mon, 02 Jun 2025 14:57:16 +0000</pubDate>
      <link>https://dev.to/anvil/how-we-brought-the-govuk-design-system-into-anvil-4a1f</link>
      <guid>https://dev.to/anvil/how-we-brought-the-govuk-design-system-into-anvil-4a1f</guid>
      <description>&lt;h1&gt;
  
  
  Case Study: Implementing Any Design System in Anvil
&lt;/h1&gt;

&lt;blockquote&gt;
&lt;p&gt;New to Anvil? Welcome! &lt;a href="https://anvil.works?utm_source=devto_govuk_design" rel="noopener noreferrer"&gt;Anvil&lt;/a&gt; lets you build full-stack web apps using only Python. No need to juggle JavaScript, HTML, CSS, Python, SQL and all their frameworks. &lt;strong&gt;Just code in Python&lt;/strong&gt; and bring your app to life!&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://www.figma.com/blog/design-systems-101-what-is-a-design-system/" rel="noopener noreferrer"&gt;Design systems&lt;/a&gt; are invaluable for creating professional web apps. Implementing your design system in Anvil, by creating custom drag-and-drop components, layouts, and themes, streamlines development for both yourself and others. Today, I’ll show you one I built from scratch to demonstrate what’s possible in Anvil.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmtsdoxp882moowwn9lqr.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmtsdoxp882moowwn9lqr.png" alt=" "&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;For this case study, I'm using &lt;a href="https://design-system.service.gov.uk/" rel="noopener noreferrer"&gt;GOV.UK's design system&lt;/a&gt;. It's a great example of a comprehensive design system, which standardises styles, helps construct components and takes accessibility seriously. It provides all the benefits of using a well thought out design system when creating a web app - so it's perfect to show you what you can achieve in Anvil.&lt;/p&gt;




&lt;h2&gt;
  
  
  The finished product
&lt;/h2&gt;

&lt;p&gt;The proof is in the pudding so, before I dig into how I implemented the system in Anvil, here's an example of using the finished design system in the Anvil editor. Here's me using the design system as a dependency and creating a GOV.UK form by simply dragging and dropping components into the page:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdg2mvuhqen3kr2xlaj2p.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdg2mvuhqen3kr2xlaj2p.gif"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can even clone this app and play around yourself:&lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;a href="https://anvil.works/build#clone:ESWLOEKGXMN2N24H=WGCFPUA34JSRPR23KVU4FJXJ" rel="noopener noreferrer"&gt;Clone the Example&lt;/a&gt;
&lt;/h4&gt;




&lt;h2&gt;
  
  
  How it's built
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://design-system.service.gov.uk/" rel="noopener noreferrer"&gt;GOV.UK's design system website&lt;/a&gt; provides all the HTML and CSS needed to implement their design system. They break everything down into individual &lt;a href="https://design-system.service.gov.uk/components" rel="noopener noreferrer"&gt;components&lt;/a&gt; and &lt;a href="https://design-system.service.gov.uk/styles/page-template/" rel="noopener noreferrer"&gt;page templates&lt;/a&gt;. Since Anvil allows for extensive customisation, I was able to use a few of its out-of-the-box features to recreate them.&lt;/p&gt;

&lt;h3&gt;
  
  
  Custom HTML Layouts
&lt;/h3&gt;

&lt;p&gt;The first step was to implement GOV.UKs page template.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1ysdi0nvi4ztm86qpcmy.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1ysdi0nvi4ztm86qpcmy.png" alt=" "&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Anvil’s &lt;a href="https://anvil.works/docs/ui/layouts/html-layouts?utm_source=devto_govuk_design" rel="noopener noreferrer"&gt;custom HTML Layouts&lt;/a&gt; let me use the HTML from the &lt;a href="https://design-system.service.gov.uk/styles/page-template/" rel="noopener noreferrer"&gt;design system's page templates&lt;/a&gt;. All I had to do was insert &lt;a href="https://anvil.works/docs/ui/layouts/html-layouts#adding-slots" rel="noopener noreferrer"&gt;slots&lt;/a&gt; in the HTML to define where components can be added to the Layout when it is used by other Forms.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;!-- Here's a slimmed down example of the GOV.UK's footer --&amp;gt;
&amp;lt;footer class="govuk-footer" role="contentinfo"&amp;gt;
    &amp;lt;!-- To let developers add components to the footer, I simply defined
    the anvil-slot. --&amp;gt;
    &amp;lt;div anvil-slot="footer-items"&amp;gt;
        &amp;lt;!-- And added usage details for the Anvil designer. --&amp;gt;
        &amp;lt;p anvil-if-slot-empty="footer-items" class="anvil-designer-only"&amp;gt;&amp;lt;i&amp;gt;Drag footer links or components here&amp;lt;/i&amp;gt;&amp;lt;/p&amp;gt;
    &amp;lt;/div&amp;gt;
&amp;lt;/footer&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;To see how simple it is to create layouts from scratch, check out our docs:&lt;/p&gt;
&lt;h4&gt;
  
  
  &lt;a href="https://anvil.works/docs/ui/layouts/html-layouts" rel="noopener noreferrer"&gt;Read the docs on custom layouts&lt;/a&gt;
&lt;/h4&gt;
&lt;h3&gt;
  
  
  Components from HTML
&lt;/h3&gt;

&lt;p&gt;For GOV.UK’s individual components, I used Anvil's ability to &lt;a href="https://anvil.works/docs/ui/custom-components/html-components?utm_source=devto_govuk_design" rel="noopener noreferrer"&gt;create components from scratch in HTML&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;I simply copied and pasted the HTML from the design system and added the &lt;code&gt;anvil-name&lt;/code&gt; attribute to the elements I wanted to access in code.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;!-- The Component's HTML is the same as the design system plus the `anvil-name` attribute --&amp;gt;
&amp;lt;input anvil-name="govuk-input" class="govuk-input"&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;With &lt;code&gt;anvil-name&lt;/code&gt; assigned, I could easily reference those elements in Python using Anvil’s &lt;a href="https://anvil.works/docs/ui/custom-components/html-components#accessing-elements?utm_source=devto_govuk_design" rel="noopener noreferrer"&gt;dom_nodes API&lt;/a&gt;. This let me to select individual elements, insert new content, apply new styles, and modify attributes—all while keeping the structure of the original design system intact.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Here's are some simple getter and setter functions for the text input component I built
@property
def label_text(self):
    return self.dom_nodes["govuk-label"].textContent

@label_text.setter
def label_text(self, value):
    self.dom_nodes["govuk-label"].textContent = value
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Anvil stands out by giving you full access to any &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/Element" rel="noopener noreferrer"&gt;HTML element's APIs&lt;/a&gt; directly from Python code. There are no limits imposed by Anvil's abtraction.&lt;/p&gt;

&lt;p&gt;Check out our tutorial on building custom components from HTML:&lt;/p&gt;
&lt;h4&gt;
  
  
  &lt;a href="https://anvil.works/learn/tutorials/access-html-elements-in-python?utm_source=devto_govuk_design" rel="noopener noreferrer"&gt;Learn how to create components&lt;/a&gt;
&lt;/h4&gt;


&lt;h2&gt;
  
  
  Ready to get started?
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;We’ve got full documentation and tutorials&lt;/strong&gt; to help you get started:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://anvil.works/learn/tutorials/using-layouts-to-create-multi-page-app?utm_source=devto_govuk_design" rel="noopener noreferrer"&gt;Multi-page apps with Layouts tutorial&lt;/a&gt; - Learn how to structure your app using layouts.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://anvil.works/docs/ui/layouts/html-layouts?utm_source=devto_govuk_design" rel="noopener noreferrer"&gt;Custom HTML Layouts docs&lt;/a&gt; - Recreate page templates as Anvil layouts.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://anvil.works/learn/tutorials/access-html-elements-in-python?utm_source=devto_govuk_design" rel="noopener noreferrer"&gt;Creating custom components from scratch tutorial&lt;/a&gt; - Follow a step-by-step guide to creating your first custom component.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://anvil.works/docs/ui/custom-components/html-components?utm_source=devto_govuk_design" rel="noopener noreferrer"&gt;Components from HTML docs&lt;/a&gt; - Build individual components and access their attributes.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These resources will help you with everything you need to bring your design system into Anvil.&lt;/p&gt;

&lt;p&gt;Any questions? Our &lt;a href="https://anvil.works/forum?utm_source=devto_govuk_design" rel="noopener noreferrer"&gt;Community Forum&lt;/a&gt; is full of helpful information and Anvil experts.&lt;/p&gt;


&lt;h2&gt;
  
  
  More about Anvil
&lt;/h2&gt;

&lt;p&gt;If you're new here, welcome! &lt;a href="https://anvil.works?utm_source=devto_govuk_design" rel="noopener noreferrer"&gt;Anvil&lt;/a&gt; is a platform for building full-stack web apps with nothing but Python. No need to wrestle with JS, HTML, CSS, Python, SQL and all their frameworks – just &lt;strong&gt;build it all in Python&lt;/strong&gt;.&lt;/p&gt;
&lt;h4&gt;
  
  
  &lt;a href="https://anvil.works/build?utm_source=devto_govuk_design" rel="noopener noreferrer"&gt;Sign up for Anvil&lt;/a&gt;
&lt;/h4&gt;

&lt;p&gt;Want to build an app of your own? Get started with one of our tutorials:&lt;/p&gt;


&lt;div class="ltag__user ltag__user__id__458094"&gt;
    &lt;a href="/codingwithryan" class="ltag__user__link profile-image-link"&gt;
      &lt;div class="ltag__user__pic"&gt;
        &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F458094%2Fb913a90e-46cd-4803-9a09-4e679b2f0021.png" alt="codingwithryan image"&gt;
      &lt;/div&gt;
    &lt;/a&gt;
  &lt;div class="ltag__user__content"&gt;
    &lt;h2&gt;
&lt;a class="ltag__user__link" href="/codingwithryan"&gt;Ryan&lt;/a&gt;Follow
&lt;/h2&gt;
    &lt;div class="ltag__user__summary"&gt;
      &lt;a class="ltag__user__link" href="/codingwithryan"&gt;Software developer. Tech enthusiast. Follow me for Python, Anvil and software development content.&lt;/a&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;



</description>
      <category>python</category>
      <category>webdev</category>
      <category>design</category>
      <category>designsystem</category>
    </item>
    <item>
      <title>Secure Team Collaboration in Anvil</title>
      <dc:creator>Love Otudor</dc:creator>
      <pubDate>Fri, 30 May 2025 14:48:49 +0000</pubDate>
      <link>https://dev.to/anvil/secure-team-collaboration-in-anvil-3680</link>
      <guid>https://dev.to/anvil/secure-team-collaboration-in-anvil-3680</guid>
      <description>&lt;p&gt;You asked and we answered! We put together a practical how-to guide on collaborating as a team in Anvil. Building amazing Anvil apps is even better with your team by your side, and we've developed foolproof methods to make this process hassle-free.&lt;/p&gt;

&lt;p&gt;This guide walks you through how to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Set up secure, real-world workflows for collaborating on Anvil apps while keeping your production environment isolated and safe.&lt;/li&gt;
&lt;li&gt;Separate development and production environments to ensure only well-tested and reviewed changes reach your users.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Whether your team prefers working together on a shared Anvil app or on individual ones, this step-by-step guide will help you implement Git-based workflows that improve code quality and team efficiency.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://anvil.works/docs/how-to/collaborate-in-anvil?utm_source=crosspost:devto:/blog/secure-team-collaboration" rel="noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwrc91ohsy7sslyw2vqwz.png" alt="Check out the full guide here" width="379" height="86"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  More about Anvil
&lt;/h2&gt;

&lt;p&gt;If you're new here, welcome! &lt;a href="https://anvil.works?utm_source=crosspost:devto:/blog/secure-team-collaboration" rel="noopener noreferrer"&gt;Anvil&lt;/a&gt; is a platform for building full-stack web apps with nothing but Python. No need to wrestle with JS, HTML, CSS, Python, SQL and all their frameworks - just build it all in Python.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://anvil.works/build?utm_source=crosspost:devto:/blog/secure-team-collaboration" rel="noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsw66qxlkopgppg50i2i7.png" alt="Sign up for Anvil" width="800" height="191"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>python</category>
      <category>anvil</category>
      <category>webdev</category>
      <category>git</category>
    </item>
    <item>
      <title>Python Admin Dashboard Template</title>
      <dc:creator>Brooke Myers</dc:creator>
      <pubDate>Tue, 29 Apr 2025 09:48:31 +0000</pubDate>
      <link>https://dev.to/anvil/python-admin-dashboard-template-3f4o</link>
      <guid>https://dev.to/anvil/python-admin-dashboard-template-3f4o</guid>
      <description>&lt;p&gt;Anvil is a powerful and versatile tool for building full-stack web applications. With Anvil, you can &lt;a href="https://anvil.works/blog/build-a-web-ui-with-python?utm_source=crosspost:dev.to:/learn/examples/admin-dashboard"&gt;quickly and easily create your UI&lt;/a&gt; and write Python code to control the front-end and back-end of your app. Creating apps with Anvil is fast and flexible, making it well-suited for building dashboards, SaaS products, and internal tools.&lt;/p&gt;

&lt;p&gt;Whatever your use case, Anvil can help you build it. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://admin-dashboard-sampler.anvil.app" rel="noopener noreferrer"&gt;Explore the dashboard&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpijemkknm6z8yg7jcen9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpijemkknm6z8yg7jcen9.png" alt="Screenshot of the profile page" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Ready to dive into the source code?&lt;/p&gt;

&lt;p&gt;&lt;a href="https://anvil.works/build?utm_source=crosspost:dev.to:/learn/examples/admin-dashboard#clone:OONBCUWWWA7LRQDM=2MBSGCHCL4MIG6WZJMFGX7OW"&gt;Clone the app&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Create powerful apps with a powerful tool
&lt;/h2&gt;

&lt;p&gt;With a &lt;a href="https://anvil.works/docs/ui/quickstart?utm_source=crosspost:dev.to:/learn/examples/admin-dashboard"&gt;drag-and-drop UI builder&lt;/a&gt;, &lt;a href="https://anvil.works/learn/tutorials/database-backed-apps?utm_source=crosspost:dev.to:/learn/examples/admin-dashboard"&gt;integrated database&lt;/a&gt; and &lt;a href="https://anvil.works/learn/tutorials/multi-user-apps?utm_source=crosspost:dev.to:/learn/examples/admin-dashboard"&gt;built-in user management&lt;/a&gt;, Anvil takes care of the hard stuff so you can focus on building your app. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://dev.to/docs/email"&gt;Send emails&lt;/a&gt;, &lt;a href="https://anvil.works/docs/working-with-files/creating-pdf-files?utm_source=crosspost:dev.to:/learn/examples/admin-dashboard"&gt;generate PDFs&lt;/a&gt; and &lt;a href="https://anvil.works/docs/deployment/quickstart?utm_source=crosspost:dev.to:/learn/examples/admin-dashboard"&gt;deploy your app to the web&lt;/a&gt; in just a click.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fk7tyaqs4duc17u1lxm1q.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fk7tyaqs4duc17u1lxm1q.png" alt="Screenshot of the analytics page" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Build your UI with Material 3
&lt;/h2&gt;

&lt;p&gt;The Admin Dashboard uses the &lt;a href="https://m3.material.io/" rel="noopener noreferrer"&gt;Material 3&lt;/a&gt; design system for a sleek and modern design. Build your own dashboards by dragging and dropping Material 3 components onto the page. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffc9q96tvc3cojtjuoox1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffc9q96tvc3cojtjuoox1.png" alt="Screenshot of the settings page" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Try it for yourself
&lt;/h2&gt;

&lt;p&gt;Clone the Admin Dashboard Template to explore it for yourself.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://anvil.works/build?utm_source=crosspost:dev.to:/learn/examples/admin-dashboard#clone:OONBCUWWWA7LRQDM=2MBSGCHCL4MIG6WZJMFGX7OW"&gt;Clone the app&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  More about Anvil
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://anvil.works?utm_source=crosspost:dev.to:/learn/examples/admin-dashboard"&gt;Anvil&lt;/a&gt; is a platform for building full-stack web apps with nothing but Python. No need to wrestle with JS, HTML, CSS, Python, SQL and all their frameworks – just &lt;strong&gt;build it all in Python&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://anvil.works/build?utm_source=crosspost:dev.to:/learn/examples/admin-dashboard"&gt;Sign up for Anvil&lt;/a&gt;&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>python</category>
    </item>
    <item>
      <title>Building a Game App with Just Python</title>
      <dc:creator>Love Otudor</dc:creator>
      <pubDate>Wed, 16 Apr 2025 16:51:04 +0000</pubDate>
      <link>https://dev.to/anvil/building-a-game-app-with-just-python-4fbm</link>
      <guid>https://dev.to/anvil/building-a-game-app-with-just-python-4fbm</guid>
      <description>&lt;p&gt;"&lt;strong&gt;Guess the Sketch&lt;/strong&gt;" is a multiplayer game where you draw sketches and challenge friends to guess what they are. Players earn points for correct guesses, with fewer attempts leading to higher scores. Each round, one player is chosen to sketch, while the others try to guess as quickly as possible.&lt;/p&gt;

&lt;p&gt;I built this game using Python and Anvil, and it was surprisingly easy! I didn’t need to write HTML, CSS, or JavaScript. In this post, I will walk you through the key parts of building Guess the Sketch:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
Building the UI,&lt;/li&gt;
&lt;li&gt;
Saving and sending sketches,&lt;/li&gt;
&lt;li&gt;
Sending invites,&lt;/li&gt;
&lt;li&gt;
Managing players and scores, and&lt;/li&gt;
&lt;li&gt;
Publishing and sharing.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Let's get started!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fd4m8wl12p5mv20ylnzts.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fd4m8wl12p5mv20ylnzts.gif" alt="Game Demo" width="1114" height="868"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://anvil.works/build#clone:LBYMHJ3D5VHWUS3G=V2TWD2XDO3Z6MHCCXTEPXQVF" rel="noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpkvbvqp0y0tdl5jyjcic.png" alt="Open in Anvil" width="461" height="140"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Building the UI
&lt;/h2&gt;

&lt;p&gt;With Anvil’s drag-and-drop editor, building the UI was very intuitive. Instead of writing HTML and CSS, I simply dragged components from the &lt;a href="https://anvil.works/docs/editor/form-editor?utm_source=crosspost:dev.to:/blog/guess-the-sketch-game#toolbox"&gt;Toolbox&lt;/a&gt; onto the Form and arranged them as needed. Here is how easy it was to build the &lt;strong&gt;SketchScreen&lt;/strong&gt;, where players create and name their sketches.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fezl5ads6zoss1frjfeq7.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fezl5ads6zoss1frjfeq7.gif" alt="Creating the Sketch Screen in Anvil" width="640" height="427"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Anvil’s &lt;a href="https://anvil.works/docs/ui/components/canvas?utm_source=crosspost:dev.to:/blog/guess-the-sketch-game"&gt;Canvas component&lt;/a&gt; provided a seamless way to add a drawing area to the game. It is a Python wrapper around the HTML &lt;code&gt;&amp;lt;canvas&amp;gt;&lt;/code&gt; element, with built-in &lt;a href="https://anvil.works/docs/api/anvil?utm_source=crosspost:dev.to:/blog/guess-the-sketch-game#Canvas_attributes"&gt;methods and event handlers&lt;/a&gt; that handle drawing effortlessly. I used the &lt;code&gt;mouse_down&lt;/code&gt;, &lt;code&gt;mouse_move&lt;/code&gt;, and &lt;code&gt;mouse_up&lt;/code&gt; events to track real-time mouse movement and draw lines on the canvas. Adding an eraser was as simple as setting the brush colour to match the background of the drawing area.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Want to learn more about the Canvas component? Check out this Canvas Tutorial:&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://anvil.works/learn/tutorials/canvas?utm_source=crosspost:dev.to:/blog/guess-the-sketch-game"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnv7i6eqqgwpg06ac8dbz.png" alt="Canvas Tutorial" width="745" height="90"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Saving and Sending Sketches
&lt;/h2&gt;

&lt;p&gt;Once a player finishes drawing and clicks the &lt;strong&gt;Send Sketch&lt;/strong&gt; button, the image is retrieved from the Canvas using the &lt;code&gt;.get_image()&lt;/code&gt; method:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;sketch&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;canvas_1&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get_image&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This converts the sketch into a &lt;a href="https://anvil.works/docs/working-with-files/media?utm_source=crosspost:dev.to:/blog/guess-the-sketch-game#media-objects"&gt;Media object&lt;/a&gt;, which is then stored in a &lt;a href="https://anvil.works/docs/data-tables?utm_source=crosspost:dev.to:/blog/guess-the-sketch-game"&gt;Data Table&lt;/a&gt; for later retrieval.&lt;/p&gt;

&lt;p&gt;When a player submits a sketch, one of two things happens:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A new game is created, along with its first round (if the player is starting a new game).&lt;/li&gt;
&lt;li&gt;A new round is added to an existing game, which happens when a player joins an ongoing game and takes their turn.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Here’s how I handled both scenarios:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;sketch&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;canvas_1&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get_image&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="c1"&gt;# Add a round to an existing game
&lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;game_id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
  &lt;span class="n"&gt;anvil&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;server&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;call&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;add_game_round&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;game_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;sketch&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;sketch_name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="nf"&gt;navigate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;/invite/:id&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;params&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;id&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;game_id&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;

&lt;span class="c1"&gt;# Create a new game
&lt;/span&gt;&lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
  &lt;span class="n"&gt;game_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;anvil&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;server&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;call&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;start_game&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;sketch&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;sketch_name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="nf"&gt;navigate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;/invite/:id&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;params&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;id&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;game_id&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In both cases, a new game round is created and linked to the current game, whether the game is newly created or ongoing.&lt;/p&gt;

&lt;p&gt;With &lt;a href="https://anvil.works/docs/data-tables?utm_source=crosspost:dev.to:/blog/guess-the-sketch-game"&gt;Data Tables&lt;/a&gt;, creating a round is as simple as inserting a new row into the Rounds Table and adding the round ID to the corresponding game's &lt;code&gt;rounds&lt;/code&gt; column (which stores a list of round IDs for that game).&lt;/p&gt;

&lt;p&gt;Here’s how I create and link a round to an existing game:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="nd"&gt;@anvil.server.callable&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;require_user&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;add_game_round&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;game_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;image&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;sketch_name&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
  &lt;span class="c1"&gt;# Other game logic...
&lt;/span&gt;  &lt;span class="n"&gt;game&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;app_tables&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;game_table&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get_by_id&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;game_id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="nb"&gt;round&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;app_tables&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;rounds_table&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add_row&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;game_id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;game_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;image&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;image&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;owner&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;player&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;sketch_name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;sketch_name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;start_time&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;datetime&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;now&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
  &lt;span class="n"&gt;game&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;rounds&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;round&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
  &lt;span class="c1"&gt;# Other game logic... 
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Sending Invites
&lt;/h2&gt;

&lt;p&gt;Anvil has a built-in  &lt;a href="https://anvil.works/docs/email?utm_source=crosspost:dev.to:/blog/guess-the-sketch-game"&gt;Email Service&lt;/a&gt;, which makes sending invites as simple as a single function call. I used &lt;code&gt;anvil.email.send()&lt;/code&gt; to email friends a game invite with a preview of the sketch as an  &lt;a href="https://anvil.works/docs/email/attachments?utm_source=crosspost:dev.to:/blog/guess-the-sketch-game#using-inline-attachments"&gt;inline attachment&lt;/a&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;  &lt;span class="n"&gt;anvil&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;bcc&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;emails&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
    &lt;span class="n"&gt;from_address&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;player&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;email&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; 
    &lt;span class="n"&gt;subject&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;player&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;name&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; is inviting you to Guess the Sketch!&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;html&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;
      Hey,
      I just created this sketch:&amp;lt;br&amp;gt;
      &amp;lt;img src=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;cid:sketch&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;&amp;gt;&amp;lt;br&amp;gt;
      Think you can figure out what it is? Click this link to play: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;link&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; 
    &lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;inline_attachments&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;sketch&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;image&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Players receive this email with a preview of the sketch right in their inbox. Here’s how it looks:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1vuarvjrg1mda7qi0r2b.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1vuarvjrg1mda7qi0r2b.png" alt="Invite Email" width="800" height="508"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This makes it really easy for players to see the sketch before they click the link to play.&lt;/p&gt;




&lt;h2&gt;
  
  
  Managing Players and Scores
&lt;/h2&gt;

&lt;p&gt;To manage player authentication, I used Anvil’s &lt;a href="https://anvil.works/docs/users?utm_source=crosspost:dev.to:/blog/guess-the-sketch-game"&gt;Users Service&lt;/a&gt;, which automatically created a &lt;strong&gt;Users Table&lt;/strong&gt; that stored player details.&lt;/p&gt;

&lt;p&gt;With just one line, I could add a login Form:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;anvil&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;users&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;login_with_form&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This allows players to sign up and log in with their Google accounts, making it easy to track their progress across games. Each new user is automatically added as a row in the Users Table.&lt;/p&gt;

&lt;p&gt;At any point in the app, I can access the currently logged-in player by calling:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;player&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;anvil&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;users&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get_user&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Tracking Player Scores
&lt;/h3&gt;

&lt;p&gt;To track scores, I added a &lt;code&gt;points&lt;/code&gt; column to the automatically generated &lt;strong&gt;Users Table&lt;/strong&gt;, where I store the total points each player accumulates.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fynl7wag7d2rcmxeyhpeb.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fynl7wag7d2rcmxeyhpeb.png" alt="Users Table" width="800" height="367"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;For every point a player earns in a game, I update the player’s total score:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;player&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;anvil&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;users&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get_user&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="c1"&gt;# Other game logic...
&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;player&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;points&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;
      &lt;span class="n"&gt;player&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;points&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="n"&gt;points_gained&lt;/span&gt;
    &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
      &lt;span class="n"&gt;player&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;points&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;points_gained&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This ensures that scores remain updated and persistent across game sessions.&lt;/p&gt;




&lt;h2&gt;
  
  
  Publishing and Sharing
&lt;/h2&gt;

&lt;p&gt;Once everything was ready, publishing the game was just one click on the  &lt;a href="https://anvil.works/docs/deployment/environments?utm_source=crosspost:dev.to:/blog/guess-the-sketch-game"&gt;Publish button&lt;/a&gt; in the Anvil editor. I instantly got a public URL, that I could share with friends to start playing right away!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fd4m8wl12p5mv20ylnzts.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fd4m8wl12p5mv20ylnzts.gif" alt="Full Game Demo" width="1114" height="868"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Want to Build Your Own?
&lt;/h2&gt;

&lt;p&gt;These are just some of the highlights, but you can clone the full project and explore how it works yourself.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://anvil.works/build#clone:LBYMHJ3D5VHWUS3G=V2TWD2XDO3Z6MHCCXTEPXQVF" rel="noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fo74xkd1d2ganf56ftrnp.png" alt="Image description" width="608" height="140"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  More about Anvil
&lt;/h2&gt;

&lt;p&gt;If you're new here, welcome! &lt;a href="https://anvil.works/?utm_source=crosspost:dev.to:/blog/guess-the-sketch-game"&gt;Anvil&lt;/a&gt; is a platform for building full-stack web apps with nothing but Python. No need to wrestle with JS, HTML, CSS, Python, SQL and all their frameworks – just &lt;strong&gt;build it all in Python&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://anvil.works/build?utm_source=crosspost:dev.to:/blog/guess-the-sketch-game"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fow63l4svon8tal3uola3.png" alt="Sign up for Anvil" width="800" height="178"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>gamedev</category>
      <category>python</category>
      <category>anvil</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Making a Clicker Game with a Leaderboard</title>
      <dc:creator>Tony</dc:creator>
      <pubDate>Thu, 27 Mar 2025 11:07:38 +0000</pubDate>
      <link>https://dev.to/anvil/making-a-clicker-game-with-a-leaderboard-oa1</link>
      <guid>https://dev.to/anvil/making-a-clicker-game-with-a-leaderboard-oa1</guid>
      <description>&lt;h2&gt;
  
  
  Are you the Ultimate Clicker?
&lt;/h2&gt;

&lt;p&gt;Arguably, the web is built from small, often ridiculous ideas. Sometimes, you don't really feel like making the next Amazon or an internal tool to "promote synergy between stakeholders". Sometimes, you just get a fun little idea, and you want to shove that into your nearest internet pipe and share it with your friends.&lt;/p&gt;

&lt;p&gt;When I started using Anvil, I quickly realized I could use it for pretty much whatever I wanted to make, be it sleek and professional productivity-oriented tools, or, you know, &lt;strong&gt;a clicker game that my friends and I can compete in!&lt;/strong&gt; And, best of all, it could do it fast and without requiring poring over documentation for days on end.&lt;/p&gt;

&lt;p&gt;You can clone the finished app by clicking &lt;a href="https://anvil.works/build#clone:PPF6KC5YOFADVWXY%3dO4KHABTFR5VUVFKVMQC5DTZD" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The idea is super simple: have my friends set up an account, let them click on a button as many times as they can to earn points, display all my friends’ total points on a public leaderboard, and let their competitive spirit do the rest.&lt;/p&gt;

&lt;p&gt;Anvil made the process super quick and painless, you can easily knock this down in an afternoon. Let me walk you through how I did it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why I Chose Anvil
&lt;/h2&gt;

&lt;p&gt;For my app, I needed a tool that provided a traditional web app structure, complete with a user interface, client-server architecture, and ideally, the following features:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Support for &lt;a href="https://anvil.works/learn/tutorials/using-layouts-to-create-multi-page-app" rel="noopener noreferrer"&gt;&lt;strong&gt;multiple pages&lt;/strong&gt;&lt;/a&gt; and navigation between them&lt;/li&gt;
&lt;li&gt;Log-in system for &lt;a href="https://anvil.works/learn/tutorials/multi-user-apps" rel="noopener noreferrer"&gt;&lt;strong&gt;multiple users&lt;/strong&gt;&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;An &lt;a href="https://anvil.works/docs/data-tables" rel="noopener noreferrer"&gt;&lt;strong&gt;integrated database&lt;/strong&gt;&lt;/a&gt; for storing users’ points&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Spoiler alert: Anvil has all of those, among many more, and they’re super easy to set up. All I had to do was create a new app using the editor, use the &lt;a href="https://anvil.works/docs/editor/form-editor" rel="noopener noreferrer"&gt;drag-and-drop interface&lt;/a&gt; to build my navigation layout, include the &lt;a href="https://anvil.works/docs/users" rel="noopener noreferrer"&gt;log-in feature&lt;/a&gt; by literally just clicking on a couple of boxes, and it even automatically created an &lt;a href="https://anvil.works/docs/data-tables" rel="noopener noreferrer"&gt;integrated Data Table&lt;/a&gt; to store all the user information.&lt;/p&gt;

&lt;h2&gt;
  
  
  Building A User Interface
&lt;/h2&gt;

&lt;p&gt;Our UI should be pretty simple: one page to get a bunch of clicks in, and another to see ourselves climbing the leaderboard.&lt;/p&gt;

&lt;p&gt;I thus created two Forms based on the navigational &lt;a href="https://anvil.works/docs/ui/layouts" rel="noopener noreferrer"&gt;layout&lt;/a&gt; I had created prior:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A &lt;strong&gt;Clicker&lt;/strong&gt; Form, which only needed a simple button and would communicate with a "Leaderboard" Data Table, storing all users' scores.&lt;/li&gt;
&lt;li&gt;A &lt;strong&gt;Leaderboard&lt;/strong&gt; Form, with a data grid to display the app’s top 10 users with the most points.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcmf6jimksuwaqfwbpgth.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcmf6jimksuwaqfwbpgth.gif" alt="Image description" width="960" height="479"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;With a clear idea in mind, I hopped in the editor and designed my heart away. The drag-and-drop interface made it very easy to arrange the various components however I wanted.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzkyg5gzjmyub7p9xhy3f.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzkyg5gzjmyub7p9xhy3f.gif" alt="Image description" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Once that was done, it was time to program the behavior of the interface with some simple Python code.&lt;/p&gt;

&lt;h2&gt;
  
  
  Registering &amp;amp; Logging Users In
&lt;/h2&gt;

&lt;p&gt;I am a simple person. I do not know fancy HTML, JavaScript or CSS. That’s three whole languages, when most people only really know one. Thankfully, Anvil lets you create &lt;strong&gt;full-stack apps with nothing but Python&lt;/strong&gt;, so I can remain a simple person and still get my friends to ruthlessly compete against each other over who can click their mouse the most.&lt;/p&gt;

&lt;p&gt;The first thing I did was add a way for users to enter a username for the leaderboard. I wanted it to be so that when somebody logs in for the first time, an Alert pops up and prompts them for a username, which is then saved along with the rest of their user information in the “Users” Data Table.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F582pg49lysed879zwpjc.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F582pg49lysed879zwpjc.gif" alt="Image description" width="974" height="606"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;For this purpose, I created a new Form, that I named UserEdit, that would be shown upon login. I placed a Label asking the user for their username, and a TextBox for the user to type it in. I then made the content of the TextBox a &lt;a href="https://anvil.works/learn/tutorials/data-bindings" rel="noopener noreferrer"&gt;data binding&lt;/a&gt;, so I could easily use the input username in code.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fc1hzg1845guai3hv249e.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fc1hzg1845guai3hv249e.png" alt="Image description" width="800" height="305"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Within the &lt;a href="https://anvil.works/docs/ui/forms#the-startup-form" rel="noopener noreferrer"&gt;startup Form&lt;/a&gt;'s code, right after logging the user in, I have the server check if that user already has a username. If not, I &lt;a href="https://anvil.works/docs/client/alerts-and-notifications" rel="noopener noreferrer"&gt;display an Alert&lt;/a&gt; showing the UserEdit Form I had just created.&lt;/p&gt;

&lt;p&gt;Upon confirmation from the user, the UserEdit Form then returns the username that was entered, which is sent to the server and saved within the "Users" Data Table for the current user. Finally, a row for this new user is initialized within the "Leaderboard" Data Table with zero points.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# In Client code

login_with_form()
# Ask the server to check if the currently logged-in user has a name.
if not anvil.server.call('does_current_user_have_a_name'):
    # Open an Alert pop-up that prompts the user for their name.
    name = alert(UserEdit(), large=True, dismissible=False, buttons=None)
    # The obtained name is then sent to the server for user initialization.
    anvil.server.call('initialize_user', name)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# In Server code

@anvil.server.callable
def does_current_user_have_a_name():
  current_user = anvil.users.get_user()
  # Check that a user is currently logged in and, if so, that they have a non-empty username.
  return current_user is not None and current_user['username'] not in (None, '')

@anvil.server.callable
def initialize_user(name):
  current_user = anvil.users.get_user()
  # Add the gathered name to our user row.
  current_user.update(username=name)
  # Add a new row to the leaderboard Data Table, with our user in the user column and 0 in the points column.
  app_tables.leaderboard.add_row(user=current_user, points=0)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Displaying Data From Data Tables
&lt;/h2&gt;

&lt;p&gt;With the user side of the app setup, it was time to take care of the leaderboard.&lt;/p&gt;

&lt;p&gt;For this, I used Anvil's &lt;a href="https://anvil.works/docs/api/anvil#DataGrid" rel="noopener noreferrer"&gt;DataGrid&lt;/a&gt; to display rows of the "Leaderboard" database. I placed an instance of that component in my page and named it &lt;code&gt;top_10_panel&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;top_10_panel&lt;/code&gt; Data Grid component needed to communicate with the "Leaderboard" Data Table. I made the Leaderboard Form fetch the contents of the "Leaderboard" Data Table whenever shown, sort the rows by descending order of points, and set the 10 first entries to populate the DataGrid. Easy-peasy!&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# In Client code

def refresh_top_10_grid(self):
    top_10_clickers = anvil.server.call('get_top_10_clickers')
    # Set our DataGrid's contents to be the top 10 leaderboard rows.
    self.top_10_panel.items = top_10_clickers
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# In Server code

@anvil.server.callable
def get_top_10_clickers():
  # Create a list containing, for each user, a dictionary with their username and points.
  all_users = [
    {
      'username': row['user']['username'],
      'points': row['points']
    } for row in app_tables.leaderboard.search()
  ]
  # Sort our list based on a descending order of points.
  all_users.sort(key=lambda x: x['points'], reverse=True)
  # Reconstruct our sorted list by enumerating it and added a ranking to each user dictionary.
  ranked_users = [
    {
      'rank': i+1,
      'username': user_dict['username'],
      'points': user_dict['points'],
    } for i, user_dict in enumerate(all_users)
  ]
  # Only return the first 10 items of our ranked list.
  return ranked_users[:10]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Making Components Interactive With Events
&lt;/h2&gt;

&lt;p&gt;Finally, all I had to do was make the clicker button actually increase your score on each click. Anvil components can raise &lt;a href="https://anvil.works/docs/client/events" rel="noopener noreferrer"&gt;events&lt;/a&gt;, which code can react to, in response to user interaction.&lt;/p&gt;

&lt;p&gt;When Button components are clicked they raise a 'click' event, so all I had to do was create a handler function to run when a user clicks the button. This is easily done from the Object Palette, or the Properties Panel:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Funh3hzd9obcl77mwbl37.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Funh3hzd9obcl77mwbl37.gif" alt="Image description" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;With the event handler in place to detect button clicks, all that remained was writing the logic into the event handler.&lt;/p&gt;

&lt;p&gt;We want every click event raised by our button to increase a &lt;code&gt;local_points&lt;/code&gt; property of the Clicker Form, which is at first initialized by fetching the amount of points of the current user:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# In Client code

def on_clicker_clicked(self, **event_args):
    # This event is triggered whenever the clicker button is clicked.
    self.item['local_points'] += 1
    # Refresh our data bindings to make sure our components reflect the form's newly updated `item` property.
    self.refresh_data_bindings()
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Clicking the button should also start a &lt;a href="https://anvil.works/docs/ui/components/basic#timer" rel="noopener noreferrer"&gt;timer&lt;/a&gt;: when that timer reaches one second, a call is made to the server with the new amount of points to save, but each button click restarts the timer. This ensures that we don’t slow down the app with as many server calls as there were clicks, but instead only make the call once the user is done clicking.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# In Client code

def on_clicker_clicked(self, **event_args):
    # This event is triggered whenever the clicker button is clicked.
    self.item['local_points'] += 1
    # Refresh our data bindings to make sure our components reflect the form's newly updated `item` property.
    self.refresh_data_bindings()
    # Reset the timer if it is already started...
    if self.click_buffer_timer.interval != 0:
        self.click_buffer_timer.interval = 0
    # ... then start it up again from zero.
    self.click_buffer_timer.interval = 1

def click_buffer_timer_tick(self, **event_args):
    # This event is triggered whenever the timer component
    # reaches its set interval.
    # Reset and stop our timer.
    self.click_buffer_timer.interval = 0
    with anvil.server.no_loading_indicator:
      anvil.server.call('update_current_user_points', self.item['local_points'])
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# In Server code

@anvil.server.callable
def update_current_user_points(new_amount):
    current_user = anvil.users.get_user()
    app_tables.leaderboard.search(user=current_user)[0]['points'] = new_amount
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And that’s really all there is to it! All that was left to do was publish the app.&lt;/p&gt;

&lt;h2&gt;
  
  
  Publishing The App
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://anvil.works/docs/deployment-new-ide" rel="noopener noreferrer"&gt;Deployment&lt;/a&gt; is so easy I could do it in my sleep. In fact, I did! And, since you have no way of proving me wrong, you’re just going to have to accept that as a fact. Isn’t this fun?&lt;/p&gt;

&lt;p&gt;All it takes is literally two clicks, and you’ll receive a shareable URL to send your friends to use your app. That way, you can focus on, you know, making the app, rather than on how to deploy it.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2zv0q65runffzfsv3mnm.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2zv0q65runffzfsv3mnm.gif" alt="Image description" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And voilà! My game was then deployed and all I had to do was set my friends loose to compete for the title of Ultimate Clicker.&lt;/p&gt;

&lt;h2&gt;
  
  
  Want to learn more?
&lt;/h2&gt;

&lt;p&gt;If you want to dive right in and take a look at the clicker app from behind the scenes, you can clone the app by clicking right &lt;a href="https://anvil.works/build#clone:PPF6KC5YOFADVWXY%3dO4KHABTFR5VUVFKVMQC5DTZD" rel="noopener noreferrer"&gt;here&lt;/a&gt;, which will let you see how it was made in more detail!&lt;/p&gt;

&lt;p&gt;Alternatively, if you want to start on your own project, our online editor is free to use and requires no installation whatsoever. We have some great &lt;a href="https://anvil.works/learn/tutorials" rel="noopener noreferrer"&gt;step-by-step tutorials&lt;/a&gt;, and a bunch of fully-featured example apps like this &lt;a href="https://anvil.works/learn/examples/ticketing-system" rel="noopener noreferrer"&gt;ticketing system app&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Also, if you have questions or for any other reason feel like giving us a shout, you can find us in the &lt;a href="https://dev.to/forum"&gt;&lt;strong&gt;Anvil Community Forum&lt;/strong&gt;&lt;/a&gt;, it's always full of activity.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Introducing the Interactive Debugger in Anvil</title>
      <dc:creator>Love Otudor</dc:creator>
      <pubDate>Wed, 26 Feb 2025 09:47:49 +0000</pubDate>
      <link>https://dev.to/anvil/introducing-the-interactive-debugger-in-anvil-10kn</link>
      <guid>https://dev.to/anvil/introducing-the-interactive-debugger-in-anvil-10kn</guid>
      <description>&lt;h2&gt;
  
  
  Say Hello to the Interactive Debugger in Anvil
&lt;/h2&gt;

&lt;p&gt;We are very excited to announce the first release of &lt;strong&gt;the Interactive Debugger&lt;/strong&gt; in Anvil. Say goodbye to countless &lt;code&gt;print&lt;/code&gt; statements!&lt;/p&gt;

&lt;p&gt;With the Interactive Debugger, you can now pause your code as it executes, inspect variables, and gain deeper insights into what’s happening in your code—whether on the client or server side.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgjo3kcs35m3i2p9i79yq.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgjo3kcs35m3i2p9i79yq.gif" alt="Debugger Demo" width="1024" height="1024"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  What is the Interactive Debugger?
&lt;/h2&gt;

&lt;p&gt;The Interactive Debugger lets you:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Add breakpoints&lt;/strong&gt; to your code to pause execution at specific lines.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Inspect variables&lt;/strong&gt; and &lt;strong&gt;values&lt;/strong&gt; at runtime.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Debug&lt;/strong&gt; both &lt;strong&gt;client-side&lt;/strong&gt; and &lt;strong&gt;server-side code&lt;/strong&gt;, including &lt;strong&gt;background tasks&lt;/strong&gt; and &lt;strong&gt;HTTP endpoints&lt;/strong&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Getting started is simple:&lt;/strong&gt; Click in the gutter next to any executable line of code to add a breakpoint and then run your code. When this breakpoint is hit, the debugger pauses execution and opens the Debugger Window, where you can easily view and inspect all the variables in your code.&lt;/p&gt;




&lt;h2&gt;
  
  
  Get Deeper Insights into your Code in real time
&lt;/h2&gt;

&lt;p&gt;With the debugger, you can add and remove breakpoints even while execution is paused, allowing you to adjust your debugging strategy as needed. The debugger toolbar gives you complete control to resume, restart, or stop execution, step over breakpoints, and step into or out of functions effortlessly. This makes it easy to navigate through your code seamlessly and gain a deeper understanding of its behaviour.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fho05ikm5nko21y3v1162.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fho05ikm5nko21y3v1162.gif" alt="Add and remove breakpoints" width="1512" height="819"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Easy Debugging Across Client and Server Code
&lt;/h2&gt;

&lt;p&gt;Anvil’s debugger allows you to step into server code directly from client code. For example, you can start in your client-side form code and step directly into your server code while showing the entire call stack on the browser frame.&lt;/p&gt;

&lt;p&gt;Here is a demo illustrating how you can step into server code from client code seamlessly:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F77ho3wq2ct1iuxfk7wqh.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F77ho3wq2ct1iuxfk7wqh.gif" alt="Step into server code" width="760" height="579"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Debug Background Tasks and HTTP Endpoints
&lt;/h2&gt;

&lt;p&gt;Debugging background tasks and HTTP endpoints in server modules has never been easier. By adding breakpoints to your background tasks or endpoint calls, you can pause execution, inspect variables, and diagnose issues with accuracy and confidence.&lt;/p&gt;




&lt;h2&gt;
  
  
  Availability
&lt;/h2&gt;

&lt;p&gt;The debugger is available to everyone!&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Free users can use Anvil’s debugger only on the client-side (Form) code.&lt;/li&gt;
&lt;li&gt;Client-side and server-side debugging is available on a Business Plan or higher.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  What’s Next?
&lt;/h2&gt;

&lt;p&gt;This is just the first version of the Anvil Debugger and we have plans for more interesting features, so stay tuned! In the meantime, we would love to hear your feedback! Try out the debugger today and let us know how it works for you.&lt;/p&gt;

&lt;p&gt;For a deep dive into debugging with the interactive debugger in Anvil, as well as additional tools to enhance your debugging process, check out our &lt;a href="https://anvil.works/docs/debugger?utm_source=crosspost:dev.to:/blog/announcing-the-debugger"&gt;Debugging Documentation&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Happy debugging!&lt;/p&gt;




&lt;h2&gt;
  
  
  More about Anvil
&lt;/h2&gt;

&lt;p&gt;If you're new here, welcome! &lt;a href="https://anvil.works?utm_source=crosspost:dev.to:/blog/announcing-the-debugger"&gt;Anvil&lt;/a&gt; is a platform for building full-stack web apps with nothing but Python. No need to wrestle with JS, HTML, CSS, Python, SQL and all their frameworks – just &lt;strong&gt;build it all in Python&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://anvil.works?utm_source=crosspost:dev.to:/blog/announcing-the-debugger"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fow63l4svon8tal3uola3.png" alt="Sign up for Anvil" width="800" height="178"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>programming</category>
      <category>python</category>
      <category>webapp</category>
    </item>
  </channel>
</rss>
