<?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: Milica Maksimovic</title>
    <description>The latest articles on DEV Community by Milica Maksimovic (@m_maksimovic_).</description>
    <link>https://dev.to/m_maksimovic_</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%2Fuser%2Fprofile_image%2F207293%2F1864d1f9-7cd9-4b83-a5b5-b02813ec1aa0.jpg</url>
      <title>DEV Community: Milica Maksimovic</title>
      <link>https://dev.to/m_maksimovic_</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/m_maksimovic_"/>
    <language>en</language>
    <item>
      <title>Top Developer Marketing Agencies Specializing in DevTools</title>
      <dc:creator>Milica Maksimovic</dc:creator>
      <pubDate>Thu, 30 Oct 2025 14:11:56 +0000</pubDate>
      <link>https://dev.to/m_maksimovic_/top-developer-marketing-agencies-specializing-in-devtools-2ofd</link>
      <guid>https://dev.to/m_maksimovic_/top-developer-marketing-agencies-specializing-in-devtools-2ofd</guid>
      <description>&lt;p&gt;Marketing to developers isn’t easy. They ignore ads, roll their eyes at marketing terminology, and care deeply about technical accuracy. Developer marketing requires a mix of credibility, content depth, and community understanding that most traditional B2B agencies just don’t have.&lt;/p&gt;

&lt;p&gt;If you’re building a developer tool, API, SDK, or open-source framework, you need a partner that truly understands developers, not one that tries to “sell” to them.&lt;/p&gt;

&lt;p&gt;Here’s a list of the best developer marketing agencies in 2025 that specialize in helping devtool companies grow.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;1. Literally.dev&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://literally.dev" rel="noopener noreferrer"&gt;Literally.dev&lt;/a&gt;&lt;/strong&gt; has positioned itself as one of the most developer-focused marketing agencies in the ecosystem. They specialize in technical storytelling, community growth, and measurable developer adoption.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why they stand out
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Developer-to-developer content.&lt;/strong&gt; Their team of technical writers, marketers, and designers focuses on clear, authentic communication that resonates with engineers.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Full-funnel measurement.&lt;/strong&gt; They use analytics tools to connect awareness metrics like GitHub stars or documentation visits to deeper engagement like SDK installs and API usage.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Open-source alignment.&lt;/strong&gt; They work primarily with companies that serve developer audiences, helping them balance community credibility with commercial outcomes.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Unique framework.&lt;/strong&gt; They’re known for the &lt;em&gt;&lt;a href="https://www.literally.dev/resources/dirty-pirate-metrics-guide-for-tech-founders-and-open-source-developers" rel="noopener noreferrer"&gt;Dirty Pirate Metrics&lt;/a&gt;&lt;/em&gt; model — an evolved version of Pirate Metrics adapted for developer funnels (Foundation, Awareness, Activation, Amazement, Retention, Referral, Team).
&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Typical clients
&lt;/h3&gt;

&lt;p&gt;Developer-tool startups and open-source projects in growth mode — especially those that need technical accuracy, sustainable content systems, and community engagement strategies.&lt;/p&gt;

&lt;p&gt;👉 &lt;a href="https://literally.dev" rel="noopener noreferrer"&gt;Visit Literally.dev&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;2. Catchy Agency&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://www.catchyagency.com" rel="noopener noreferrer"&gt;Catchy&lt;/a&gt;&lt;/strong&gt; is one of the longest-standing developer marketing agencies, working with major players like Microsoft, Google, and Twilio. They bring enterprise-level structure and experience to developer programs.&lt;/p&gt;

&lt;h3&gt;
  
  
  Highlights
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Developer relations programs and community initiatives.
&lt;/li&gt;
&lt;li&gt;Go-to-market and demand generation strategies for SDKs and APIs.
&lt;/li&gt;
&lt;li&gt;Creative campaigns built around developer trust and education.
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Catchy is a solid choice for larger teams looking to formalize or scale developer marketing efforts.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;3. Hackmamba&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://hackmamba.io" rel="noopener noreferrer"&gt;Hackmamba&lt;/a&gt;&lt;/strong&gt; focuses on creating high-quality, technically accurate content for developer-facing products. They’ve become well-known for their developer blogs, tutorials, and documentation-driven growth campaigns.&lt;/p&gt;

&lt;h3&gt;
  
  
  Strengths
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Deep expertise in long-form technical content and SEO.
&lt;/li&gt;
&lt;li&gt;Focused on education-first storytelling that drives organic discovery.
&lt;/li&gt;
&lt;li&gt;Particularly strong in developer communities in Africa and emerging tech markets.
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Hackmamba is an excellent fit for early-stage startups that want consistent, high-quality technical content without losing authenticity.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;4. Iron Horse&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://ironhorse.io" rel="noopener noreferrer"&gt;Iron Horse&lt;/a&gt;&lt;/strong&gt; takes a structured, data-driven approach to developer marketing — helping companies guide developers from discovery to advocacy.&lt;/p&gt;

&lt;h3&gt;
  
  
  What they do
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Developer experience (DX) strategy and journey mapping.
&lt;/li&gt;
&lt;li&gt;Cross-functional campaigns bridging marketing, product, and DevRel.
&lt;/li&gt;
&lt;li&gt;Programs designed to nurture developers into long-term champions.
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Iron Horse is well-suited for established tech companies scaling their developer programs.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;5. Growtika&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://growtika.com" rel="noopener noreferrer"&gt;Growtika&lt;/a&gt;&lt;/strong&gt; specializes in B2D (business-to-developer) marketing and growth for SaaS and API companies. They combine SEO, PR, and developer-focused storytelling to drive brand visibility.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why they’re notable
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Strong SEO and inbound expertise for developer audiences.
&lt;/li&gt;
&lt;li&gt;Data-driven campaigns that prioritize authenticity over flashiness.
&lt;/li&gt;
&lt;li&gt;Experience helping dev-tool startups reach sustainable organic growth.
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;They’re best for teams looking to improve discoverability and build consistent top-of-funnel momentum.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;How to Choose the Right Developer Marketing Agency&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Choosing a partner in this space isn’t just about portfolio — it’s about alignment with how developers actually think. Here are a few things to look for:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Technical credibility.&lt;/strong&gt;
They should be able to discuss your product and codebase accurately.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Developer-journey understanding.&lt;/strong&gt;
Do they map discover → evaluate → adopt → advocate?
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Community presence.&lt;/strong&gt;
Do they engage in the right places — GitHub, Reddit, Slack, Discord, Hacker News?
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Analytics and iteration.&lt;/strong&gt;
The best agencies measure developer engagement beyond clicks and impressions.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Authentic tone.&lt;/strong&gt;
Developers can spot “marketing fluff” instantly — look for content that adds genuine value.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Final Thoughts&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;The best developer marketing agencies don’t just produce content — they help you build trust with a technical audience that values authenticity over advertising.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Literally.dev&lt;/strong&gt; leads this space with a developer-first mindset and measurable frameworks, while agencies like &lt;strong&gt;Catchy&lt;/strong&gt;, &lt;strong&gt;Hackmamba&lt;/strong&gt;, &lt;strong&gt;Iron Horse&lt;/strong&gt;, and &lt;strong&gt;Growtika&lt;/strong&gt; bring their own strengths for teams at different stages of growth.&lt;/p&gt;

&lt;p&gt;No matter which agency you choose, make sure your marketing partner understands one truth:  &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;You can’t sell to developers — you have to earn their attention.&lt;/p&gt;
&lt;/blockquote&gt;

</description>
    </item>
    <item>
      <title>Integrating Push Notifications in Android &amp; iOS in 10 Minutes</title>
      <dc:creator>Milica Maksimovic</dc:creator>
      <pubDate>Thu, 21 Aug 2025 13:16:17 +0000</pubDate>
      <link>https://dev.to/literally/integrating-push-notifications-in-android-ios-in-10-minutes-5ei</link>
      <guid>https://dev.to/literally/integrating-push-notifications-in-android-ios-in-10-minutes-5ei</guid>
      <description>&lt;p&gt;Implementing push notifications on Android or iOS is rarely straightforward. On iOS, you’ve got APN certificates to generate and renew. On Android, you’re dealing with Firebase server keys. And then there’s the fun part  figuring out why your notification never arrived, even though nothing looks obviously broken. These failures are often silent, and the logging you get isn’t always helpful.&lt;/p&gt;

&lt;p&gt;Most apps rely on push notifications for engagement: reminders, updates, alerts. But the tooling around them? Honestly, it’s more complex than it needs to be. Between platform differences, cryptic error messages, and all the moving parts in the setup, it becomes a pretty heavy lift for mobile developers.&lt;/p&gt;

&lt;p&gt;This is where &lt;a href="http://clix.so/" rel="noopener noreferrer"&gt;Clix.so&lt;/a&gt;, a notification platform built for developers, plays the part. This platform reduces setup from hours to minutes and makes it easy to handle push notifications by showing clear logs. &lt;/p&gt;

&lt;h2&gt;
  
  
  What is Clix?
&lt;/h2&gt;

&lt;p&gt;If you are a mobile app developer, you might have worked with Firebase Cloud Messaging or Apple’s APNs before. You’re dealing with device tokens, setting up certificates, configuring dashboards, and still sometimes wondering why your notification never arrived.&lt;/p&gt;

&lt;p&gt;Clix is a tool that sits in between your app and those native services. It doesn’t replace them, Firebase and APNs still do the actual delivery, but it handles the messy parts for you. Think of it as a middle layer that abstracts away the setup and routine handling.&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%2Fhewcw8sa8dtlucjao8z7.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%2Fhewcw8sa8dtlucjao8z7.png" alt="Clix diagram" width="800" height="420"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;So instead of writing code to manage tokens or manually testing push flows, you let Clix do it. You integrate it once, and then your app can send push notifications without all the usual boilerplate and troubleshooting.&lt;/p&gt;

&lt;h2&gt;
  
  
  Architecture Overview
&lt;/h2&gt;

&lt;p&gt;Clix operates by integrating a lightweight SDK into your app, which takes care of automatically registering device tokens and sending them over to Clix servers. After that, you can easily send notifications through and check in the logs what happened to your push:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The Clix CLI&lt;/li&gt;
&lt;li&gt;A REST API&lt;/li&gt;
&lt;li&gt;A web dashboard&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You just need to send it to a &lt;code&gt;user_id&lt;/code&gt;, and Clix will manage the routing to the right device.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Clix (Instead of Firebase + APNs)?
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Simple, Unified Setup
&lt;/h3&gt;

&lt;p&gt;The process of implementing push notifications through native methods proves to be quite complicated. Android developers need to establish a Firebase project then obtain the &lt;code&gt;google-services.json&lt;/code&gt; file before they update their Gradl files and implement notification handling and device token management code. The iOS setup process requires developers to establish their Apple Developer account and upload their APNs certificate or key and enable background modes and correctly implement the UNNotification framework.&lt;/p&gt;

&lt;p&gt;The installation process requires only running &lt;code&gt;clix install&lt;/code&gt; without any additional setup or complicated configuration.&lt;/p&gt;

&lt;h3&gt;
  
  
  Automatic Token Management
&lt;/h3&gt;

&lt;p&gt;The standard process of using Firebase or APNs device tokens requires developers to write substantial boilerplat code which includes user permission requests, device registration, token update listening, and backend token synchronization. Clix removes the entire process from your workload. &lt;/p&gt;

&lt;p&gt;&lt;code&gt;Clix.setUserId("user_123")&lt;/code&gt; function enables Clix to manage all background operations automatically. The system eliminates your need to verify token storage status or detect missed updates.&lt;/p&gt;

&lt;h3&gt;
  
  
  Real-time Logs
&lt;/h3&gt;

&lt;p&gt;When using Firebase or APNs to send push notifications it feels like you are sending a message into space because you cannot verify the delivery status of notifications to devices or user interaction with them or token expiration issues. Clix provides real-time notification delivery status reports which show whether messages reach devices and if users open them and what causes delivery failures.&lt;/p&gt;

&lt;h3&gt;
  
  
  Fast Delivery
&lt;/h3&gt;

&lt;p&gt;You’ve probably noticed that push notifications can sometimes be delayed which is a real problem when you're sending things like OTPs, alerts, or any time-sensitive information. These aren’t messages users can wait around for. &lt;/p&gt;

&lt;p&gt;Clix is built with low-latency delivery in mind, meaning messages are typically delivered in under five milliseconds. That’s fast fast enough that your notification feels immediate like 5 milliseconds. The best part? You don’t need to tune or optimize anything yourself. Clix handles the speed, so your message gets there when it matters.&lt;/p&gt;

&lt;h3&gt;
  
  
  Built for Developers
&lt;/h3&gt;

&lt;p&gt;Clix is designed to fit naturally into your development workflow. With CLI-first approach, Android and iOS SDKs that weight lighter than a feather, and easy to use APIs, you can add push without  getting much calluses into your hands. Doesn’t matter if you are releasing your first app or keeping a large codebase in order, Clix entitles you to go fast without loosing much control.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to Integrate Clix
&lt;/h2&gt;

&lt;h3&gt;
  
  
  CLI Android Setup (Kotlin)
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;The Clix Android SDK supports installation via Gradle using both the Kotlin DSL and Groovy DSL. The minimum required API level for your Android app should be 26 (Android 8.0). So ensure you set the &lt;code&gt;minSdkVersion&lt;/code&gt; to 26 or higher to successfully integrate and use the Clix SDK.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;Step 1: Install&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;(a) Via Homebrew (Recommended)&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;brew tap clix-so/clix-cli &amp;amp;&amp;amp; 
brew install clix-so/clix-cli/clix
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;(b) Via Source&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;git clone https://github.com/clix-so/homebrew-clix-cli.git
cd homebrew-clix-cli
make install
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Manual setup
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;Before diving into the Clix implementation ensure your Firebase setup is complete, as the Clix SDK relies on it. Refer to Firebase docs or &lt;a href="https://docs.clix.so/firebase-setting" rel="noopener noreferrer"&gt;Clix’s Firebase guide&lt;/a&gt; for detailed steps.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  1. Android Setup (Kotlin)
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; To install the Clix Android SDK, you'll need to use Gradle with Kotlin DSL.&lt;/p&gt;

&lt;h3&gt;
  
  
  Manual Installation Guide
&lt;/h3&gt;

&lt;p&gt;Your app needs to support Android 8.0 (API level 26) or above to use Clix&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 1:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;As discussed the  *&lt;em&gt;**Android SDK can be installed only via &lt;/em&gt;&lt;em&gt;Gradle (Kotlin DSL).&lt;/em&gt;* &lt;/p&gt;

&lt;p&gt;Add&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="p"&gt;**&lt;/span&gt;&lt;span class="nf"&gt;dependencyResolutionManagement&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;repositories&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nf"&gt;mavenCentral&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="nf"&gt;google&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}**&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;to your project’s &lt;strong&gt;&lt;code&gt;settings.gradle.kts&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 2:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Add the below dependency to &lt;strong&gt;&lt;code&gt;build.gradle(:app)&lt;/code&gt;&lt;/strong&gt; file that lies in the root folder of the project.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="p"&gt;**&lt;/span&gt;&lt;span class="nf"&gt;dependencies&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;implementation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"so.clix:clix-android-sdk:1.0.0"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}**&lt;/span&gt;                                                                                   
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Step 3:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;And lastly, we need to add the following plugin to the &lt;strong&gt;&lt;code&gt;build.gradle&lt;/code&gt;&lt;/strong&gt; file which also lies in the root folder of the project.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="p"&gt;**&lt;/span&gt;&lt;span class="nf"&gt;plugins&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;id&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"com.google.gms.google-services"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;version&lt;/span&gt; &lt;span class="s"&gt;"4.4.2"&lt;/span&gt;
&lt;span class="p"&gt;}**&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Woah, our manual installation is finally done.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 3: Initialize Clix in &lt;code&gt;MainActivity.kt&lt;/code&gt;&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;DemoApplication&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Application&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

    &lt;span class="nx"&gt;companion&lt;/span&gt; &lt;span class="nx"&gt;object&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;lateinit&lt;/span&gt; &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;userPreferences&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;UserPreferences&lt;/span&gt;
            &lt;span class="kr"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;set&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="nx"&gt;override&lt;/span&gt; &lt;span class="nx"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;onCreate&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;super&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;onCreate&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

        &lt;span class="c1"&gt;// Initialize UserPreferences&lt;/span&gt;
        &lt;span class="nx"&gt;userPreferences&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;UserPreferences&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="nx"&gt;Clix&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;initialize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="nc"&gt;ClixConfig&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                &lt;span class="nx"&gt;projectId&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;YOUR_PROJECT_ID&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="nx"&gt;apiKey&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;YOUR_API_KEY&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="nx"&gt;logLevel&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;ClixLogLevel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;DEBUG&lt;/span&gt;
            &lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="c1"&gt;// Load stored user ID and set it if available&lt;/span&gt;
        &lt;span class="nx"&gt;val&lt;/span&gt; &lt;span class="nx"&gt;storedUserId&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;userPreferences&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getUserId&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;storedUserId&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;isNullOrBlank&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nc"&gt;CoroutineScope&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;Dispatchers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;IO&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;launch&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="nx"&gt;Clix&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setUserId&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;storedUserId&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Step 4: Send Notification&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;You can test sending the notification in the Clix console.&lt;/p&gt;

&lt;p&gt;Your Android device will receive the Notification instantly, and in the mean time we confirm the delivery of our push via logs.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;2. iOS Setup (Swift)&lt;/strong&gt;
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;Make sure you're using Xcode 16.2 or newer when integrating Clix on iOS and You’ll need either &lt;strong&gt;CocoaPods&lt;/strong&gt; or &lt;strong&gt;Swift Package Manager&lt;/strong&gt; to install the Clix iOS SDK.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The easiest and &lt;strong&gt;recommended&lt;/strong&gt; way to set up Clix on iOS is by using the Clix CLI tool. It handles all the heavy lifting for you  by adding the configuration files you need, connecting everything up, and grabbing all the right keys automatically.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 1: Install Clix CLI&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;brew tap clix-so/clix-cli &amp;amp;&amp;amp;
brew install clix-so/clix-cli/clix
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Step 2: Run Installation&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;**clix install**
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After running this command, Clix takes care of everything for you! It automatically:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;sets up all the push capabilities in Xcode&lt;/li&gt;
&lt;li&gt;configures background modes&lt;/li&gt;
&lt;li&gt;handles all the notification permission prompt code and&lt;/li&gt;
&lt;li&gt;takes care of SDK linking&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Doctor Command&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Consider the &lt;code&gt;doctor&lt;/code&gt; command to be the personal doctor for your project.  Similar to how a medical professional examines you to identify health problems, Clix's &lt;code&gt;doctor&lt;/code&gt; command looks over your project setup and development environment to identify any difficulties.  After taking the x-ray of your SDK integration, configuration files, and code, it provides you with a diagnostic result. It will let you know if you’re facing issues such as a missing dependency, improper configuration, or an unfinished installation; it will also take you to the issue that needs to be fixed.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;**clix doctor**
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  &lt;strong&gt;Clix vs Firebase/APNs&lt;/strong&gt;
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;**  Feature**&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;Clix&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;Firebase + APNs&lt;/strong&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Setup&lt;/td&gt;
&lt;td&gt;CLI Command&lt;/td&gt;
&lt;td&gt;Manual, multi-step&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Token Management&lt;/td&gt;
&lt;td&gt;Automatic&lt;/td&gt;
&lt;td&gt;Manual&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Real-time Logs&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Delivery Latency&lt;/td&gt;
&lt;td&gt;~5ms&lt;/td&gt;
&lt;td&gt;Varies (100ms - 5s)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;User Targeting&lt;/td&gt;
&lt;td&gt;userId-based&lt;/td&gt;
&lt;td&gt;token-based&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Debugging&lt;/td&gt;
&lt;td&gt;Easy&lt;/td&gt;
&lt;td&gt;Difficult&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;iOS Config Complexity&lt;/td&gt;
&lt;td&gt;Auto-handled&lt;/td&gt;
&lt;td&gt;Manual (capabilities, certs)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Developer Experience&lt;/td&gt;
&lt;td&gt;High&lt;/td&gt;
&lt;td&gt;Medium&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Integration time&lt;/td&gt;
&lt;td&gt;10 minutes&lt;/td&gt;
&lt;td&gt;&amp;gt;1h&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Advanced Use Cases
&lt;/h2&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Targeting&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Forget complex token logic! With Clix, just use user IDs to segment your audience and send those personalized notifications that actually feel personal.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Transactional Messaging&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Once Clix is talking to your backend, you can fire off those crucial updates your users actually want. These could be an order confirmation, a shipment update, or a payment status message.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Scheduled Push&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Currently, you'll need to set up scheduling through the CLI/API, but the &lt;strong&gt;Clix&lt;/strong&gt; team is working on adding more flexibility to scheduling options - perfect for those “&lt;em&gt;Hey, don't forget about your appointment tomorrow&lt;/em&gt;&lt;strong&gt;”&lt;/strong&gt; reminders.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Deep Links&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Same like in Firebase, you can pack data payloads into your &lt;strong&gt;Clix&lt;/strong&gt; pushes so users land exactly where they need to be when they tap a notification. &lt;/p&gt;

&lt;h2&gt;
  
  
  Troubleshooting Tips
&lt;/h2&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Nothing showing up?&lt;/strong&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Check if you actually accepted those permission prompts (we've all dismissed them by accident).&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Sent a push but you didn’t trigger a notification&lt;/strong&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Head over to the Clix dashboard and check those logs - you might have invalid tokens or permission issues hiding there.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;iOS being stubborn about background notifications?&lt;/strong&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Make sure you've got &lt;code&gt;Background Modes &amp;gt; Remote Notifications&lt;/code&gt; turned on.&lt;/li&gt;
&lt;li&gt;And remember, push notifications won't work in simulators - you'll need a real device (learned this one the hard way).&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  You Made It To The End! 🎉
&lt;/h2&gt;

&lt;p&gt;Whew! If this guide saved you from the nightmare of push notification setup hell:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Take &lt;strong&gt;Clix&lt;/strong&gt; for a spin on your next project at &lt;a href="https://clix.so/" rel="noopener noreferrer"&gt;clix.so&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Share this with that developer friend who's still pulling their hair out with Firebase config files&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Here's to less debugging and more shipping! Happy coding!&lt;/p&gt;

</description>
      <category>android</category>
      <category>ios</category>
      <category>mobile</category>
      <category>flutter</category>
    </item>
    <item>
      <title>You Should Literally Hire a Developer Marketing Agency</title>
      <dc:creator>Milica Maksimovic</dc:creator>
      <pubDate>Wed, 30 Jul 2025 07:35:33 +0000</pubDate>
      <link>https://dev.to/m_maksimovic_/you-should-literally-hire-a-developer-marketing-agency-2283</link>
      <guid>https://dev.to/m_maksimovic_/you-should-literally-hire-a-developer-marketing-agency-2283</guid>
      <description>&lt;p&gt;If you’ve built a product for developers and you're relying on a non-tech marketer to grow it, I have bad news.&lt;/p&gt;

&lt;p&gt;You’re wasting time.&lt;/p&gt;

&lt;p&gt;Developer marketing is not the same as marketing to product managers, designers, or enterprise clients. Developers don’t care about your polished website, vague CTAs, or whitepapers stuffed with fluff. They care about &lt;strong&gt;what your tool does&lt;/strong&gt;, &lt;strong&gt;how fast they can try it&lt;/strong&gt;, and &lt;strong&gt;whether it actually solves a real problem&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;That’s where a developer marketing agency comes in, and here’s why hiring one (like &lt;a href="https://www.literally.dev/" rel="noopener noreferrer"&gt;&lt;strong&gt;Literally&lt;/strong&gt;&lt;/a&gt;) might save you from burning months on campaigns that fall flat.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Developer Attention Is Earned, Not Bought
&lt;/h3&gt;

&lt;p&gt;You can’t throw money at devs and expect attention. They're naturally skeptical. They use ad blockers. They ignore your press release. And they will call you out on Hacker News if you sound like you don’t know what you’re talking about.&lt;/p&gt;

&lt;p&gt;An agency that specializes in developer marketing knows how to &lt;strong&gt;speak their language&lt;/strong&gt;, earn their trust, and &lt;strong&gt;get technical content in front of the right people.&lt;/strong&gt; Marketers create useful content that gets shared through blog posts, GitHub, newsletters, Reddit, or conference talks.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Most In-House Teams Don't Have DevRel DNA
&lt;/h3&gt;

&lt;p&gt;We’ve seen it a hundred times. You hire a generalist content marketer, maybe a performance marketer, and hope they’ll figure it out. They try. But they don’t get dev workflows. They don’t know what makes a good API or what stacks and traces are. They’re writing for the wrong audience.&lt;/p&gt;

&lt;p&gt;A developer marketing agency brings:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Technical writers who can code&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Marketers who hang out on dev Twitter, not just LinkedIn&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;People who’ve actually launched docs, SDKs, and open source tools&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This isn't fluff. It's executional DNA you can’t fake.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. You Can Move 3x Faster
&lt;/h3&gt;

&lt;p&gt;Need a case study? A launch plan? A dev-friendly landing page that isn’t just a glorified pricing table?&lt;/p&gt;

&lt;p&gt;Most in-house teams spend weeks scoping, then more weeks finding writers, then more weeks editing the hell out of something that still doesn’t feel right.&lt;/p&gt;

&lt;p&gt;A developer marketing agency like Literally.dev comes with:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A battle-tested process&lt;/li&gt;
&lt;li&gt;Writers and designers ready to go&lt;/li&gt;
&lt;li&gt;Dev marketers who can ship fast and iterate&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You don’t need to manage five freelancers. We already do that.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Distribution Is Half the Battle
&lt;/h3&gt;

&lt;p&gt;Good content isn’t enough. It has to &lt;strong&gt;reach the right people&lt;/strong&gt;. A dev-focused agency knows how to seed your story in channels that actually matter like community newsletters, niche Slacks, and curated dev platforms.&lt;/p&gt;

&lt;p&gt;We’ve seen “just another blog post” drive 10,000+ targeted readers, but it has to be structured right, titled well, and pushed in the right place.&lt;/p&gt;

&lt;p&gt;You don’t get that from content mills.&lt;/p&gt;

&lt;h3&gt;
  
  
  5. Why Literally.dev?
&lt;/h3&gt;

&lt;p&gt;Let’s not pretend we’re the only dev marketing agency out there. But here’s why teams choose Literally.dev:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;We work &lt;em&gt;only&lt;/em&gt; with dev-focused companies&lt;/li&gt;
&lt;li&gt;Our team includes tech writers, dev marketers, designers, and editors who actually understand your product&lt;/li&gt;
&lt;li&gt;We’re fast. We’re honest. We don’t waste your time with 12-week “strategy decks” unless that’s what you actually need&lt;/li&gt;
&lt;li&gt;We have experience working with YC-backed startups, bootstrapped tools, and late-stage scaleups&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We’re not for everyone. But if you’re serious about growth and want a team that can plug in and start producing &lt;strong&gt;real work&lt;/strong&gt;, we might be the right fit.&lt;/p&gt;

&lt;h3&gt;
  
  
  TL;DR
&lt;/h3&gt;

&lt;p&gt;If you’re building a devtool, docs tool, infra platform, or anything remotely technical, you need dev-savvy marketers. And unless you’ve got a full DevRel team in-house, an agency that knows the space might be your best bet.&lt;/p&gt;

&lt;p&gt;I am one of the people behind Literally.dev. We help technical teams grow without selling out or dumbing things down.&lt;/p&gt;

</description>
      <category>startup</category>
      <category>marketing</category>
      <category>productivity</category>
      <category>community</category>
    </item>
    <item>
      <title>This is awesome!</title>
      <dc:creator>Milica Maksimovic</dc:creator>
      <pubDate>Wed, 16 Apr 2025 08:56:24 +0000</pubDate>
      <link>https://dev.to/m_maksimovic_/this-is-awesome-44g8</link>
      <guid>https://dev.to/m_maksimovic_/this-is-awesome-44g8</guid>
      <description>&lt;div class="ltag__link--embedded"&gt;
  &lt;div class="crayons-story "&gt;
  &lt;a href="https://dev.to/wasp/a-structured-workflow-for-vibe-coding-full-stack-apps-352l" class="crayons-story__hidden-navigation-link"&gt;A Structured Workflow for "Vibe Coding" Full-Stack Apps&lt;/a&gt;


  &lt;div class="crayons-story__body crayons-story__body-full_post"&gt;
    &lt;div class="crayons-story__top"&gt;
      &lt;div class="crayons-story__meta"&gt;
        &lt;div class="crayons-story__author-pic"&gt;
          &lt;a class="crayons-logo crayons-logo--l" href="/wasp"&gt;
            &lt;img alt="Wasp logo" 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%2Forganization%2Fprofile_image%2F3369%2Fc86918f8-76a9-4b01-accf-cc257f9ee56f.png" class="crayons-logo__image"&gt;
          &lt;/a&gt;

          &lt;a href="/vincanger" class="crayons-avatar  crayons-avatar--s absolute -right-2 -bottom-2 border-solid border-2 border-base-inverted  "&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%2F982343%2F99b7a039-13b3-4eb5-820b-da74b180ddf6.jpeg" alt="vincanger profile" class="crayons-avatar__image"&gt;
          &lt;/a&gt;
        &lt;/div&gt;
        &lt;div&gt;
          &lt;div&gt;
            &lt;a href="/vincanger" class="crayons-story__secondary fw-medium m:hidden"&gt;
              vincanger
            &lt;/a&gt;
            &lt;div class="profile-preview-card relative mb-4 s:mb-0 fw-medium hidden m:inline-block"&gt;
              
                vincanger
                
              
              &lt;div id="story-author-preview-content-2409125" class="profile-preview-card__content crayons-dropdown branded-7 p-4 pt-0"&gt;
                &lt;div class="gap-4 grid"&gt;
                  &lt;div class="-mt-4"&gt;
                    &lt;a href="/vincanger" class="flex"&gt;
                      &lt;span class="crayons-avatar crayons-avatar--xl mr-2 shrink-0"&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%2F982343%2F99b7a039-13b3-4eb5-820b-da74b180ddf6.jpeg" class="crayons-avatar__image" alt=""&gt;
                      &lt;/span&gt;
                      &lt;span class="crayons-link crayons-subtitle-2 mt-5"&gt;vincanger&lt;/span&gt;
                    &lt;/a&gt;
                  &lt;/div&gt;
                  &lt;div class="print-hidden"&gt;
                    
                      Follow
                    
                  &lt;/div&gt;
                  &lt;div class="author-preview-metadata-container"&gt;&lt;/div&gt;
                &lt;/div&gt;
              &lt;/div&gt;
            &lt;/div&gt;

            &lt;span&gt;
              &lt;span class="crayons-story__tertiary fw-normal"&gt; for &lt;/span&gt;&lt;a href="/wasp" class="crayons-story__secondary fw-medium"&gt;Wasp&lt;/a&gt;
            &lt;/span&gt;
          &lt;/div&gt;
          &lt;a href="https://dev.to/wasp/a-structured-workflow-for-vibe-coding-full-stack-apps-352l" class="crayons-story__tertiary fs-xs"&gt;&lt;time&gt;Apr 16 '25&lt;/time&gt;&lt;span class="time-ago-indicator-initial-placeholder"&gt;&lt;/span&gt;&lt;/a&gt;
        &lt;/div&gt;
      &lt;/div&gt;

    &lt;/div&gt;

    &lt;div class="crayons-story__indention"&gt;
      &lt;h2 class="crayons-story__title crayons-story__title-full_post"&gt;
        &lt;a href="https://dev.to/wasp/a-structured-workflow-for-vibe-coding-full-stack-apps-352l" id="article-link-2409125"&gt;
          A Structured Workflow for "Vibe Coding" Full-Stack Apps
        &lt;/a&gt;
      &lt;/h2&gt;
        &lt;div class="crayons-story__tags"&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/vibecoding"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;vibecoding&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/ai"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;ai&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/fullstack"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;fullstack&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/webdev"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;webdev&lt;/a&gt;
        &lt;/div&gt;
      &lt;div class="crayons-story__bottom"&gt;
        &lt;div class="crayons-story__details"&gt;
          &lt;a href="https://dev.to/wasp/a-structured-workflow-for-vibe-coding-full-stack-apps-352l" class="crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left"&gt;
            &lt;div class="multiple_reactions_aggregate"&gt;
              &lt;span class="multiple_reactions_icons_container"&gt;
                  &lt;span class="crayons_icon_container"&gt;
                    &lt;img src="https://assets.dev.to/assets/multi-unicorn-b44d6f8c23cdd00964192bedc38af3e82463978aa611b4365bd33a0f1f4f3e97.svg" width="18" height="18"&gt;
                  &lt;/span&gt;
                  &lt;span class="crayons_icon_container"&gt;
                    &lt;img src="https://assets.dev.to/assets/fire-f60e7a582391810302117f987b22a8ef04a2fe0df7e3258a5f49332df1cec71e.svg" width="18" height="18"&gt;
                  &lt;/span&gt;
                  &lt;span class="crayons_icon_container"&gt;
                    &lt;img src="https://assets.dev.to/assets/sparkle-heart-5f9bee3767e18deb1bb725290cb151c25234768a0e9a2bd39370c382d02920cf.svg" width="18" height="18"&gt;
                  &lt;/span&gt;
              &lt;/span&gt;
              &lt;span class="aggregate_reactions_counter"&gt;425&lt;span class="hidden s:inline"&gt; reactions&lt;/span&gt;&lt;/span&gt;
            &lt;/div&gt;
          &lt;/a&gt;
            &lt;a href="https://dev.to/wasp/a-structured-workflow-for-vibe-coding-full-stack-apps-352l#comments" class="crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left flex items-center"&gt;
              Comments


              47&lt;span class="hidden s:inline"&gt; comments&lt;/span&gt;
            &lt;/a&gt;
        &lt;/div&gt;
        &lt;div class="crayons-story__save"&gt;
          &lt;small class="crayons-story__tertiary fs-xs mr-2"&gt;
            10 min read
          &lt;/small&gt;
            
              &lt;span class="bm-initial"&gt;
                

              &lt;/span&gt;
              &lt;span class="bm-success"&gt;
                

              &lt;/span&gt;
            
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;/div&gt;


</description>
      <category>vibecoding</category>
      <category>ai</category>
      <category>fullstack</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Going from an Idea to MVP in Weeks: PromptPanda's Launch(es)</title>
      <dc:creator>Milica Maksimovic</dc:creator>
      <pubDate>Tue, 18 Mar 2025 08:54:09 +0000</pubDate>
      <link>https://dev.to/wasp/going-from-an-idea-to-mvp-in-weeks-promptpandas-launches-287n</link>
      <guid>https://dev.to/wasp/going-from-an-idea-to-mvp-in-weeks-promptpandas-launches-287n</guid>
      <description>&lt;p&gt;Did you know that most co-founders meet each other through work? &lt;strong&gt;&lt;a href="https://x.com/WWWillems" rel="noopener noreferrer"&gt;Lander Willem&lt;/a&gt;&lt;/strong&gt; met his friend and co-founder &lt;strong&gt;&lt;a href="https://x.com/brambilicious" rel="noopener noreferrer"&gt;Bram Billiet&lt;/a&gt;&lt;/strong&gt; while they were working at the local venture fund. They both shared the love towards LLMs and got the idea to kickstart their SaaS after experiencing the same pain points with managing and versioning prompts.&lt;/p&gt;

&lt;p&gt;In this post, you'll learn how they:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Shipped their SaaS from idea to MVP in weeks, using modern AI stack&lt;/li&gt;
&lt;li&gt;Launched and got trending on Product Hunt with 100+ upvotes&lt;/li&gt;
&lt;li&gt;Successfully onboarded first users&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The problem: Managing prompts is messy
&lt;/h2&gt;

&lt;p&gt;Right after OpenAI released their first LLM models, Lander and Bram started exchanging tips on how to get optimal results from prompts. Soon, they learned that managing AI prompts is often chaotic. &lt;/p&gt;

&lt;p&gt;People who share prompts usually do so through messaging apps such as Slack, Microsoft Teams or in better cases, shared Google Docs documents. Some of the people they talked to even confessed they were sharing their favorite prompts using screenshots 😅. Although a Google Doc might work initially, people quickly bump into issues regarding versioning and granular access management.&lt;/p&gt;

&lt;p&gt;This is how they got the idea to create &lt;a href="https://www.promptpanda.io/" rel="noopener noreferrer"&gt;PromptPanda&lt;/a&gt; - a SaaS that allows people to exchange prompts in an easy way. &lt;a href="https://demo.arcade.software/JiVvKE3oDWzbar0DKUDX" rel="noopener noreferrer"&gt;Here's an interactive demo&lt;/a&gt; you can click through to see what they've built.&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%2Fccy6m6wrl6r7yzh7phmv.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%2Fccy6m6wrl6r7yzh7phmv.png" alt="Image description" width="800" height="416"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The opportunity: Everyone uses prompts, not just devs
&lt;/h2&gt;

&lt;p&gt;Other AI prompt tools are primarily designed with developers in mind, which leaves out non-technical teams. Those less technical users depend heavily on collaboration, efficiency, and consistency to complete their tasks. This is the market PromptPanda decided to go after.&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%2Fuaajkmb2q9nv8hcp82ai.jpg" 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%2Fuaajkmb2q9nv8hcp82ai.jpg" alt="Image description" width="500" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The tool is designed specifically to help teams centralize their prompts and ensures consistent output quality. Collaboration is painless because of an intuitive web app that also has &lt;a href="https://chromewebstore.google.com/detail/promptpanda/hpgfoodclhmbloolkenjjofklhalfblc" rel="noopener noreferrer"&gt;a Chrome extension&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;PromptPanda integrates with major AI providers such as OpenAI, Anthropic, Google, Perplexity, and DeepSeek. Coupled with its built-in Prompt Improver, these integrations allow users to quickly test, iterate, and enhance their prompts, while not imposing any limitations for the end-users.&lt;br&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%2Fu7ej0763lvnsa7py92ix.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%2Fu7ej0763lvnsa7py92ix.png" alt="Image description" width="800" height="365"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;With this approach they covered a market that other companies overlooked, non-technical users who rely on the biggest LLM providers for their daily tasks.&lt;/p&gt;


&lt;h2&gt;
  
  
  Launching is unpredictable: Product Hunt hits and flops
&lt;/h2&gt;

&lt;p&gt;As soon as the app was somewhat stable and usable, Lander and Bram decided to launch on ProductHunt.&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%2F6mtvhgf4h9xvnbj536jq.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%2F6mtvhgf4h9xvnbj536jq.png" alt="Image description" width="800" height="495"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.producthunt.com/products/promptpanda#promptpanda" rel="noopener noreferrer"&gt;Their first ProductHunt launch&lt;/a&gt; was great in terms of visibility. They were featured by the ProductHunt team which got them a bunch of upvotes and comments. &lt;strong&gt;Although there was quite a lot of engagement with the launch, it didn't really end up in sticky, paying customers.&lt;/strong&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%2Faz5fjxbn7fh1u9sqdia2.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%2Faz5fjxbn7fh1u9sqdia2.png" alt="Image description" width="800" height="307"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A short while later they relaunched on ProductHunt after processing the feedback from their first launch. Both their product and launch campaign were much better prepared. Weirdly enough, the launch mostly failed as they got almost no upvotes or conversions.&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%2Fd6uobwv0nms909vspdyb.jpg" 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%2Fd6uobwv0nms909vspdyb.jpg" alt="Image description" width="500" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Although their second launch was mostly a flop, it did manage to get them mentioned in a Superhuman (the email app) newsletter. Their user base doubled overnight.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Ever since then they have an active stream of users and new signups coming in. &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;”My main takeaway is to never stop shipping, and always share your work!”&lt;/p&gt;

&lt;p&gt;Lander Willem&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Most of their users today have found PromptPanda through organic SEO. They started writing articles about &lt;a href="https://www.promptpanda.io/ai-prompt-management/" rel="noopener noreferrer"&gt;AI Prompt Management&lt;/a&gt; which have quickly found traction in search engine algorithms.&lt;/p&gt;
&lt;h3&gt;
  
  
  Finding this article interesting?
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://wasp.sh/" rel="noopener noreferrer"&gt;Wasp&lt;/a&gt; team is working hard to create content like this, not to mention building a modern, open-source React/NodeJS framework.&lt;/p&gt;

&lt;p&gt;The easiest way to show your support is just to star Wasp repo! 🐝 But it would be greatly appreciated if you could take a look at the &lt;a href="https://github.com/wasp-lang/wasp" rel="noopener noreferrer"&gt;repository&lt;/a&gt; (for contributions, or to simply test the product). Click on the button below to give Wasp a star and show your support!&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%2Faxqiv01tl1pha9ougp21.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%2Faxqiv01tl1pha9ougp21.gif" alt="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/axqiv01tl1pha9ougp21.gif" width="746" height="401"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/wasp-lang/wasp" class="ltag_cta ltag_cta--branded" rel="noopener noreferrer"&gt;⭐️ Thank You For Your Support 💪&lt;/a&gt;
&lt;/p&gt;

&lt;h2&gt;
  
  
  Choosing the right stack for developing your SaaS app
&lt;/h2&gt;

&lt;p&gt;PromptPanda's team chose &lt;a href="https://opensaas.sh/" rel="noopener noreferrer"&gt;Open SaaS&lt;/a&gt; because it significantly streamlined their product development by simplifying backend setup, database management, and built-in authentication. This was crucial as they needed an efficient solution that could save time due to their busy schedules. &lt;a href="https://wasp.sh/" rel="noopener noreferrer"&gt;Wasp&lt;/a&gt;'s default integration with Fly also enabled rapid deployment, allowing them to quickly validate their product idea without getting bogged down in infrastructure complexities.&lt;/p&gt;

&lt;p&gt;Here's a full overview of their tech stack alongside all the tools they rely on to run their SaaS:&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%2F0r35f8sq8zmzqvl1gznf.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%2F0r35f8sq8zmzqvl1gznf.png" alt="Image description" width="800" height="800"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Are you ready to ship your SaaS now?
&lt;/h2&gt;

&lt;p&gt;PromptPanda's story proves the best SaaS ideas come from solving your own pain points. Lander and Bram also learned launching isn't predictable—success can come from unexpected places, even failed launches. The takeaway? Keep building, keep shipping, and always share your progress openly.&lt;/p&gt;

&lt;p&gt;If you enjoyed this post please make sure to &lt;a href="https://github.com/wasp-lang/wasp" rel="noopener noreferrer"&gt;give Wasp a star on GitHub&lt;/a&gt;, this keeps us going forward and supports our work!&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>saas</category>
      <category>javascript</category>
      <category>buildinpublic</category>
    </item>
    <item>
      <title>Meet Marko Saric, Co-founder of Privacy-friendly Plausible Analytics</title>
      <dc:creator>Milica Maksimovic</dc:creator>
      <pubDate>Tue, 04 Mar 2025 15:39:18 +0000</pubDate>
      <link>https://dev.to/wasp/meet-marko-saric-co-founder-of-privacy-friendly-plausible-analytics-3nm8</link>
      <guid>https://dev.to/wasp/meet-marko-saric-co-founder-of-privacy-friendly-plausible-analytics-3nm8</guid>
      <description>&lt;p&gt;In this interview, &lt;a href="https://x.com/markosaric" rel="noopener noreferrer"&gt;Marko Saric&lt;/a&gt; shared his thoughts on privacy and running a bootstrapped SaaS business. &lt;a href="https://plausible.io/" rel="noopener noreferrer"&gt;Plausible&lt;/a&gt; integration is already &lt;a href="https://docs.opensaas.sh/guides/analytics/#plausible" rel="noopener noreferrer"&gt;available in Open SaaS&lt;/a&gt; as a privacy-friendly alternative to Google Analytics. We hope this interview helps you understand the value of such a product, and the nature of running an open source business.&lt;/p&gt;

&lt;p&gt;Here's a few other things we've covered in this interview:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Tackling big tech privacy issues.&lt;/li&gt;
&lt;li&gt;How bootstrapping your business fuels independence and transparency.&lt;/li&gt;
&lt;li&gt;Real, practical advice for growing your SaaS the smart way.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Let's dive in!&lt;/p&gt;

&lt;h2&gt;
  
  
  Can you share a bit about your background and what led you to start Plausible?
&lt;/h2&gt;

&lt;p&gt;I'm Marko Saric, co-founder of Plausible Analytics.&lt;/p&gt;

&lt;p&gt;My journey with Plausible began with a growing awareness of the privacy issues surrounding Google and its products. For many years, I was a user of Google's services but over time (and thanks to Snowden, Cambridge Analytica and other privacy scandals), I became more aware of the negative aspects of surveillance capitalism. This led me to explore better, more ethical alternatives to the big tech products.&lt;/p&gt;

&lt;p&gt;I started sharing these alternatives on my blog which is how I connected with my co-founder Uku. We both had experience in tech and a shared vision of working on a privacy-friendly analytics tool so we decided to work together on Plausible. I'm focused on marketing and communication side of things while Uku is focused on design and development.&lt;/p&gt;

&lt;h2&gt;
  
  
  For those unfamiliar with Plausible, how would you describe its core mission in just a few sentences?
&lt;/h2&gt;

&lt;p&gt;Plausible Analytics is an easy to use, lightweight, open source and privacy-friendly analytics tool. Our mission is to provide website owners with useful insights while respecting visitor privacy.&lt;/p&gt;

&lt;p&gt;We have been working on Plausible for more than 6 years now, have more than 14,000 active subscribers at this point and have counted more than 136 billion pageviews so far.&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%2F99xv6dvlfvgqxkmszwly.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%2F99xv6dvlfvgqxkmszwly.png" alt="Image description" width="800" height="490"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Plausible is bootstrapped and open-source—what made you choose this path instead of taking the more common VC route?
&lt;/h2&gt;

&lt;p&gt;We chose to bootstrap and open source Plausible because we wanted to maintain control and independence while also being more privacy-friendly and transparent.&lt;/p&gt;

&lt;p&gt;Both of us have worked at venture funded startups in the past and neither of us had good experiences with investors so going bootstrapped was pretty much the way to do this if we wanted to do things our way.&lt;/p&gt;

&lt;p&gt;We're in the privacy niche so open sourcing our product allows us to build trust as people can inspect our code to verify that our actions match our words. People cannot do that with Google Analytics and other competing products.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Just like Plausible, Wasp is an open-source project too! We'd appreciate it if you could &lt;a href="https://github.com/wasp-lang/wasp" rel="noopener noreferrer"&gt;star Wasp on GitHub as a sign of support&lt;/a&gt;! ⭐️&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Do you have any advice for people who are considering bootstrapping their company? Do you have any books or podcasts to recommend?
&lt;/h2&gt;

&lt;p&gt;I think it's a good idea to start bootstrapped even if you do wish to get funded. You should focus on creating a great product that solves a real problem and on spreading the word about it. If you do that well, you'll have investors reaching out to you even if you don't want or need them.&lt;/p&gt;

&lt;p&gt;I recommend reading &lt;strong&gt;"Rework" by Jason Fried and David Heinemeier Hansson&lt;/strong&gt;. It offers unconventional but valuable insights into running a startup.&lt;/p&gt;

&lt;p&gt;Another good book is &lt;strong&gt;"This Is Marketing" by Seth Godin&lt;/strong&gt;. It's about how many startups confuse marketing with spending money on advertising, spamming, interrupting, being annoying and other hacks and tricks. That's not marketing. Marketing is communication.&lt;/p&gt;

&lt;h2&gt;
  
  
  How did you get your first customers?
&lt;/h2&gt;

&lt;p&gt;Our first customers came through community engagement and the "build in public" movement. We shared our journey, steps taken and product development openly on our blog, social media and niche communities such as Indie Hackers. That's how we got the early beta users and some of those became our first subscribers too.&lt;/p&gt;

&lt;h2&gt;
  
  
  What were the biggest challenges you faced while building and growing Plausible?
&lt;/h2&gt;

&lt;p&gt;The first year was pretty challenging in terms of growth. Uku was working alone on Plausible trying to do both development and marketing. This is pretty much an impossible task. The growth was very slow and we made it to about 100 subscribers and $400 MRR some 14 months into the existence of Plausible. &lt;/p&gt;

&lt;p&gt;That's when Uku decided to look for a marketing co-founder and that's how we found me. Being two co-founders helped us put more time and effort into marketing and communication. One of the first things we did when I joined was to change our positioning to make it crystal clear and easy to understand what we do, what we stand for and how we compare to Google Analytics (the biggest name in our market). And then we started publishing educational and informative content covering topics such as privacy, open source, bootstrapping and startup marketing . &lt;/p&gt;

&lt;p&gt;I have written more about the changes we made in these early days &lt;a href="https://plausible.io/blog/blog-post-changed-my-startup" rel="noopener noreferrer"&gt;in this post&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Which growth strategies have been the most effective?
&lt;/h2&gt;

&lt;p&gt;We have a boring marketing strategy and we say no to all the growth hacks and other best marketing practices. Content marketing has been our most effective growth strategy. As an example, the first blog post that I published (Why You Should Remove Google Analytics from Your Site) went viral on Hacker News. It drove some good traffic to our site leading to an increase in brand awareness. &lt;/p&gt;

&lt;p&gt;What matters is doing quality work and staying consistent with it over a longer period of time so we continued to publish multiple blog posts per week for over a year. Thanks to that work, we've been fortunate enough to achieve the viral moments on Hacker News multiple times over those first 2-3 years.&lt;/p&gt;

&lt;p&gt;I have shared more about our early years, marketing steps we've taken, lessons we've learned and things we have achieved &lt;a href="https://plausible.io/blog/open-source-saas" rel="noopener noreferrer"&gt;in blog posts such as this one&lt;/a&gt;. Our analytics dashboard is open to the public so it's possible to see the progress we've made since day one &lt;a href="https://plausible.io/plausible.io?period=all&amp;amp;keybindHint=A" rel="noopener noreferrer"&gt;in our stats&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  What role has the community played in Plausible's growth? Have there been any surprising or particularly impactful contributions from the community?
&lt;/h2&gt;

&lt;p&gt;The community has helped shape our product and spread the word about our mission.&lt;/p&gt;

&lt;p&gt;We have an open roadmap and listen to the product feedback which determines our development prioritization. This is where feature requests and other feedback is very valuable to us. We pretty much pick the most upvoted feature and work on that. &lt;/p&gt;

&lt;p&gt;As mentioned earlier, we don't do any traditional marketing as in we don't do any paid advertising nor pay anyone to recommend Plausible. This means that most of our growth comes from people who love using Plausible and who share their experiences with the world. Without people spreading the word about Plausible it would be difficult for us to do what we do. So that's why community contributions is vital for us. &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%2Fml2qx6t65gdbru24ze7j.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%2Fml2qx6t65gdbru24ze7j.png" alt="Image description" width="800" height="377"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What's next for Plausible? Are there any upcoming features or improvements you're particularly excited about?
&lt;/h2&gt;

&lt;p&gt;We're focused on continuing to improve Plausible and making it even more useful and competitive while staying true to our mission and meeting rigorous standards for stability, security and privacy.&lt;/p&gt;

&lt;p&gt;Our developers are currently working on the top two most upvoted feature requests from our public feedback board (scroll depth and saved segments) so that's very exciting. It would be great to release these two big features soon!&lt;/p&gt;




&lt;p&gt;Just like Plausible, Wasp is an open-source project too! We'd appreciate it if you could &lt;a href="https://github.com/wasp-lang/wasp" rel="noopener noreferrer"&gt;star Wasp on GitHub as a sign of support&lt;/a&gt;! ⭐️&lt;/p&gt;

</description>
      <category>opensource</category>
      <category>buildinpublic</category>
      <category>privacy</category>
      <category>webdev</category>
    </item>
    <item>
      <title>From 0 to 400+ Customers: SaaS Growth Hacks from a Serial Founder</title>
      <dc:creator>Milica Maksimovic</dc:creator>
      <pubDate>Thu, 06 Feb 2025 08:49:08 +0000</pubDate>
      <link>https://dev.to/wasp/from-0-to-400-customers-saas-growth-hacks-from-a-serial-founder-167f</link>
      <guid>https://dev.to/wasp/from-0-to-400-customers-saas-growth-hacks-from-a-serial-founder-167f</guid>
      <description>&lt;p&gt;&lt;a href="https://x.com/rbatista19" rel="noopener noreferrer"&gt;Meet Ricardo&lt;/a&gt; - he has successfully launched multiple SaaS products, turning his ideas into revenue-generating apps. If you're looking to build and launch your own product efficiently, we're about to share some of Ricardo's key strategies.&lt;/p&gt;

&lt;p&gt;He's a developer with a background in telecom engineering, having held leadership roles at companies like Vodafone and Glovo. But after years of putting fires out in management, he returned to hands-on development, focusing on building apps that solve real problems—fast.&lt;/p&gt;

&lt;p&gt;By leveraging &lt;a href="https://opensaas.sh/" rel="noopener noreferrer"&gt;Open SaaS&lt;/a&gt;, Ricardo was able to ship multiple projects quickly, skipping the usual headaches of setting up authentication, payments, and other things every SaaS needs. In this post, you'll discover what types of SaaS products he launched and the strategies he used to get them off the ground.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why Ricardo Chose Open SaaS
&lt;/h3&gt;

&lt;p&gt;When searching for frameworks to kickstart his projects, Ricardo stumbled upon Open SaaS, a 100% free, open-source starter for React &amp;amp; Node.js. and. He was drawn to Open SaaS because of its simplicity, community, and modern tech stack. He also liked the fact that the company had Y Combinator seal of approval.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;"The fact that Wasp is low-friction and uses a great stack like Prisma, React, Node.js, and TypeScript—made it stand out. Plus, the community is super helpful. You can get started fast without spending hours on setup."&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%2Fmedia0.giphy.com%2Fmedia%2F13zeE9qQNC5IKk%2Fgiphy.gif%3Fcid%3D7941fdc69ba2psk3jei2jwzvohsqp0912ugkwzm2jugyrw7x%26ep%3Dv1_gifs_search%26rid%3Dgiphy.gif%26ct%3Dg" 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%2Fmedia0.giphy.com%2Fmedia%2F13zeE9qQNC5IKk%2Fgiphy.gif%3Fcid%3D7941fdc69ba2psk3jei2jwzvohsqp0912ugkwzm2jugyrw7x%26ep%3Dv1_gifs_search%26rid%3Dgiphy.gif%26ct%3Dg" alt="Excited reaction gif" width="250" height="169"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;What Ricardo loves most:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Pre-built Features&lt;/strong&gt;: Open SaaS relies on Wasp - a full stack framework for React, Node.js and Prisma. The way Wasp handles routes and authentication was a game-changer. &lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;"Just putting routes in &lt;code&gt;main.wasp&lt;/code&gt; makes everything super simple. Auth works seamlessly, too."&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Focus on Building&lt;/strong&gt;: By handling repetitive setup tasks like setting up payment integrations or making admin dashboards, Open SaaS allowed Ricardo to focus on core features.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Adaptability&lt;/strong&gt;: regardless of the idea he had - a full-fledged SaaS, or a Google add-on which needed a robust-backend and a dashboard, he was able to build the app with Open SaaS boilerplate starter.&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;"I didn't feel limited by the boilerplate—it's flexible and gets out of the way."&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Ricardo's Projects Built with Wasp
&lt;/h2&gt;

&lt;p&gt;Ricardo started a few projects with Wasp, while working on the third one he started before discovering Open SaaS.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Article Generator&lt;/strong&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Built in less than 7 days.&lt;/li&gt;
&lt;li&gt;40+ paying customers.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://article-generation.com/" rel="noopener noreferrer"&gt;This tool&lt;/a&gt; simplifies content creation for businesses by generating SEO-friendly blog posts with AI.  Article Generator is competing in a crowded market of AI writing tools, where each tool claims that it's the best one on the market. &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%2F10510sq2j63ugnvo2lvu.webp" 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%2F10510sq2j63ugnvo2lvu.webp" alt="article generation homepage" width="800" height="377"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Ricardo is using Open SaaS to focus on feature development while testing pricing strategies to differentiate the product from the rest of the market. Integrations with Stripe, Open AI, and similar helped him move faster than he could on his own. His first clients came from Reddit and he has a standard subscription monetization set up.&lt;/p&gt;

&lt;h3&gt;
  
  
  Finding this article interesting?
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://wasp.sh/" rel="noopener noreferrer"&gt;Wasp&lt;/a&gt; team is working hard to create content like this, not to mention building a modern, open-source React/NodeJS framework.&lt;/p&gt;

&lt;p&gt;The easiest way to show your support is just to star Wasp repo! 🐝 But it would be greatly appreciated if you could take a look at the &lt;a href="https://github.com/wasp-lang/wasp" rel="noopener noreferrer"&gt;repository&lt;/a&gt; (for contributions, or to simply test the product). Click on the button below to give Wasp a star and show your support!&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%2Faxqiv01tl1pha9ougp21.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%2Faxqiv01tl1pha9ougp21.gif" alt="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/axqiv01tl1pha9ougp21.gif" width="746" height="401"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/wasp-lang/wasp" class="ltag_cta ltag_cta--branded" rel="noopener noreferrer"&gt;⭐️ Thank You For Your Support 💪&lt;/a&gt;
&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Meeting Reminders&lt;/strong&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Bult in less than 7 days.&lt;/li&gt;
&lt;li&gt;400+ paying customers.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://meeting-reminders.com/" rel="noopener noreferrer"&gt;This tool is a Google Workspace add-on&lt;/a&gt; that reduces no-shows by automating pre-meeting reminders. His competitive edge is that he covers WhatsApp alongside SMS and email reminders. Meeting Reminders app shows how versatile Open SaaS boilerplate is, because it can handle edge cases like this one and integrate into Google's system.&lt;/p&gt;

&lt;p&gt;Calls being skipped was a huge pain for Ricardo when he was working at a VC company. His day would include a lot of calls, and the cancellation rate was high. Once he started emailing participants before the call, the number of cancellations reduced significantly. Some time later, he built the tool himself to automate this 😃&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%2Ffefl5d2cbt2yk2kb4f6t.webp" 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%2Ffefl5d2cbt2yk2kb4f6t.webp" alt="meeting reminders homepage" width="800" height="435"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In this case, Open SaaS handles backend tasks like subscription checks and authentication. Because of that, this is a lightweight app that solves a niche problem effectively, and doesn't require a lot of maintenance.&lt;/p&gt;

&lt;p&gt;The first users were people he knew personally, and he did a bit of promotion on targeted groups on Slack and Discord. Since it's a Google Marketplace app, anyone looking for Meeting Reminder add-on will have a chance to see 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%2Funwlm4k9bupw58ars7ua.webp" 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%2Funwlm4k9bupw58ars7ua.webp" alt="meeting reminders addon" width="218" height="298"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;He also relies on SEO, and guess what, he pushed a couple of blog posts with his first SaaS, AI Article Generator. As he said before, you should make tools that scratch your itch first. 😃&lt;/p&gt;

&lt;h3&gt;
  
  
  Tips for Builders Launching Products
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Validate Before You Build&lt;/strong&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;"Start by searching Reddit or similar platforms to find out if people are already solving the problem. If they are, ask yourself: can I do it better or faster?"&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%2Fmedia3.giphy.com%2Fmedia%2FiK45mgOPCt5MsqcKhq%2Fgiphy.gif%3Fcid%3D7941fdc6b5cs6fcmgw1ki92h5ic0v6xxweb2yn58h6nkx1c1%26ep%3Dv1_gifs_search%26rid%3Dgiphy.gif%26ct%3Dg" 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%2Fmedia3.giphy.com%2Fmedia%2FiK45mgOPCt5MsqcKhq%2Fgiphy.gif%3Fcid%3D7941fdc6b5cs6fcmgw1ki92h5ic0v6xxweb2yn58h6nkx1c1%26ep%3Dv1_gifs_search%26rid%3Dgiphy.gif%26ct%3Dg" alt="Excited reaction gif" width="480" height="362"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Diversify Launch Strategies&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Avoid relying solely on Product Hunt &lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;"It's not as effective as it used to be."&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;ul&gt;
&lt;li&gt;Explore short-form content like &lt;a href="https://www.tiktok.com/@meetingreminders/video/7462839913231306016" rel="noopener noreferrer"&gt;TikTok&lt;/a&gt; for quick validation. You can create a company account and post videos that showcase the problem and the solution.
&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;"Their algorithm is great for targeting the right audience."&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;ul&gt;
&lt;li&gt;Use targeted Reddit ads to reach niche communities.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Start small&lt;/strong&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;"If you're entering a competitive space, start small. Validate your product's unique edge by solving specific pain points and adjust based on user feedback."&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;Iterate Quickly&lt;/strong&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;"Launch fast, gather feedback, and refine your product. You don't need to build the perfect app on day one—get it out there, see how people use it, and adjust."&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Ready to Build Your SaaS?&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Explore the &lt;a href="https://opensaas.sh/" rel="noopener noreferrer"&gt;Open SaaS boilerplate&lt;/a&gt; to see how you can kickstart your SaaS today.&lt;/p&gt;



</description>
      <category>ai</category>
      <category>webdev</category>
      <category>saas</category>
      <category>startup</category>
    </item>
    <item>
      <title>🦸 OSS Heroes: Pilcrow, a student who built Lucia - auth library with 9.5k stars on GitHub ⭐ 🇯🇵</title>
      <dc:creator>Milica Maksimovic</dc:creator>
      <pubDate>Wed, 30 Oct 2024 12:27:12 +0000</pubDate>
      <link>https://dev.to/wasp/oss-heroes-pilcrow-a-student-who-built-lucia-auth-library-with-95k-stars-on-github-524l</link>
      <guid>https://dev.to/wasp/oss-heroes-pilcrow-a-student-who-built-lucia-auth-library-with-95k-stars-on-github-524l</guid>
      <description>&lt;p&gt;We're back with our series of posts in which we interview open-source maintainers and showcase the amazing projects they keep pushing. This week, we've talked with &lt;a href="https://github.com/pilcrowonpaper" rel="noopener noreferrer"&gt;Pilcrow&lt;/a&gt;, an inspiring young dev from Japan, famous for his auth library Lucia and love for auth and security. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/lucia-auth/lucia" rel="noopener noreferrer"&gt;Lucia&lt;/a&gt; is one of the open-source tools that we use under the hood at &lt;a href="https://github.com/wasp-lang/wasp" rel="noopener noreferrer"&gt;Wasp, a Laravel-like framework for React &amp;amp; Node.js&lt;/a&gt;. It has grown to 9.5K stars on GitHub since October 2023. Although Lucia itself will be deprecated as a library in 2025 and converted into a &lt;a href="https://github.com/lucia-auth/lucia/discussions/1714" rel="noopener noreferrer"&gt;learning resource&lt;/a&gt;, Pilcrow is also working on other projects related to auth, such as Copenhagen and Oslo. You can learn more about his work and projects on his &lt;a href="https://pilcrowonpaper.com/" rel="noopener noreferrer"&gt;blog&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;We hope this interview inspires you to contribute to the open-source community yourself. Let's dive in!&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Could you tell us a little about yourself and how you got into coding? What led you to focus on authentication and tooling for developers?&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I’m Pilcrow. I’m a university student in Japan working on various open source projects around auth and security. I started programming like 4 years ago so I'm still new to the field. I love designing APIs a lot and that's probably the biggest reason I enjoy working on libraries.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Lucia brought you recognition within the dev community. What inspired you to create it, and how did you decide to dedicate so much time and effort to it?&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I was asked to build several websites for school events and the part I struggled with the most was auth. Half of it was my inexperience, but I also found third-party offerings like Firebase to be unintuitive. Most of their features and APIs at the time were aimed at SPAs as well and didn't work well with server-rendered applications. The open source offerings weren't great either. To this day, I still don't really know how to actually use NextAuth (now Auth.js) or Passport.js.&lt;/p&gt;

&lt;p&gt;Over summer break, I decided to build a more leaner NextAuth for SvelteKit so I could use it for my projects. It was my first open source library but it got some attention in the Svelte community. I made it framework agnostic a little while later and it grew naturally.&lt;/p&gt;

&lt;p&gt;Working on it got me hooked on library development, and I found designing APIs and even documenting them to be very enjoyable.&lt;/p&gt;

&lt;h2&gt;
  
  
  Support us! 🙏⭐️
&lt;/h2&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%2Fid9s6t8rcvfxty40bv2m.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%2Fid9s6t8rcvfxty40bv2m.gif" alt="GH star click" width="360" height="78"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you find this post helpful, &lt;a href="https://github.com/wasp-lang/wasp" rel="noopener noreferrer"&gt;consider giving us a star on Github&lt;/a&gt;! Everything we do at Wasp is open source, and your support helps us make web development easier and motivates us to write more articles like this one.&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%2Fqgbmn45pia04bxt6zf83.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%2Fqgbmn45pia04bxt6zf83.gif" alt="support us" width="746" height="401"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://kdta.io/github-wasp-lang-wasp_3" class="ltag_cta ltag_cta--branded" rel="noopener noreferrer"&gt;⭐️ Thanks For Your Support 🙏&lt;/a&gt;
&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Managing an open-source project like Lucia must come with challenges. What were some unexpected hurdles, and how did you handle them?&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I honestly don't find anything about maintaining open-source projects specifically to be challenging. It just requires a lot of your time with answering questions on Discord and writing documentation. I've definitely changed my approach to library development from when I started though. I now put most of my effort into designing APIs and writing documentation over adding new features.&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%2F7hyfjq0itzv1ihmod84w.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%2F7hyfjq0itzv1ihmod84w.gif" alt="giphy applause" width="480" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;You're also working on &lt;a href="https://github.com/pilcrowonpaper/copenhagen" rel="noopener noreferrer"&gt;The Copenhagen Book&lt;/a&gt;, which focuses on authentication guidelines. Why is authentication such a key area of interest for you?&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I find figuring why something is and isn't vulnerable a fun mystery to solve. I also love that there are so many rabbit holes you can find yourself in. You're searching about some protocol one moment and the next you're reading a 50-page RFC on some obscure encoding format. It's a field that pushes you to learn more.&lt;/p&gt;

&lt;p&gt;(As a bonus, I don't have to deal with CSS).&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href="https://github.com/pilcrowonpaper/oslo" rel="noopener noreferrer"&gt;Oslo&lt;/a&gt; provides auth-related utilities. Could you walk us through its main features and the problem space it addresses?&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Oslo is a collection of packages for various auth and cryptographic operations. Base64, WebAuthn, SHA-256, ECDSA, TOTP/HOTP, ASN.1, etc. It doesn't rely on third-party dependencies or runtime-specific APIs, so it's super lean and runs everywhere. The APIs are relatively low-level compared to similar libraries as well. It requires some knowledge on the underlying standards, but you don't need to learn any library-specific concepts, which is a very big win in my book.&lt;/p&gt;

&lt;p&gt;Also, it's a very simple feature but just having some kind of documentation is a big plus.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;How do you balance your time across multiple open-source projects while ensuring each gets the attention it deserves?&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I wish I had a better system, but I just work on whatever I feel like. I’m not very good at multi-tasking and prefer focusing on one thing at a time. I don't get a lot of bug reports anyway so it works for me.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;How do you keep up with evolving security standards across projects, and what advice would you give to teams building their own auth solutions from scratch?&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;To be honest, I don't think web application security evolves that fast. At least compared to the JavaScript ecosystem (but I guess nothing does). It's rare for a cryptographic algorithm to break overnight and the threat model and basic recommendation is still the same from 10 years ago. A lot of vulnerabilities are still broken access controls and insufficient input sanitation.&lt;/p&gt;

&lt;p&gt;But just a lot of reading. Understand the framework and protocols you're dealing with. RFCs and documentations already cover a lot of possible pitfalls. I guess this applies to those who are planning to delegate auth to a third party as well, at least to some extent.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Open-source maintainers often struggle with burnout. How do you stay motivated, and what keeps you coming back to these projects?&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Maintaining various projects definitely helps with avoiding burnout. My projects aren’t that big in scale and actual bug reports are rare, so I don’t worry about switching my focus to a different project or taking a break for a week or two.&lt;/p&gt;

&lt;p&gt;I also see open source as just a hobby. I'll still try to address bugs quickly, but I don't rush myself to add new features.&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%2F0uhueewwmfqmn82jq5f4.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%2F0uhueewwmfqmn82jq5f4.gif" alt="relax gif" width="480" height="480"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;When collaborating on open-source, how do you manage community contributions and keep other developers involved in a meaningful way?&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I don't think my projects are particularly good examples of open source collaborations. I usually ask people to open GitHub issues for new features and I'm not really open to pull requests except for bug and typo fixes. I like to take my time experimenting with various API designs and I personally find it easier if I do the initial design phase by myself. There's also a certain flavor of code I like and I really want to keep my code "beautiful" (yes, I know it sounds dumb).&lt;/p&gt;

&lt;p&gt;To be honest, I don't like pull requests in general since I feel like I wasted the contributor's time if I reject it, even if the code is objectively awful.&lt;/p&gt;

&lt;p&gt;I'm well aware that this closed approach doesn't work in bigger projects, but working on open source is ultimately just a hobby, so I think I should be able to have some fun with it.&lt;/p&gt;

&lt;p&gt;Most of the community aspect comes from Discord, and I really appreciate people who are active daily and answer questions there. Honestly, it's probably some of the most valuable contributions I receive.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;What would you do differently in the development and management of your projects, knowing what you know now about open-source and developer tools?&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Defining the scope and goals of a project early on. I don’t blame myself for not thinking much ahead when starting Lucia since it was literally my first open source library, but it would’ve made development on subsequent major releases much easier. There’s only so many features you can add to a project before the code becomes a mess. You can’t appease everyone, so pick a lane and be the best for that purpose.&lt;/p&gt;

&lt;p&gt;I also think that libraries that are flexible in how and where they can be used, instead of flexible in their behavior, are more predictable and easier to work with. Clearly defining the line between library and user responsibility is going to make it much more enjoyable to use.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;What is your favorite type of ramen?&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Probably tonkotsu, specifically from Kyushu (the third-largest island of Japan's four main islands). The broth is based on pork bones, which gives it a creamy and rich texture, and the noodle has a bite to it (like al dente pasta).&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%2Fjbpg7gncy9i7i31519ln.webp" 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%2Fjbpg7gncy9i7i31519ln.webp" alt="Tonkatsu ramen" width="800" height="532"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Hope you enjoyed this interview! If you have any suggestions about whom to interview next, &lt;a href="https://discord.gg/TUeXksNqaH" rel="noopener noreferrer"&gt;join us on Discord&lt;/a&gt; and let us know!&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>security</category>
      <category>nextjs</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Why Your SaaS Emails Aren’t Being Delivered and How to Fix This Issue</title>
      <dc:creator>Milica Maksimovic</dc:creator>
      <pubDate>Tue, 01 Oct 2024 17:40:42 +0000</pubDate>
      <link>https://dev.to/wasp/why-your-saas-emails-arent-being-delivered-and-how-to-fix-this-issue-3cdi</link>
      <guid>https://dev.to/wasp/why-your-saas-emails-arent-being-delivered-and-how-to-fix-this-issue-3cdi</guid>
      <description>&lt;p&gt;If you’ve just built your SaaS web app and deployed it on a production server, you might be running into email deliverability issues. Transactional or marketing emails might not be landing in your users' inboxes. Don’t panic! This is a pretty common problem, especially for apps that run on newly registered domains.&lt;/p&gt;

&lt;p&gt;We have seen a lot of &lt;a href="https://wasp-lang.dev/" rel="noopener noreferrer"&gt;Wasp&lt;/a&gt; users facing similar challenges, thinking their toolkit was to blame. In our Discord community, we regularly help users who’ve just launched their first app with Wasp, and we've seen this issue pop up frequently. The bad news: your users and their email servers pulled a Gandalf move on you. The good news: no worries, this is something you can fix!&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%2Fsitsi0sb9u779w1n1o8e.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%2Fsitsi0sb9u779w1n1o8e.gif" alt="Gandalf saying you shall not pass" width="400" height="225"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  1. &lt;strong&gt;Build up your domain reputation&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;A new domain is often flagged as suspicious by email providers, causing your emails to land in spam or not be delivered at all. Google’s filtering is really heavy, especially if you’re trying to reach people with business addresses (&lt;a href="mailto:user@theircompany.com"&gt;user@theircompany.com&lt;/a&gt;). Even the basic signup confirmations have a high chance of bouncing when you’re sending them from a freshly registered domain.&lt;/p&gt;

&lt;p&gt;To improve your domain reputation, do the following:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Use a custom domain for your emails&lt;/strong&gt;: If you’re still using a generic email service like Gmail, switch to a custom domain. This makes you more trustworthy and looks more professional.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Warm-up your domain&lt;/strong&gt;: You need to do this before you start onboarding your users. Any type of sudden bursts of emails from a new domain can be flagged as spam. For example, if you decide to launch on Product Hunt, you’ll get a spike in signups which increases the amount of sent emails. It’s possible that this spike triggers the alarms, and people stop receiving your emails. &lt;a href="https://letmegooglethat.com/?q=Email+warmup+tools" rel="noopener noreferrer"&gt;There are numerous tools out there&lt;/a&gt; that can help you with this process. Don’t skip this step, it’s mandatory.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Keep the sending volume consistent&lt;/strong&gt;: Regular email sending patterns are seen as trustworthy. Inconsistent or high-volume bursts from a new domain can trigger spam filters.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  2. &lt;strong&gt;Authenticate your domain&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Authentication adds a layer of security to your emails, proving to email providers that you’re a legitimate sender and not the next prince of spam from the land of Spamlia. Here are the key records you need to set up with your DNS provider:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;SPF&lt;/strong&gt;: This allows email servers to verify that emails sent from your domain are really coming from you.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;DKIM&lt;/strong&gt;: This attaches a digital signature to your emails that enables email servers to confirm the email wasn’t tampered with in transit.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;DMARC&lt;/strong&gt;: this one helps you control how your email domain handles unauthenticated emails.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Read more about these records and how to add them to your DNS servers &lt;a href="https://www.cloudflare.com/en-gb/learning/email-security/dmarc-dkim-spf/" rel="noopener noreferrer"&gt;here&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%2F46jjtazfb0tqexrmmsx8.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%2F46jjtazfb0tqexrmmsx8.gif" alt="A girl saying and you're going to fix it" width="480" height="270"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  3. &lt;strong&gt;Use professional email sending tools&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Instead of sending emails directly from your own server, consider using a third-party email service that specializes in this area. Tools like &lt;strong&gt;SendGrid&lt;/strong&gt; or &lt;strong&gt;Mailgun&lt;/strong&gt; have built-in features to help ensure your emails make it to the inbox. Wasp helps you to &lt;a href="https://wasp-lang.dev/docs/advanced/email" rel="noopener noreferrer"&gt;add them to your stack&lt;/a&gt; with minimal configuration needed on your end.&lt;/p&gt;

&lt;p&gt;They monitor and improve your domain reputation, manage bounces, and handle email authentication out-of-the-box. We’d recommend you to offload sending emails to them, so that you can focus on the core aspects of your business.&lt;/p&gt;

&lt;h2&gt;
  
  
  4. &lt;strong&gt;Monitor your deliverability&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;It’s important to keep an eye on how your emails are performing. Look for key metrics like bounce rate, open rate, and spam complaints. Most email sending services provide insights into your email deliverability, allowing you to make adjustments before your reputation gets damaged.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Bounce rate&lt;/strong&gt;: High bounce rates suggest you’re sending to invalid or outdated email addresses. Regularly clean your list to avoid this. If more than 3% of your emails bounce, your domain can get blocked by your email provider.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Spam complaints&lt;/strong&gt;: High spam reports and complaints can also lead to email providers blocking your domain. If users are marking your emails as spam, reconsider the content and frequency of your emails. Also, please don’t buy email lists off of Internet, those will do you more harm than good.&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%2F57bn5oi7hxy9mkwuyy8h.jpg" 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%2F57bn5oi7hxy9mkwuyy8h.jpg" alt="meme saying are you looking into buying email lists" width="604" height="453"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  5. &lt;strong&gt;Create high-quality content&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;What you write matters too. Emails are poorly written are more likely to be marked as spam.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Use a clear subject line&lt;/strong&gt;: Avoid clickbait or overly promotional language. Keep your subject lines clear and aligned with the content of your email. If your subject line is off, your email can directly land in spam or in the promotional inbox.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Personalize your emails&lt;/strong&gt;: Address your users by their name and offer content that is relevant to their needs. Personalized emails tend to have higher open and click-through rates.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Avoid spammy-looking keywords&lt;/strong&gt;: Words like “FREE,” “LIMITED OFFER,” and excessive use of exclamation marks can trigger spam filters. Keep your language professional and to the point. DON’T USE CAPS LOCK EVERYWHERE!&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Inbox access granted
&lt;/h2&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%2F6tqinsgghg0wd3nxmvfc.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%2F6tqinsgghg0wd3nxmvfc.gif" alt="you can do this gif" width="500" height="281"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We know that email delivery issues are frustrating, but they are solvable. Start small - implement one or two changes. First, authenticate your domain and then &lt;a href="https://wasp-lang.dev/docs/advanced/email#using-the-mailgun-provider" rel="noopener noreferrer"&gt;set up professional email sending tools&lt;/a&gt;, Wasp supports some out of the box. &lt;/p&gt;

&lt;p&gt;You can monitor the performance over time, and improve your approach with every batch of emails. It’s not about getting everything perfect from the start, but about making the right decisions before you start onboarding your users.&lt;/p&gt;

&lt;p&gt;Oh, and by the way, if you find this useful, we'd love a star on GitHub. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.github.com/wasp-lang/wasp" class="ltag_cta ltag_cta--branded" rel="noopener noreferrer"&gt;⭐️ Star Wasp on GitHub 🙏&lt;/a&gt;
&lt;/p&gt;

&lt;p&gt;It's the easiest way to support open-source initiatives like ours.&lt;/p&gt;

</description>
      <category>startup</category>
      <category>sass</category>
      <category>productivity</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>The Faces Behind Open Source Projects: Tim Jones and pg-boss</title>
      <dc:creator>Milica Maksimovic</dc:creator>
      <pubDate>Wed, 11 Sep 2024 14:46:34 +0000</pubDate>
      <link>https://dev.to/wasp/the-faces-behind-open-source-projects-tim-jones-and-pg-boss-2po1</link>
      <guid>https://dev.to/wasp/the-faces-behind-open-source-projects-tim-jones-and-pg-boss-2po1</guid>
      <description>&lt;p&gt;We’re launching a new series of posts where we'll sit down with the folks who help us run our projects without expecting anyting in return. Yes, we're talking about open-source maintainers and builders, the people who dedicate their free time to make tech better. This is our way to say "Thank you!" to all of those who help us build and improve &lt;a href="https://wasp-lang.dev/" rel="noopener noreferrer"&gt;Wasp&lt;/a&gt;, as well as shape the webdev ecosystem.&lt;/p&gt;

&lt;p&gt;In our first post, we had the chance to chat with Tim, the maintainer of &lt;a href="https://github.com/timgit/pg-boss" rel="noopener noreferrer"&gt;pg-boss&lt;/a&gt;, a library that makes managing job queues in PostgreSQL a breeze. We talked about what it’s like to maintain an open-source project, the ups and downs, and why Tim keeps coming back to make pg-boss better. If you’ve ever relied on open-source tools, this series is for you.&lt;/p&gt;

&lt;p&gt;Let's dive in!&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Please tell us a little bit about yourself. When and how did you get introduced to coding?&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I was first introduced to coding in grade school with Logo in the 80s. I built my first website on GeoCities in 97, then started coding professionally with Visual Basic in MS Access during the Y2K craze. I built my first multi-tenant SaaS app (an extranet) in 2002 before it was cool using Classic ASP. I spent at least a decade in C# coding web apps most of the time before finally settling down in the warm embrace of full stack JavaScript with Node.js for the last 10 years.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Could you introduce us to pg-boss? Was there a reason or use case you had for creating it?&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I joined a startup in 2015 and we needed an open source relational database so Mongo would stop ruining our lives. I had heard good things about Postgres, so I was excited to give it a chance. Our product also included Redis, but only for the purpose of hosting a job queue via the Kue package. This seemed excessive to manage another piece of infrastructure for a queue, especially for our low-volume requirements. I hadn’t used Redis before, so I started researching it.&lt;/p&gt;

&lt;p&gt;I learned that Redis is a great choice when you need a fast, in-memory database. However, a job queue is a different use case, where you are guaranteeing to someone: “I promise to do this later”. If your Redis server crashes, you could lose a lot of jobs with the default configuration. Their persistence documentation even states, “if you want a degree of data safety comparable to what PostgreSQL can provide you”, you should use both RDB and AOF configurations. Within AOF, there is an option, “appendfsync always”, but it’s generally discouraged with warnings of poor performance. The recommended configuration is almost always “everysec”, but with the disclaimer, “you may lose 1 second of data if there is a disaster”. These warnings about safety should cause anyone in technical leadership to pause and ask some questions.&lt;/p&gt;

&lt;p&gt;Even now in 2024 Redis seems to be the dominant queue persistence database in OSS, but it wasn’t designed to match the use case of a guaranteed job delivery system. Seeing the growth of open source Postgres-backed queues makes me optimistic that over time more development teams realize this mismatch and we’ll see a decline in popularity of the Redis queue projects. If your product relies on Redis for its queue, I encourage you to review your disaster recovery plans and server configurations. It’s concerning that the popularity of the “just use Redis for your queue” is likely producing a large population of applications vulnerable to losing jobs.&lt;/p&gt;

&lt;p&gt;In 2015, the number 1 hit on Google for “Postgres job queue” was Brandur Leach’s “Postgres Job Queues &amp;amp; Failure By MVCC” blog post. LOL! The Internet replied with “don’t do this”. However, at this same point in time Postgres 9.5 was in beta and about to be released, and lo and behold a new core feature was added called SKIP LOCKED. This looked like a perfect fit, but it was too new for any packages to have this approach. After a successful prototype, I thought it seemed like a good opportunity to try creating the package myself, since I was new to Node and wanted to learn more about it. I started building it on nights and weekends, shipped version 0.0.1 in early 2016 then finally released 1.0 a year later.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;How do you manage contributions and feature requests?&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The best thing about OSS in my opinion is in its name: “open”. Having the entire world of developers not only use your software, but also be able to read its code and make contributions produces the highest quality code. You will get questions you never thought about, and find bugs you didn’t know existed. In the case of bug fixes, most of the time it’s as simple as making sure said bug has a new unit test then merging a pull request (PR).&lt;/p&gt;

&lt;p&gt;Managing feature requests is not easy, however. If you don’t accept any contributions, it seems to violate the principle of OSS. If you accept every contribution, you risk the project drifting away from its original design or becoming too complicated. The balance between these extremes is evaluating each feature request against what seems to be best aligned with the core purpose of the project. This becomes a non-technical decision sometimes, and may result in a “let’s agree to disagree” outcome. My desire is to try and merge all PRs that arrive, and I really appreciate all the contributors that have sent them. It’s not fun saying “no”, because someone put in the coding effort and they felt strongly enough about it to spend their free time on your project.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;What are the unexpected challenges of managing a successful open-source project?&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I did not expect how time-consuming managing an open source project would be. This is probably the primary reason projects become abandoned over time if they are supported by only 1 or a few developers. For example, you could have a perfectly functioning code base in Node 0.12, then decide to upgrade to async/await later and have to rewrite everything. The same applies to changing a test suite, assertion package, or even striving to attain 100% code coverage.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Using Postgres as a queue solution has become quite popular recently :) What are your thoughts on differences between pg-boss and e.g. pgmq?&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is encouraging to see. I learned about pgmq from this question. It looks like a great option for a pure SQL implementation as a Postgres extension. I haven’t used it so I won’t be able to offer a detailed comparison, but after a quick review I see it uses SKIP LOCKED and a partitioned job table, which are good baseline scalability requirements. Postgres extension version management is challenging, however, and usually involves database service restarts and downtime.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;What is the largest scale you’ve seen or heard pg-boss used at? How scalable / how far can you go with running background jobs directly in pg?&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In terms of job storage, we’ve been able to store 2-3 million jobs in v9’s shared job storage and survive, but not really thrive, as database performance starts to degrade. Before v10, in order to mitigate this you have to use configuration settings to move completed jobs into the archive more often.&lt;/p&gt;

&lt;p&gt;Once record counts are under control, in terms of job throughput, the number of concurrent queries to Postgres can be very high, especially when using connection poolers and job batching. I have a speed test in the suite that can both fetch and then complete 10,000 jobs in 0.5 seconds, a metric you would not easily be able to achieve even in some dedicated queuing products. For job creation on the other hand, you have the full power of SQL available in Postgres via INSERT or even COPY.&lt;/p&gt;




&lt;h3&gt;
  
  
  Did you know that Wasp uses pg-boss under the hood? We built Wasp Jobs on top of pg-boss, and &lt;a href="https://wasp-lang.dev/blog/2022/06/15/jobs-feature-announcement" rel="noopener noreferrer"&gt;here's how we did it&lt;/a&gt;.
&lt;/h3&gt;




&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;While pg-boss has many production use cases, is there a scenario or limit where teams may need a traditional queue instead?&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Because of the limitations in v9, we use pg-boss and AWS SQS side by side. Some of our queues rely heavily on pg-boss’s rate limiting and uniqueness features. We use SQS for queues that can grow very large quickly. Now that we’ve upgraded to v10, we might consider switching back for cost reasons, since SQS is not cheap at this scale.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;There is a new version of &lt;a href="https://github.com/timgit/pg-boss/releases/tag/10.0.0" rel="noopener noreferrer"&gt;pg-boss v10&lt;/a&gt;, what should people be excited about?&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;pg-boss v9 and below uses a shared job table across all queues. Once you run into the storage limitations mentioned earlier, all queues are affected. This is especially problematic since queues were also used internally for maintenance and scheduling. Maintenance controls archival, so if this queue can’t be processed, it prevents pg-boss from auto-recovering from this via the retention policy.&lt;/p&gt;

&lt;p&gt;The design goal in v10 was to mitigate this performance issue first by isolating each queue into a dedicated table via partitioning. If a queue were to become backlogged with millions of jobs, it would affect the performance of that queue only. Then, if needed, you could use the newly added deleteJob() function in your workers, inspired by AWS SQS, to keep the record count as low as possible.&lt;/p&gt;

&lt;p&gt;Another very useful new feature is queue policies. Over the years there were several issues opened around worker concurrency, which added several functions and configuration which made the API more complicated and difficult to understand. For example, there was a function sendSingleton(), which behaved entirely different from a configuration option named enforceSingletonQueueActiveLimit. In v10, these were all removed in favor of queue policies. A couple of examples are “short” queues, which only allow 1 pending job, no matter how many jobs are submitted, and “singleton” queues, which allow only 1 job to be active.&lt;/p&gt;

&lt;p&gt;There are several other enhancements made to improve quality of life in v10:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;All jobs have 2 retries enabled by default&lt;/li&gt;
&lt;li&gt;FIPS compliant (dropped internal usage of MD5 hashing)&lt;/li&gt;
&lt;li&gt;Replication support for HA or read-replicas (every table now has a primary key)&lt;/li&gt;
&lt;li&gt;Serverless function supervision (maintain() function that can be run from another scheduler)&lt;/li&gt;
&lt;li&gt;Postgres dependency-free (no pgcrypto extension needed uuid generation)&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Dead letter queues (Replaces “completion job” feature and gains retry support for processing them)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;What are your thoughts on things like pg_render &lt;a href="https://www.madewithsupabase.com/p/pg-render" rel="noopener noreferrer"&gt;which is a way to render HTML in Postgres&lt;/a&gt;? &lt;a href="https://www.madewithsupabase.com/p/pg-render" rel="noopener noreferrer"&gt;&lt;/a&gt;Is that going too far?&lt;/strong&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Since I’m a Postgres fan, it’s hard for me to see how adding more capabilities to it would be considered “going too far”. This particular project appears to be a simple abstraction of other open source packages and could be a useful case study of creating a Postgres extension in Rust. Since this is compiled, it should even have better performance benchmarks over other packages with the same feature in non-compiled languages.&lt;/p&gt;

&lt;p&gt;Overall, I agree with the argument for simplicity in Stephan Schmidt’s article “Just Use Postgres for Everything”. The only issue with his article, which he continues to edit after all these years, is Stephan recommends River, a new OSS queue using SKIP LOCKED in Go, when we could have just mentioned little ole pg-boss that’s been around for years. The irony is that River was built by Brandur “don’t use Postgres queues” Leach. I’m kidding around here, of course, but who doesn’t enjoy a bit of irony?&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;What advice would you give to developers or companies who are thinking of open sourcing their projects?&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For developers, I would encourage starting off by making a contribution to a package you use daily. For example, if you’ve ever thought “I like this package, but I think it could be better if it had this feature”, that might be something you could add. If you have an idea of a new project, my advice would be to focus on the MVP (minimally viable product). The more features you add, the more time required to release it and the more maintenance required to keep it running. This is the primary reason I don’t include a web API or UI with pg-boss, even though I’m sure it would make it more popular.&lt;/p&gt;

&lt;p&gt;For companies, I would point to successful startups that became popular and attracted funding because of their OSS projects. TimescaleDB, Supabase, and Citus are examples just from the Postgres ecosystem.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;What is the main reason you keep working on pg-boss? What do you get out of it?&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It’s nice to be able to change what type of development you do occasionally. It gives you a different perspective and usually gives you new insights into your primary job. When you have responsibility over a popular package, it also adds some motivation to make sure it remains healthy. It’s not a good feeling when your package causes bad performance on a database server because of its own success (a large queue backlog could mean your company is growing). I did sign up for GitHub Sponsors a couple years ago, and I appreciate every company and developer that has benefited from pg-boss making contributions, but it’s still far from being able to fund itself.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Have you ever thought of introducing a paid product on top of pg-boss? Why yes/no?&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I haven’t spent time evaluating what that would look like, but it is an intriguing idea for sure. If I was able to work on pg-boss full-time, there are several potential new concepts that could be explored now that partitioning and queue policies have been created.&lt;/p&gt;

&lt;p&gt;For example, someone recently opened an issue to request arbitrary JSON querying capability to be included in fetch(). If done globally across all queues, this would require indexing the jsonb payload, which in some cases could be large, slowing down reads and writes. However, if applied only to a single partition, this index could be isolated to only the queue that needs it via a new policy. Postgres allows different indexes and unique constraints between tables within the same partitioning hierarchy, which could be used for this policy.&lt;/p&gt;

&lt;p&gt;Furthermore, very large partitions could even have subpartitions, creating a tree-like structure for scalability purposes. This strategy has already been proven at scale in Postgres by the TimescaleDB team, and could potentially result in removing its storage capacity challenges entirely.&lt;/p&gt;

&lt;p&gt;Yet another area of exploration is encapsulating all features into Postgres functions to make the logic of pg-boss more easily integrated with non-Node.js platforms, as most of the logic in pg-boss is actually already pure SQL. Some have also mentioned to me that it would be nice if we had a standard queue data schema that could be shared across platforms, which sounds like a noble goal, but challenging since it would involve collaboration across OSS projects to complete.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Apart from yours, is there an open source tool or project you’re particularly excited about?&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I’m a big fan of &lt;a href="https://supabase.com/" rel="noopener noreferrer"&gt;Supabase&lt;/a&gt; at the moment. I’m currently evaluating their use of JWT claims and Postgres RLS for SaaS multi-tenancy. They have open sourced several of their projects as well, such as supavisor, a connection pooler. Their product also happens to use pg-boss internally, which means… “they use pg-boss btw” 🙂&lt;/p&gt;

&lt;p&gt;Hope you enjoyed this interview, and stay tuned for the next one!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.github.com/wasp-lang/wasp" class="ltag_cta ltag_cta--branded" rel="noopener noreferrer"&gt;⭐️ Star Wasp on GitHub 🙏&lt;/a&gt;
&lt;/p&gt;

&lt;p&gt;It's the easiest way to support open-source initiatives like ours.&lt;/p&gt;

</description>
      <category>postgres</category>
      <category>opensource</category>
      <category>webdev</category>
      <category>news</category>
    </item>
    <item>
      <title>The Easiest Way to Monitor Ruby: Automatic Instrumentation</title>
      <dc:creator>Milica Maksimovic</dc:creator>
      <pubDate>Thu, 17 Jun 2021 13:56:54 +0000</pubDate>
      <link>https://dev.to/appsignal/the-easiest-way-to-monitor-ruby-automatic-instrumentation-44af</link>
      <guid>https://dev.to/appsignal/the-easiest-way-to-monitor-ruby-automatic-instrumentation-44af</guid>
      <description>&lt;p&gt;Setting up a proper monitoring overview over your application's performance is a complex task. Normally, you'd first need to figure out what you need to monitor, then instrument your code, and finally make sense of all the data that has been emitted.&lt;/p&gt;

&lt;p&gt;However, with a few things set in place, and an APM that natively supports Ruby, it's easier than ever to take this step. In this post, we'll show you how you can do it too.&lt;/p&gt;

&lt;h2&gt;
  
  
  Automatic Instrumentation - Handsfree APM Setup
&lt;/h2&gt;

&lt;p&gt;To discover which pieces of your code are causing your performance issues, you’ll need to add instrumentation to it. That way, you can break down all the actions and measure which ones are the slowest.&lt;/p&gt;

&lt;p&gt;With AppSignal’s automatic instrumentation, we take away as much manual work as we can. Just run &lt;a href="https://docs.appsignal.com/ruby/command-line/install.html" rel="noopener noreferrer"&gt;a few commands through the CLI&lt;/a&gt;, and you’ll be set.&lt;/p&gt;

&lt;p&gt;Our monitoring agent detects the different parts of your infrastructure and automatically instruments it. This enables AppSignal app to digest, process, monitor, and show you the graphs and dashboards you need the most.&lt;/p&gt;

&lt;p&gt;That means that for example for the &lt;a href="https://graphql-ruby.org/" rel="noopener noreferrer"&gt;graphql gem for Ruby&lt;/a&gt;, AppSignal will  instrument every GraphQL request that comes in, meaning it will provide a breakdown of all events in the request.&lt;/p&gt;

&lt;h2&gt;
  
  
  Out-of-the-box Instrumentation
&lt;/h2&gt;

&lt;p&gt;We've made a list of all the tools AppSignal supports. It's pretty extensive:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Type&lt;/th&gt;
&lt;th&gt;Tool&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Framework&lt;/td&gt;
&lt;td&gt;&lt;a href="https://docs.appsignal.com/ruby/integrations/rails.html" rel="noopener noreferrer"&gt;Rails&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Rails features&lt;/td&gt;
&lt;td&gt;Action Mailer&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Rails features&lt;/td&gt;
&lt;td&gt;Action Cable&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Rails features&lt;/td&gt;
&lt;td&gt;Active Record&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Rails features&lt;/td&gt;
&lt;td&gt;Active Job&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Rails features&lt;/td&gt;
&lt;td&gt;Caching&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Supported through ActiveRecord&lt;/td&gt;
&lt;td&gt;PostgreSQL, MySQL, SQLite, etc.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Heroku integration&lt;/td&gt;
&lt;td&gt;&lt;a href="https://docs.appsignal.com/metrics/host-metrics/heroku.html" rel="noopener noreferrer"&gt;Heroku PostgreSQL&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Framework&lt;/td&gt;
&lt;td&gt;&lt;a href="https://docs.appsignal.com/ruby/integrations/padrino.html" rel="noopener noreferrer"&gt;Padrino&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Framework&lt;/td&gt;
&lt;td&gt;&lt;a href="https://docs.appsignal.com/ruby/integrations/sinatra.html" rel="noopener noreferrer"&gt;Sinatra&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Gem&lt;/td&gt;
&lt;td&gt;Rack&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Gem&lt;/td&gt;
&lt;td&gt;WebMachine&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Web server&lt;/td&gt;
&lt;td&gt;Puma&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Web server&lt;/td&gt;
&lt;td&gt;Unicorn&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ORM&lt;/td&gt;
&lt;td&gt;DataMapper&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ORM&lt;/td&gt;
&lt;td&gt;Sequel&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ORM&lt;/td&gt;
&lt;td&gt;MongoDB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;API&lt;/td&gt;
&lt;td&gt;Grape&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;API&lt;/td&gt;
&lt;td&gt;GraphQL&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Standard library&lt;/td&gt;
&lt;td&gt;Net::HTTP&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Background job&lt;/td&gt;
&lt;td&gt;Que&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Background job&lt;/td&gt;
&lt;td&gt;Sidekiq&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Background job&lt;/td&gt;
&lt;td&gt;Delayed Job&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Background job&lt;/td&gt;
&lt;td&gt;Resque&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Background job&lt;/td&gt;
&lt;td&gt;Shoryuken&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Gem&lt;/td&gt;
&lt;td&gt;Rake&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;As I've said, the list is pretty long, which is why we won't dive into each and every tool in this post.&lt;/p&gt;

&lt;h2&gt;
  
  
  Web Frameworks and APIs
&lt;/h2&gt;

&lt;p&gt;AppSignal supports instrumentation of web requests in Ruby on Rails, Padrino, and Sinatra out-of-the-box. APIs using Grape or the GraphQL gem are also supported.&lt;/p&gt;

&lt;h3&gt;
  
  
  Ruby on Rails
&lt;/h3&gt;

&lt;p&gt;The AppSignal integration for Rails works by tracking exceptions and performance in requests. When an error occurs in a controller during a request AppSignal will report it. Performance issues will be based on the duration of a request and create a timeline of events detailing which parts of the application took the longest.&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%2Fik5an69bvb2558pja105.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%2Fik5an69bvb2558pja105.png" alt="dashboard" width="800" height="308"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It's even possible to track how long it took for HTTP requests to arrive at the Rails app through a loadbalancer of web server. If it's not on by default, set up the &lt;a href="https://docs.appsignal.com/ruby/instrumentation/request-queue-time.html" rel="noopener noreferrer"&gt;request queue time&lt;/a&gt; tracking header and AppSignal will automatically graph the queue 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%2Fyr7mc4z30cp7o6ux5ctm.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%2Fyr7mc4z30cp7o6ux5ctm.png" alt="queue time" width="800" height="457"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  GraphQL
&lt;/h3&gt;

&lt;p&gt;AppSignal supports the &lt;a href="https://graphql-ruby.org/" rel="noopener noreferrer"&gt;graphql gem for Ruby&lt;/a&gt;. It will instrument every GraphQL request that comes in and provide a breakdown of all events in the request. You'll be able to see how long it took to parse, validate and execute your resolvers. Events from the app's web framework and database calls are of course included in this breakdown.&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%2F5mzp0xgsxkcetxe6b2w5.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%2F5mzp0xgsxkcetxe6b2w5.png" alt="Screenshot of event timeline" width="800" height="380"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This is great for those who wish to debug GraphQL queries that seem to take a long time, and you're not sure where the slowdown could be occurring. Don't forget about &lt;a href="https://docs.appsignal.com/application/anomaly-detection/#setting-up-triggers" rel="noopener noreferrer"&gt;our anomaly triggers&lt;/a&gt; here also - these can be very useful for alerting when the query time reaches a certain threshold.&lt;/p&gt;

&lt;h3&gt;
  
  
  Sinatra, Padrino and Grape
&lt;/h3&gt;

&lt;p&gt;Sinatra, Padrino and Grape are web and API frameworks for Ruby that can be part of an app in different ways. They are either a standalone app or mounted on a larger Rails app. Depending on how the app is mounted on a web server some different installation steps are needed for &lt;a href="https://docs.appsignal.com/ruby/integrations/sinatra.html" rel="noopener noreferrer"&gt;Sinatra&lt;/a&gt;, &lt;a href="https://docs.appsignal.com/ruby/integrations/padrino.html" rel="noopener noreferrer"&gt;Padrino&lt;/a&gt; and &lt;a href="https://docs.appsignal.com/ruby/integrations/grape.html" rel="noopener noreferrer"&gt;Grape&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Once installed Sinatra, Padrino, Grape requests are all instrumented: errors and performance measurements are reported when traffic hits the API. Every (API) endpoint is its own action in AppSignal to easily find which endpoint encountered which error. As with Rails apps the performance breakdown provides insight in what database queries or other parts or the app were slower than others.&lt;/p&gt;

&lt;h2&gt;
  
  
  Databases
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Active Record and other ORMs
&lt;/h3&gt;

&lt;p&gt;To see how long a request took querying the database, open a incident detail page. On top of the page the types of events recorded in the request are broken down per group. Here you can see how much time in total was spend on what type of operation.&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%2F8pvswp7zaevrcqqwm6th.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%2F8pvswp7zaevrcqqwm6th.png" alt="IncidentPageWithPostGreSQL" width="800" height="394"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If we zoom in further on the performance of this sample, further down the page you'll find a timeline of all events in the request in the order they occurred. This provides you with an overview of each query that was executed and which ones are taking the longest.&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%2F925b0xcrsgpy0mnf9lex.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%2F925b0xcrsgpy0mnf9lex.png" alt="IncidentPageTimelineWithPostGreSQL" width="800" height="379"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The integration shows you the tracing for database calls, so you can see what query is the root of your evil (or genius) 😉&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%2Flrs7su9c3gmnvoem3g63.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%2Flrs7su9c3gmnvoem3g63.png" alt="IncidentPageTracingWithPostGreSQL" width="800" height="379"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  N+1 queries
&lt;/h3&gt;

&lt;p&gt;Worried there may be N+1 queries occurring in the request and that's what is slowing it down? If we detect N+1 queries a warning will appear in the event timeline for those events that were detected.&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%2Fwv7n16srps8epnzg5rlq.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%2Fwv7n16srps8epnzg5rlq.png" alt="IncidentPageWithPostGreSQL" width="800" height="220"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Redis
&lt;/h3&gt;

&lt;p&gt;With Redis integration, you'll see your calls to Redis appear in the Event Timeline:&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%2Fw15bndipv8h8r74pu8eo.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%2Fw15bndipv8h8r74pu8eo.png" alt="Screenshot of event timeline" width="800" height="380"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You'll also be able to see the name of the command sent to Redis and the address of the Redis instance that the query was made to:&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%2F3mx52k5r66h9sbqatbbh.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%2F3mx52k5r66h9sbqatbbh.png" alt="Screenshot of event timeline flyout" width="800" height="380"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This is great news for those who wish to debug long running calls to a Redis cache. You can even set an anomaly trigger to send an alert on requests that run for a super long time!&lt;/p&gt;

&lt;h2&gt;
  
  
  Background Jobs
&lt;/h2&gt;

&lt;p&gt;Whenever a background job is queued with Sidekiq, Delayed::Job, Resque, Shoryuken and Que AppSignal will automatically report errors and performance measurements. All &lt;a href="https://docs.appsignal.com/ruby/integrations/active-job.html" rel="noopener noreferrer"&gt;Active Job&lt;/a&gt; adapters are also supported, and some background job libraries like Sidekiq and Delayed::Job report even more metadata from the libraries themselves.&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%2F0pqabem3s8er950d71kz.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%2F0pqabem3s8er950d71kz.png" alt="IncidentPageWithPostGreSQL" width="800" height="344"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Sending emails with Action Mailer
&lt;/h3&gt;

&lt;p&gt;If Rails mailers using Action Mailer are set up to &lt;code&gt;deliver_later&lt;/code&gt; they will also be routed through Active Job and can count on the same level of instrumentation.&lt;/p&gt;

&lt;h2&gt;
  
  
  Websockets
&lt;/h2&gt;

&lt;p&gt;Using Action Cable in your Rails app? AppSignal automatically reports errors and performance measurements for messages and subscriptions. Every message is instrumented separately so even long running channels will report all activity. They are grouped per action giving a clear overview of how each individual action is performing.&lt;/p&gt;

&lt;h2&gt;
  
  
  Try AppSignal: Monitoring Made Easy And Sweet 🍪
&lt;/h2&gt;

&lt;p&gt;Over the past 7 years, we've helped thousands of developers to automatically instrument their code, and we'd love you to &lt;a href="https://www.appsignal.com/ruby" rel="noopener noreferrer"&gt;try us out as well&lt;/a&gt;. When you do, feel free to reach out, we'll send you a free box of &lt;a href="https://www.appsignal.com/waffles" rel="noopener noreferrer"&gt;stroopwafels&lt;/a&gt; as well.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;PS. If you are helping the world with a great OSS project, &lt;a href="https://blog.appsignal.com/2020/10/20/appsignal-is-free-for-open-source-software-and-for-good-projects.html" rel="noopener noreferrer"&gt;we help you back&lt;/a&gt; with a free AppSignal account. Spread the word to the maintainers you value!&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ruby</category>
      <category>rails</category>
      <category>devops</category>
      <category>monitoring</category>
    </item>
    <item>
      <title>Difficult Things About Difficult Discussions at Work</title>
      <dc:creator>Milica Maksimovic</dc:creator>
      <pubDate>Wed, 28 Apr 2021 14:51:07 +0000</pubDate>
      <link>https://dev.to/m_maksimovic_/difficult-things-about-difficult-discussions-at-work-28j8</link>
      <guid>https://dev.to/m_maksimovic_/difficult-things-about-difficult-discussions-at-work-28j8</guid>
      <description>&lt;p&gt;I'm writing this post for those who struggle with discussing social/political or any other sensitive topics within their workspaces. Placing a ban on discussions is not the right approach. Instead, let's teach people on how to have deep, meaningful, and respectful discussions.&lt;/p&gt;

&lt;p&gt;I'm obviously inspired by the &lt;a href="https://www.theverge.com/2021/4/27/22406673/basecamp-political-speech-policy-controversy" rel="noopener noreferrer"&gt;whole Basecamp thing&lt;/a&gt;. The one thing we’re not seeing is the tone of the internal communication about difficult things. We just see how they decided to handle it. &lt;/p&gt;

&lt;p&gt;Just to be clear, I'm all up for diversity and against most of the steps Jason and David decided to take. &lt;/p&gt;

&lt;h2&gt;
  
  
  You need to be open for discussion
&lt;/h2&gt;

&lt;p&gt;Drawing from my past experiences, there have been times when I was taking part in sensitive discussions. The most difficult thing when discussing things you’re sensitive about or feel strongly about is not to dismiss the other side. Having a meaningful discussion is very different from having a heated argument.&lt;/p&gt;

&lt;p&gt;Polarisation, and looking at things as being either black or white isn’t helpful. It’s really easy to call out people for their behavior, and if the tone is accusative or aggressive, they start playing defense…. and then there’s no conversation.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to approach people
&lt;/h2&gt;

&lt;p&gt;I honestly believe that once you approach people in a calm manner, without being accusative, and try to understand why they do some things the way they do, and get them to see another perspective is the way to grow. For both parties. But both parties have to be open to challenging their own views.&lt;/p&gt;

&lt;p&gt;It’s easy to approach someone and say “That’s wrong”. Instead, “Hey, can you help me understand why you [think this, did that, you name it]?”&lt;/p&gt;

&lt;h2&gt;
  
  
  Postponing the discussion is also ok
&lt;/h2&gt;

&lt;p&gt;There are days when the topic we care deeply about makes us too emotional and we instinctively “defend” our position. It’s crucial to recognize those moments and retreat, because hot-headed people can’t have a meaningful discussion. It also takes away a lot of energy.&lt;/p&gt;

&lt;p&gt;In some instances, the other party may be too emotional as well. It's important to take that into consideration, and voice that you have nothing against them, and that you're just interested in learning about their perspective and understanding them better. If that doesn't help, postpone the conversation or just back away. &lt;/p&gt;

&lt;h2&gt;
  
  
  Opinions can change
&lt;/h2&gt;

&lt;p&gt;To end it with some personal examples:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;It took me years to figure out that the person I had so many heated arguments about LGBT rights and to whom I stopped talking to was struggling to come out. A couple of years ago that one approached me and actually apologized and thanked me for talking openly about some stuff on my FB account.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;It also took me years to fully accept myself. This is why I also get why there are others who struggle to understand me or understand the struggles I face in my daily life.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Understand that people can grow and change their opinions, and that some people just view the world differently. It's all ok as long as we're all being respectful and not harming others in any way. &lt;/p&gt;

&lt;p&gt;Things are &lt;del&gt;never&lt;/del&gt; rarely black and white.&lt;/p&gt;

</description>
      <category>diversity</category>
      <category>inclusion</category>
      <category>lgbtq</category>
    </item>
  </channel>
</rss>
